summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ExternalAPI/m_help.h93
-rw-r--r--Help/Info_Src.txt39
-rw-r--r--Help/License_Appendix.txt64
-rw-r--r--Help/datastore.c577
-rw-r--r--Help/dlgboxsubclass.c455
-rw-r--r--Help/docs/Help-Developer.txt93
-rw-r--r--Help/docs/Help-License.txt278
-rw-r--r--Help/docs/Help-Readme.txt196
-rw-r--r--Help/docs/Help-Translation.txt217
-rw-r--r--Help/docs/helppack_english.txt193
-rw-r--r--Help/docs/helppack_sample.txt256
-rw-r--r--Help/help.def11
-rw-r--r--Help/help.dep120
-rw-r--r--Help/help.dsp335
-rw-r--r--Help/help.dsw29
-rw-r--r--Help/help.h142
-rw-r--r--Help/help.mak581
-rw-r--r--Help/help.vcproj498
-rw-r--r--Help/help_8.vcproj1038
-rw-r--r--Help/helpdlg.c700
-rw-r--r--Help/helppack.c466
-rw-r--r--Help/main.c203
-rw-r--r--Help/options.c804
-rw-r--r--Help/resource.h61
-rw-r--r--Help/resource.rc300
-rw-r--r--Help/streaminout.c713
-rw-r--r--Help/unzip.c3305
-rw-r--r--Help/unzip.h122
-rw-r--r--Help/update.c1082
-rw-r--r--Help/utils.c399
-rw-r--r--Help/version.h40
-rw-r--r--Help/version.rc51
32 files changed, 13461 insertions, 0 deletions
diff --git a/ExternalAPI/m_help.h b/ExternalAPI/m_help.h
new file mode 100644
index 0000000..04425a5
--- /dev/null
+++ b/ExternalAPI/m_help.h
@@ -0,0 +1,93 @@
+/*
+
+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.
+*/
+
+#ifndef M_HELP_H__
+#define M_HELP_H__
+
+#if defined (_MSC_VER) && (_MSC_VER >= 1020)
+ #pragma once
+#endif
+
+/*
+ Help Plugin 0.2.1.2
+ All services in here except MS_HELP_SHOWLANGDIALOG should be thread-safe,
+ you can call them from any thread
+*/
+
+/* interface id */
+#if !defined(MIID_HELP)
+ #define MIID_HELP {0x302660c5,0x1bf6,0x4054,{0xa7,0x9f,0x77,0xb1,0x96,0x5d,0x6f,0x48}}
+#endif
+
+/* Enable/disable the help context menu for a specific control. v0.2.0.0+
+Note: You normally do not need to call this, read below.
+You can can use this to deactivate the appearance of the help context menu
+being shown when the user right clicks on an control.
+You can use this service to disable the context menu.
+
+You do *not* need to use this service when you would like to show
+a context menu by yourself, just handle WM_CONTEXTMENU correctly instead.
+You need to return TRUE in your DlgProc or 0 in your WndProc, indicating 'message handled'.
+
+The context menu is disabled by default on the following controls (looks silly on multi-component controls):
+ListView, TreeView, Statusbar, Toolbar, CLC
+AutoTips are disabled by default for controls stating DLGC_WANTALLKEYS or DLGC_HASSETSEL at
+WM_GETDLGCODE (autotips are annoying on edits).
+ wParam=(WPARAM)(HWND)hwndCtl
+ lParam=(LPARAM)flags (see below)
+Returns 0 on success or nonzero on failure
+*/
+#define MS_HELP_SETCONTEXTSTATE "Help/SetContextState"
+#define HCSF_CONTEXTMENU 0x01 // show help context menu for this control
+#define HCSF_AUTOTIP 0x02 // show automatic help tip on hover for this control
+ // only works for non-editable
+#if !defined(HELP_NOHELPERFUNCTIONS)
+__inline static int Help_SetContextState(HWND hwndCtl,DWORD flags) {
+ if(!ServiceExists(MS_HELP_SETCONTEXTSTATE)) return -1;
+ return CallService(MS_HELP_SETCONTEXTSTATE,(WPARAM)hwndCtl,flags);
+}
+#endif
+
+/* Show a help tooltip for a specific control or dialog. v0.2.0.0+
+You can call this if you would like to show help at a specific time.
+ wParam=(WPARAM)(HWND)hwndCtl
+ lParam=0 (unused)
+Returns 0 on success or nonzero on failure.
+The service fails when the help tooltip cannot be instantiated.
+*/
+#define MS_HELP_SHOWHELP "Help/ShowHelp"
+
+/* Show the download language dialog. v0.2.1.0+
+ wParam=lParam=0
+The dialog can't have a parent due to it's asynchronous nature.
+If the language window is already opened it will be
+brought to front instead (returns success).
+Returns 0 on success, nonzero otherwise.
+*/
+#define MS_HELP_SHOWLANGDIALOG "Help/ShowLangDialog"
+
+
+#ifndef HELP_NOSETTINGS
+#define SETTING_AUTOTIPSENABLED_DEFAULT 0
+#define SETTING_AUTOTIPDELAY_DEFAULT 4000
+#define SETTING_ENABLEHELPUPDATES_DEFAULT 1
+#endif
+
+#endif // M_HELP_H__
diff --git a/Help/Info_Src.txt b/Help/Info_Src.txt
new file mode 100644
index 0000000..6e46e8e
--- /dev/null
+++ b/Help/Info_Src.txt
@@ -0,0 +1,39 @@
+
+Help Plugin 0.2.1.2 for Miranda IM 0.6+
+------------------------------------------------------------------------
+ Source Code
+
+Reminder:
+The Help Plugin is released under the terms of the
+GNU General Public License.
+See 'Help-License.txt' for more details.
+Help Plugin is copyright 2002 Richard Hughes, 2005-2007 H. Herkenrath.
+
+Please notify me of any changes that improve
+the help Plugin or add new features.
+If you have any questions on the code, feel free
+to contact me at my email address.
+
+ H. Herkenrath (hrathh at users.sourceforge.net)
+
+
+Notes
+------------------------------------------------------------------------
+The project files for VS 7 and 8 (*.vcproj and *.vspscc) are not
+kept up-to-date.
+The working project files are the ones of VS 6 (*.dsw and *.dsp).
+
+When modifying resource with VC 6 the resource editor replaces
+RICHEDIT_CLASS in the resources automatically by 'RichEdit20A'.
+When compiling for final release make sure to correct this
+again to RICHEDIT_CLASS to maintain unicode support correctly.
+
+The following files need to be changed to bump the version number:
+
+Info_Src.txt (1 place)
+version.h (6 places)
+m_help.h (1 place)
+m_help.inc (1 place)
+Docs\Help-Readme.txt (3 places)
+Docs\Help-Translation.txt (2 places)
+Docs\Help-Developer.txt (1 place)
diff --git a/Help/License_Appendix.txt b/Help/License_Appendix.txt
new file mode 100644
index 0000000..c590c3f
--- /dev/null
+++ b/Help/License_Appendix.txt
@@ -0,0 +1,64 @@
+
+Excecpt of GNU General Public License (Appendix):
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/Help/datastore.c b/Help/datastore.c
new file mode 100644
index 0000000..9acabff
--- /dev/null
+++ b/Help/datastore.c
@@ -0,0 +1,577 @@
+/*
+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 <tchar.h>
+#include <stdio.h>
+#define __RPCASYNC_H__ /* header shows warnings in VS6 */
+#include <windows.h>
+#include <win2k.h>
+#define MIRANDA_VER 0x0600
+#include <newpluginapi.h>
+#include <m_system.h>
+#include <m_database.h>
+#include <m_utils.h>
+#include <m_langpack.h>
+#include "help.h"
+
+extern HWND hwndHelpDlg;
+
+struct DlgControlData {
+ int id;
+ int type;
+ TCHAR *szTitle;
+ char *szText; // ANSI or UTF-8 depending on _UNICODE defined (for RichEdit)
+};
+
+struct DialogData {
+ char *szId;
+ char *szModule;
+ struct DlgControlData *control;
+ int controlCount;
+ DWORD timeLoaded,timeLastUsed;
+ int changes;
+ LCID locale;
+ UINT defaultCodePage;
+ int isLocaleRTL;
+};
+
+static struct DialogData *dialogCache=NULL;
+static int dialogCacheCount=0;
+static CRITICAL_SECTION csDialogCache;
+static HANDLE hServiceFileChange,hFileChange;
+
+#define DIALOGCACHEEXPIRY 10*60*1000 // delete from cache after those milliseconds
+
+static int ServiceFileChanged(WPARAM wParam,LPARAM lParam)
+{
+ int i;
+ UNREFERENCED_PARAMETER(lParam);
+
+ EnterCriticalSection(&csDialogCache);
+ for(i=0;i<dialogCacheCount;i++)
+ dialogCache[i].timeLastUsed=0;
+ LeaveCriticalSection(&csDialogCache);
+
+ if((HANDLE)wParam!=NULL) FindNextChangeNotification((HANDLE)wParam);
+ return 0;
+}
+
+void InitDialogCache(void)
+{
+ TCHAR szFilePath[MAX_PATH],*p;
+
+ InitializeCriticalSection(&csDialogCache);
+
+ hServiceFileChange=CreateServiceFunction("Help/HelpPackChanged",ServiceFileChanged);
+ hFileChange=INVALID_HANDLE_VALUE;
+ if(GetModuleFileName(NULL,szFilePath,SIZEOF(szFilePath))) {
+ p=_tcsrchr(szFilePath,_T('\\'));
+ if(p!=NULL) *(p+1)=_T('\0');
+ hFileChange=FindFirstChangeNotification(szFilePath,FALSE,FILE_NOTIFY_CHANGE_LAST_WRITE);
+ if(hFileChange!=INVALID_HANDLE_VALUE)
+ CallService(MS_SYSTEM_WAITONHANDLE,(WPARAM)hFileChange,(LPARAM)"Help/HelpPackChanged");
+ }
+}
+
+static void FreeDialogCacheEntry(struct DialogData *entry)
+{
+ int i;
+ for(i=0;i<entry->controlCount;i++) {
+ mir_free(entry->control[i].szText); // does NULL check
+ mir_free(entry->control[i].szTitle); // does NULL check
+ }
+ mir_free(entry->control); // does NULL check
+ mir_free(entry->szId); // does NULL check
+ mir_free(entry->szModule); // does NULL check
+}
+
+void FreeDialogCache(void)
+{
+ int i;
+
+ if(hFileChange!=INVALID_HANDLE_VALUE) {
+ CallService(MS_SYSTEM_REMOVEWAIT,(WPARAM)hFileChange,0);
+ FindCloseChangeNotification(hFileChange);
+ }
+ DestroyServiceFunction(hServiceFileChange);
+
+ DeleteCriticalSection(&csDialogCache);
+ for(i=0;i<dialogCacheCount;i++)
+ FreeDialogCacheEntry(&dialogCache[i]);
+ dialogCacheCount=0;
+ mir_free(dialogCache); // does NULL check
+ dialogCache=NULL;
+}
+
+/**************************** LOAD HELP ***************************/
+
+struct LoaderThreadStartParams {
+ HWND hwndCtl;
+ char *szDlgId;
+ char *szModule;
+ int ctrlId;
+};
+
+static void LoaderThread(struct LoaderThreadStartParams *dtsp)
+{
+ FILE *fp;
+ char line[4096];
+ char *pszLine, *pszColon, *pszBuf;
+ int startOfLine=0;
+
+ WIN32_FIND_DATA wfd;
+ HANDLE hFind;
+ TCHAR szDir[MAX_PATH];
+ TCHAR szSearch[MAX_PATH];
+ TCHAR *p;
+ int success=0;
+
+ struct DialogData dialog;
+ struct DlgControlData *control;
+ void *buf;
+ ZeroMemory(&dialog,sizeof(dialog));
+
+ if(GetModuleFileName(NULL,szDir,SIZEOF(szDir))) {
+ p=_tcsrchr(szDir,_T('\\'));
+ if(p) *p=_T('\0');
+ mir_sntprintf(szSearch,SIZEOF(szSearch),_T("%s\\helppack_*.txt"),szDir);
+
+ hFind=FindFirstFile(szSearch,&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;
+ mir_sntprintf(szSearch,SIZEOF(szSearch),_T("%s\\%s"),szDir,wfd.cFileName);
+ success=1;
+ break;
+ } while(FindNextFile(hFind,&wfd));
+ FindClose(hFind);
+ }
+ }
+ if(!success) {
+ if(!Miranda_Terminated() && IsWindow(hwndHelpDlg))
+ PostMessage(hwndHelpDlg,M_HELPLOADFAILED,0,(LPARAM)dtsp->hwndCtl);
+ return;
+ }
+
+ fp=_tfopen(szSearch,_T("rt"));
+ if(fp==NULL) {
+ if(!Miranda_Terminated() && IsWindow(hwndHelpDlg))
+ PostMessage(hwndHelpDlg,M_HELPLOADFAILED,0,(LPARAM)dtsp->hwndCtl);
+ return;
+ }
+ fgets(line,SIZEOF(line),fp);
+ TrimString(line);
+ if(lstrcmpA(line,"Miranda Help Pack Version 1")) {
+ fclose(fp);
+ if(!Miranda_Terminated() && IsWindow(hwndHelpDlg))
+ PostMessage(hwndHelpDlg,M_HELPLOADFAILED,0,(LPARAM)dtsp->hwndCtl);
+ return;
+ }
+
+ // headers
+ dialog.locale=LOCALE_USER_DEFAULT;
+ dialog.defaultCodePage=CP_ACP;
+ while(!feof(fp)) {
+ startOfLine=ftell(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) {
+ fclose(fp);
+ if(!Miranda_Terminated() && IsWindow(hwndHelpDlg))
+ PostMessage(hwndHelpDlg,M_HELPLOADFAILED,0,(LPARAM)dtsp->hwndCtl);
+ return;
+ }
+ *pszColon='\0';
+
+ // locale
+ if(!lstrcmpA(line,"Locale")) {
+ char szCP[6];
+ TrimString(pszColon+1);
+ dialog.locale=MAKELCID((USHORT)strtol(pszColon+1,NULL,16),SORT_DEFAULT);
+ // codepage
+ if(GetLocaleInfoA(dialog.locale,LOCALE_IDEFAULTANSICODEPAGE,szCP,sizeof(szCP))) {
+ szCP[5]='\0'; // codepages have 5 digits at max
+ dialog.defaultCodePage=atoi(szCP);
+ }
+ }
+ }
+
+ // RTL flag
+ // see also: http://blogs.msdn.com/michkap/archive/2006/03/03/542963.aspx
+ { LOCALESIGNATURE sig;
+ dialog.isLocaleRTL=0;
+ if(GetLocaleInfo(dialog.locale,LOCALE_FONTSIGNATURE,(LPTSTR)&sig,sizeof(sig)/sizeof(TCHAR)))
+ dialog.isLocaleRTL=(sig.lsUsb[3]&0x8000000); // Win2000+: testing for 'Layout progress: horizontal from right to left' bit
+ switch(PRIMARYLANGID(LANGIDFROMLCID(dialog.locale))) { // prior to Win2000
+ case LANG_ARABIC:
+ case LANG_HEBREW:
+ case LANG_FARSI:
+ dialog.isLocaleRTL=1;
+ }
+ }
+
+ // body
+ fseek(fp,startOfLine,SEEK_SET);
+ success=1;
+ control=NULL;
+ while(!feof(fp)) {
+ if(fgets(line,SIZEOF(line),fp)==NULL) break;
+ if(IsEmpty(line) || line[0]==';' || line[0]=='\0') continue;
+ TrimStringSimple(line);
+
+ if(line[0]=='[' && line[lstrlenA(line)-1]==']') {
+ pszLine=line+1;
+ line[lstrlenA(line)-1]='\0';
+
+ // module
+ pszColon=strrchr(pszLine,':');
+ if(pszColon==NULL) continue;
+ *pszColon='\0';
+ pszColon++;
+ TrimString(pszLine);
+ if(lstrcmpiA(dtsp->szModule,pszLine)) continue;
+ pszBuf=pszLine;
+
+ // dlgid
+ pszLine=pszColon;
+ pszColon=strrchr(pszLine,'@');
+ if(pszColon==NULL) continue;
+ *pszColon='\0';
+ pszColon++;
+ TrimString(pszColon);
+ if(lstrcmpA(dtsp->szDlgId,pszColon)) continue;
+
+ if(dialog.szModule==NULL && dialog.szId==NULL) {
+ dialog.szModule=mir_strdup(pszBuf);
+ dialog.szId=mir_strdup(pszColon);
+ if(dialog.szId==NULL || dialog.szModule==NULL) {
+ success=0;
+ break;
+ }
+ }
+ buf=(struct DlgControlData*)mir_realloc(dialog.control,sizeof(struct DlgControlData)*(dialog.controlCount+1));
+ if(buf==NULL) {
+ success=0;
+ break;
+ }
+ dialog.controlCount++;
+ dialog.control=(struct DlgControlData*)buf;
+ control=&dialog.control[dialog.controlCount-1];
+ ZeroMemory(control,sizeof(*control));
+
+ // ctlid
+ TrimString(pszLine);
+ control->id=atoi(pszLine);
+ }
+ else if(control!=NULL) {
+ pszLine=line;
+
+ // ctltext
+ pszColon=strchr(pszLine,'=');
+ if(pszColon==NULL) continue;
+ *pszColon='\0';
+ pszColon++;
+ TrimString(pszColon);
+ TrimString(pszLine);
+ if(*pszColon=='\0' || *pszLine=='\0') continue;
+#if defined(_UNICODE)
+ { int size=lstrlenA(pszLine)+1;
+ control->szTitle=(WCHAR*)mir_alloc(size*sizeof(WCHAR));
+ if(control->szTitle!=NULL) {
+ *control->szTitle=_T('\0');
+ MultiByteToWideChar(dialog.defaultCodePage,0,pszLine,-1,control->szTitle,size);
+ }
+ }
+#else
+ control->szTitle=mir_strdup(pszLine);
+#endif
+
+ // text
+#if defined(_UNICODE)
+ control->szText=mir_utf8encodecp(pszColon,dialog.defaultCodePage);
+#else
+ control->szText=mir_strdup(pszColon);
+#endif
+ control=NULL; // control done
+ }
+ }
+ fclose(fp);
+
+ if(success) {
+ int i,dialogInserted=0;
+
+ dialog.timeLoaded=dialog.timeLastUsed=GetTickCount();
+ EnterCriticalSection(&csDialogCache);
+ for(i=0;i<dialogCacheCount;i++) {
+ if(dialogCache[i].timeLastUsed && dialogCache[i].timeLastUsed<(dialog.timeLoaded-DIALOGCACHEEXPIRY)) {
+ FreeDialogCacheEntry(&dialogCache[i]);
+ if(dialogInserted || !dialog.controlCount) {
+ MoveMemory(dialogCache+i,dialogCache+i+1,sizeof(struct DialogData)*(dialogCacheCount-i-1));
+ dialogCacheCount--;
+ buf=(struct DialogData*)mir_realloc(dialogCache,sizeof(struct DialogData)*dialogCacheCount);
+ if(buf!=NULL) dialogCache=(struct DialogData*)buf;
+ else if(!dialogCacheCount) dialogCache=NULL;
+ }
+ else {
+ dialogInserted=1;
+ dialogCache[i]=dialog;
+ }
+ }
+ }
+ if(dialog.controlCount && !dialogInserted) {
+ buf=(struct DialogData*)mir_realloc(dialogCache,sizeof(struct DialogData)*(dialogCacheCount+1));
+ if(buf!=NULL) {
+ dialogCacheCount++;
+ dialogCache=(struct DialogData*)buf;
+ dialogCache[dialogCacheCount-1]=dialog;
+ dialogInserted=1;
+ }
+ }
+ LeaveCriticalSection(&csDialogCache);
+
+ if(!dialogInserted) {
+ mir_free(dialog.szId); // does NULL check
+ mir_free(dialog.szModule); // does NULL check
+ mir_free(dialog.control); // does NULL check
+ }
+ if(!Miranda_Terminated() && IsWindow(hwndHelpDlg))
+ PostMessage(hwndHelpDlg,M_HELPLOADED,0,(LPARAM)dtsp->hwndCtl);
+ }
+ if(!success) {
+ mir_free(dialog.szId); // does NULL check
+ mir_free(dialog.szModule); // does NULL check
+ mir_free(dialog.control); // does NULL check
+ if(!Miranda_Terminated() && IsWindow(hwndHelpDlg))
+ PostMessage(hwndHelpDlg,M_HELPLOADFAILED,0,(LPARAM)dtsp->hwndCtl);
+ }
+
+ mir_free(dtsp->szDlgId);
+ mir_free(dtsp->szModule);
+ mir_free(dtsp);
+}
+
+// mir_free() the return value
+char *CreateControlIdentifier(const char *pszDlgId,const char *pszModule,int ctrlId,HWND hwndCtl)
+{
+ int size;
+ char *szId;
+ TCHAR szDefCtlText[128];
+ GetControlTitle(hwndCtl,szDefCtlText,SIZEOF(szDefCtlText));
+ size=lstrlenA(pszModule)+lstrlenA(pszDlgId)+SIZEOF(szDefCtlText)+22;
+ szId=(char*)mir_alloc(size);
+ mir_snprintf(szId,size,"[%s:%i@%s]\r\n"TCHAR_STR_PARAM"%s",pszModule,ctrlId,pszDlgId,szDefCtlText,szDefCtlText[0]?"=":"");
+ return szId;
+}
+
+int GetControlHelp(HWND hwndCtl,const char *pszDlgId,const char *pszModule,int ctrlId,TCHAR **ppszTitle,char **ppszText,int *pType,LCID *pLocaleID,UINT *pCodePage,BOOL *pIsRTL,DWORD flags)
+{
+ int i,j,useNext=0;
+ struct LoaderThreadStartParams *dtsp;
+
+ EnterCriticalSection(&csDialogCache);
+ for(i=0;i<dialogCacheCount;i++) {
+ if(!(flags&GCHF_DONTLOAD)) {
+ if(!dialogCache[i].timeLastUsed || dialogCache[i].timeLastUsed<(GetTickCount()-DIALOGCACHEEXPIRY)) {
+ struct DialogData *buf;
+ FreeDialogCacheEntry(&dialogCache[i]);
+ MoveMemory(dialogCache+i,dialogCache+i+1,sizeof(struct DialogData)*(dialogCacheCount-i-1));
+ dialogCacheCount--;
+ buf=(struct DialogData*)mir_realloc(dialogCache,sizeof(struct DialogData)*dialogCacheCount);
+ if(buf!=NULL) dialogCache=(struct DialogData*)buf;
+ else if(!dialogCacheCount) dialogCache=NULL;
+ i--;
+ continue;
+ }
+ }
+ if(lstrcmpA(pszDlgId,dialogCache[i].szId)) break;
+ for(j=0;j<dialogCache[i].controlCount;j++) {
+ if(ctrlId==dialogCache[i].control[j].id || useNext || dialogCache[i].control[j].id==0) {
+ if(dialogCache[i].control[j].szTitle==NULL) {
+ useNext=1;
+ continue;
+ }
+ if(ppszTitle) *ppszTitle=dialogCache[i].control[j].szTitle;
+ if(ppszText) *ppszText=dialogCache[i].control[j].szText;
+ if(pType) *pLocaleID=dialogCache[i].locale;
+#if defined(_UNICODE)
+ if(pCodePage) *pCodePage=CP_UTF8;
+#else
+ if(pCodePage) *pCodePage=dialogCache[i].defaultCodePage;
+#endif
+ if(pIsRTL) *pIsRTL=dialogCache[i].isLocaleRTL;
+ if(dialogCache[i].control[j].id!=ctrlId && !useNext) continue;
+ dialogCache[i].timeLastUsed=GetTickCount();
+ LeaveCriticalSection(&csDialogCache);
+ return 0;
+ }
+ }
+ break;
+ }
+
+ if(ppszTitle) *ppszTitle=NULL;
+ if(ppszText) *ppszText=NULL;
+ if(pType) *pType=CTLTYPE_UNKNOWN;
+ if(pLocaleID) *pLocaleID=LOCALE_USER_DEFAULT;
+ if(pCodePage) *pCodePage=CP_ACP;
+
+ if(!(flags&GCHF_DONTLOAD)) {
+ dtsp=(struct LoaderThreadStartParams*)mir_alloc(sizeof(struct LoaderThreadStartParams));
+ if(dtsp==NULL) {
+ LeaveCriticalSection(&csDialogCache);
+ return 0;
+ }
+ dtsp->szDlgId=mir_strdup(pszDlgId);
+ dtsp->szModule=mir_strdup(pszModule);
+ if(dtsp->szDlgId==NULL || dtsp->szModule==NULL) {
+ mir_free(dtsp->szDlgId); // does NULL check
+ mir_free(dtsp->szModule); // does NULL check
+ mir_free(dtsp);
+ LeaveCriticalSection(&csDialogCache);
+ return 0;
+ }
+ dtsp->ctrlId=ctrlId;
+ dtsp->hwndCtl=hwndCtl;
+ mir_forkthread(LoaderThread,dtsp);
+ }
+ LeaveCriticalSection(&csDialogCache);
+ return 1;
+}
+
+/**************************** SAVE HELP ***************************/
+
+#ifdef EDITOR
+void SetControlHelp(const char *pszDlgId,const char *pszModule,int ctrlId,TCHAR *pszTitle,char *pszText,int type)
+{
+ int i,j;
+ int found=0;
+ void *buf;
+
+ EnterCriticalSection(&csDialogCache);
+ j=0;
+ for(i=0;i<dialogCacheCount;i++) {
+ if(lstrcmpA(pszDlgId,dialogCache[i].szId)) continue;
+ for(j=0;j<dialogCache[i].controlCount;j++) {
+ if(ctrlId==dialogCache[i].control[j].id) {
+ mir_free(dialogCache[i].control[j].szTitle); // does NULL check
+ mir_free(dialogCache[i].control[j].szText); // does NULL check
+ dialogCache[i].control[j].szTitle=NULL;
+ dialogCache[i].control[j].szText=NULL;
+ found=1;
+ break;
+ }
+ }
+ if(!found) {
+ buf=(struct DlgControlData*)mir_realloc(dialogCache[i].control,sizeof(struct DlgControlData)*(dialogCache[i].controlCount+1));
+ if(buf==NULL) {
+ LeaveCriticalSection(&csDialogCache);
+ return;
+ }
+ dialogCache[i].control=(struct DlgControlData*)buf;
+ j=dialogCache[i].controlCount++;
+ found=1;
+ }
+ break;
+ }
+ if(!found) {
+ buf=(struct DialogData*)mir_realloc(dialogCache,sizeof(struct DialogData)*(dialogCacheCount+1));
+ if(buf==NULL) {
+ LeaveCriticalSection(&csDialogCache);
+ return;
+ }
+ dialogCache=(struct DialogData*)buf;
+ dialogCache[i].control=(struct DlgControlData*)mir_alloc(sizeof(struct DlgControlData));
+ if(dialogCache[i].control==NULL) {
+ LeaveCriticalSection(&csDialogCache);
+ return;
+ }
+ dialogCache[i].controlCount=1;
+ i=dialogCacheCount;
+ j=0;
+
+ dialogCache[i].szId=mir_strdup(pszDlgId);
+ dialogCache[i].szModule=mir_strdup(pszModule);
+ if(dialogCache[i].szId==NULL || dialogCache[i].szModule==NULL) {
+ mir_free(dialogCache[i].szId); // does NULL check
+ mir_free(dialogCache[i].szModule); // does NULL check
+ LeaveCriticalSection(&csDialogCache);
+ return;
+ }
+ dialogCacheCount++;
+ dialogCache[i].timeLoaded=0;
+ }
+ dialogCache[i].control[j].szTitle=mir_tstrdup(pszTitle); // does NULL arg check
+ dialogCache[i].control[j].szText=mir_strdup(pszText); // does NULL arg check
+ dialogCache[i].control[j].type=type;
+ dialogCache[i].control[j].id=ctrlId;
+ dialogCache[i].timeLastUsed=GetTickCount();
+ dialogCache[i].changes=1;
+ LeaveCriticalSection(&csDialogCache);
+}
+
+static void DialogCacheSaveThread(void *unused)
+{
+ int success=0;
+ UNREFERENCED_PARAMETER(unused);
+
+ // TODO: port the following code to write to the helppack file instead
+ // (netlib code already removed)
+ /*
+ { WCHAR *szDecoded;
+ char *szEncoded=mir_strdup(dialogCache[i].control[j].szText);
+ if(mir_utf8decode(szEncoded,&szDecoded)) {
+ [...]
+ mir_free(szDecoded)
+ }
+ mir_free(szEncoded); // does NULL check
+ }
+
+
+ int i,j;
+ struct ResizableCharBuffer data={0},dlgId={0};
+
+ for(i=0;i<dialogCacheCount;i++) {
+ if(!dialogCache[i].changes) continue;
+
+ AppendToCharBuffer(&data,"t <dialog id=\"%s\" module=\"%s\">\r\n",dialogCache[i].szId,dialogCache[i].szModule);
+ for(j=0;j<dialogCache[i].controlCount;j++) {
+ AppendToCharBuffer(&data,"<control id=%d type=%d>\r\n",dialogCache[i].control[j].id,dialogCache[i].control[j].type);
+ if(dialogCache[i].control[j].szTitle) AppendToCharBuffer(&data,"<title>%s</title>\r\n",dialogCache[i].control[j].szTitle);
+ if(dialogCache[i].control[j].szText) AppendToCharBuffer(&data,"<text>%s</text>\r\n",dialogCache[i].control[j].szText);
+ AppendToCharBuffer(&data,"</control>\r\n");
+ }
+ AppendToCharBuffer(&data,"</dialog>");
+ }
+
+ if(success) {
+ dialogCache[i].changes=0;
+ dialogCache[i].timeLoaded=GetTickCount();
+ }
+ */
+ MessageBoxEx(NULL,success?TranslateT("Help saving complete."):TranslateT("Help saving failed!"),TranslateT("Help Editor"),(success?MB_ICONINFORMATION:MB_ICONERROR)|MB_OK|MB_SETFOREGROUND|MB_TOPMOST|MB_TASKMODAL,LANGIDFROMLCID((LCID)CallService(MS_LANGPACK_GETLOCALE, 0, 0)));
+}
+
+void SaveDialogCache(void)
+{
+ mir_forkthread(DialogCacheSaveThread,0,NULL);
+}
+#endif // defined EDITOR
diff --git a/Help/dlgboxsubclass.c b/Help/dlgboxsubclass.c
new file mode 100644
index 0000000..ff0706c
--- /dev/null
+++ b/Help/dlgboxsubclass.c
@@ -0,0 +1,455 @@
+/*
+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 <tchar.h>
+#define _WIN32_WINNT 0x0400
+#define __RPCASYNC_H__ /* header shows warnings in VS6 */
+#include <windows.h>
+#include <win2k.h>
+
+#define MIRANDA_VER 0x0600
+#include <newpluginapi.h>
+#include <m_langpack.h>
+#include <stdio.h>
+#include <m_system.h>
+#include <m_utils.h>
+#include "help.h"
+#include "m_help.h"
+
+#include "resource.h"
+
+#define SC_CONTEXTHELP_SEPARATOR SC_SEPARATOR+1
+#define SC_CONTEXTHELP_DIALOG SC_CONTEXTHELP+1
+
+#define PROP_CONTEXTSTATE _T("HelpPlugin_ContextState")
+#define PROPF_MENUFORCED 0x01 // always show help context menu for ctl (override default)
+#define PROPF_MENUDISABLED 0x02 // never show help context menu for ctl
+#define PROPF_AUTOTIPFORCED 0x04 // always show autotip for ctl (override default)
+#define PROPF_AUTOTIPDISABLED 0x08 // never show autotip for ctl
+
+extern HINSTANCE hInst;
+extern HWND hwndHelpDlg;
+extern WORD settingAutoTipDelay;
+static HHOOK hMessageHook,hKeyboardHook,hEatNextMouseHook=NULL;
+static HANDLE hServiceShowHelp,hServiceSetContext;
+
+struct DlgBoxSubclassData {
+ HWND hwndDlg;
+ WNDPROC pfnOldWndProc;
+ DWORD flags;
+} static *dlgBoxSubclass=NULL;
+static int dlgBoxSubclassCount=0;
+static CRITICAL_SECTION csDlgBoxSubclass;
+
+#define DBSDF_MINIMIZABLE 0x01 // WS_MINIMIZEBOX style was set on hooked window
+#define DBSDF_MAXIMIZABLE 0x02 // WS_MAXIMIZEBOX style was set on hooked window
+
+struct FindChildAtPointData {
+ HWND hwnd;
+ POINT pt;
+ int bestArea;
+};
+
+// ChildWindowFromPoint() messes up with group boxes
+static BOOL CALLBACK FindChildAtPointEnumProc(HWND hwnd,LPARAM lParam)
+{
+ if(IsWindowVisible(hwnd)) {
+ struct FindChildAtPointData *fcap=(struct FindChildAtPointData*)lParam;
+ RECT rcVisible,rc,rcParent;
+ GetWindowRect(hwnd,&rc);
+ GetWindowRect(GetParent(hwnd),&rcParent);
+ IntersectRect(&rcVisible,&rcParent,&rc);
+ if(PtInRect(&rcVisible,fcap->pt)) {
+ int thisArea=(rc.bottom-rc.top)*(rc.right-rc.left);
+ if(thisArea && (thisArea<fcap->bestArea || fcap->bestArea==0)) {
+ fcap->bestArea=thisArea;
+ fcap->hwnd=hwnd;
+ }
+ }
+ }
+ return TRUE;
+}
+
+// IsChild() messes up with owned windows
+int IsRealChild(HWND hwndParent,HWND hwnd)
+{
+ while(hwnd!=NULL) {
+ if(hwnd==hwndParent) return 1;
+ if(hwndParent==GetWindow(hwnd,GW_OWNER)) return 0;
+ hwnd=GetParent(hwnd);
+ }
+ return 0;
+}
+
+static BOOL CALLBACK RemovePropForAllChildsEnumProc(HWND hwnd,LPARAM lParam)
+{
+ RemoveProp(hwnd,(TCHAR*)lParam);
+ return TRUE;
+}
+
+static HWND hwndMouseMoveDlg=NULL;
+static UINT idMouseMoveTimer=0;
+static LONG cursorPos=MAKELONG(-1,-1);
+static int openedAutoTip=0;
+static void CALLBACK NoMouseMoveForDelayTimerProc(HWND hwnd,UINT msg,UINT idTimer,DWORD time)
+{
+ POINT pt;
+ HWND hwndCtl;
+ struct FindChildAtPointData fcap;
+ UNREFERENCED_PARAMETER(msg);
+ UNREFERENCED_PARAMETER(time);
+
+ KillTimer(hwnd,idTimer);
+ if(idMouseMoveTimer!=idTimer) return;
+ idMouseMoveTimer=0;
+ if(!settingAutoTipDelay || !IsWindow(hwndMouseMoveDlg)) return;
+
+ ZeroMemory(&fcap,sizeof(fcap));
+ if(!GetCursorPos(&pt)) return;
+ // ChildWindowFromPoint() messes up with group boxes
+ fcap.hwnd=NULL;
+ fcap.pt=pt;
+ EnumChildWindows(hwndMouseMoveDlg,FindChildAtPointEnumProc,(LPARAM)&fcap);
+ hwndCtl=fcap.hwnd;
+ if(hwndCtl==NULL) {
+ ScreenToClient(hwndMouseMoveDlg,&pt);
+ hwndCtl=ChildWindowFromPointEx(hwndMouseMoveDlg,pt,CWP_SKIPINVISIBLE);
+ if(hwndCtl==NULL) return;
+ }
+ { LONG flags=(LONG)GetProp(hwndCtl,PROP_CONTEXTSTATE);
+ if(flags&PROPF_AUTOTIPDISABLED) return;
+ flags=SendMessage(hwndCtl,WM_GETDLGCODE,(WPARAM)VK_RETURN,(LPARAM)NULL);
+ if(flags&DLGC_HASSETSEL || flags&DLGC_WANTALLKEYS) return; // autotips on edits are annoying
+ }
+ { CURSORINFO ci;
+ BOOL (WINAPI *pfnGetCursorInfo)(CURSORINFO*);
+ ci.cbSize=sizeof(ci);
+ *(FARPROC*)&pfnGetCursorInfo=GetProcAddress(GetModuleHandleA("USER32"),"GetCursorInfo");
+ if(pfnGetCursorInfo && IsWinVer2000Plus()) // call not safe for WinNT4
+ if(pfnGetCursorInfo(&ci) && !(ci.flags&CURSOR_SHOWING)) return;
+ }
+ if(IsRealChild(hwndMouseMoveDlg,hwndCtl) && hwndHelpDlg==NULL) {
+ hwndHelpDlg=CreateDialog(hInst,MAKEINTRESOURCE(IDD_HELP),NULL,HelpDlgProc);
+ if(hwndHelpDlg==NULL) return;
+ openedAutoTip=1;
+ PostMessage(hwndHelpDlg,M_CHANGEHELPCONTROL,0,(LPARAM)hwndCtl);
+ }
+}
+
+static LRESULT CALLBACK KeyboardInputHookProc(int code,WPARAM wParam,LPARAM lParam)
+{
+ if(code==HC_ACTION && idMouseMoveTimer!=0) {
+ KillTimer(NULL,idMouseMoveTimer);
+ idMouseMoveTimer=0;
+ }
+ return CallNextHookEx(hKeyboardHook,code,wParam,lParam);
+}
+
+// workaround for WM_HELP (SC_CONTEXTHELP causes an additional WM_LBUTTONUP when selecting)
+static LRESULT CALLBACK EatNextMouseButtonUpHookProc(int code,WPARAM wParam,LPARAM lParam)
+{
+ if(code>=0 && wParam==WM_LBUTTONUP) {
+ UnhookWindowsHookEx(hEatNextMouseHook); // unhook ourselves
+ hEatNextMouseHook=NULL;
+ return -1;
+ }
+ return CallNextHookEx(hEatNextMouseHook,code,wParam,lParam);
+}
+
+static LRESULT CALLBACK DialogBoxSubclassProc(HWND hwndDlg,UINT msg,WPARAM wParam,LPARAM lParam)
+{
+ WNDPROC pfnWndProc;
+ DWORD flags;
+ int i;
+
+ EnterCriticalSection(&csDlgBoxSubclass);
+ for(i=0;i<dlgBoxSubclassCount;i++)
+ if(dlgBoxSubclass[i].hwndDlg==hwndDlg) break;
+ if(i==dlgBoxSubclassCount) {
+ LeaveCriticalSection(&csDlgBoxSubclass);
+ return 0;
+ }
+ pfnWndProc=dlgBoxSubclass[i].pfnOldWndProc;
+ flags=dlgBoxSubclass[i].flags;
+ if(msg==WM_NCDESTROY) {
+ struct DlgBoxSubclassData *buf;
+ MoveMemory(dlgBoxSubclass+i,dlgBoxSubclass+i+1,sizeof(struct DlgBoxSubclassData)*(dlgBoxSubclassCount-i-1));
+ dlgBoxSubclassCount--;
+ buf=(struct DlgBoxSubclassData*)mir_realloc(dlgBoxSubclass,sizeof(struct DlgBoxSubclassData)*dlgBoxSubclassCount);
+ if(buf!=NULL) dlgBoxSubclass=buf;
+ else if(!dlgBoxSubclassCount) dlgBoxSubclass=NULL;
+ }
+ LeaveCriticalSection(&csDlgBoxSubclass);
+
+ switch(msg) {
+ case WM_INITMENUPOPUP:
+ if(flags&DBSDF_MINIMIZABLE || flags&DBSDF_MAXIMIZABLE) {
+ HMENU hMenu=GetSystemMenu(hwndDlg,FALSE);
+ int isMin,isMax;
+ if((HMENU)wParam!=hMenu) break;
+ isMin=IsIconic(hwndDlg);
+ isMax=IsZoomed(hwndDlg);
+ EnableMenuItem(hMenu,SC_RESTORE,MF_BYCOMMAND|(isMin || isMax)?MF_ENABLED:MF_GRAYED);
+ EnableMenuItem(hMenu,SC_MINIMIZE,MF_BYCOMMAND|(flags&DBSDF_MINIMIZABLE && !isMin)?MF_ENABLED:MF_GRAYED);
+ EnableMenuItem(hMenu,SC_MAXIMIZE,MF_BYCOMMAND|(flags&DBSDF_MAXIMIZABLE && !isMax)?MF_ENABLED:MF_GRAYED);
+ EnableMenuItem(hMenu,SC_SIZE,MF_BYCOMMAND|(GetWindowLong(hwndDlg,GWL_STYLE)&WS_THICKFRAME && !isMin && !isMax)?MF_ENABLED:MF_GRAYED);
+ }
+ break;
+ case WM_MOUSEMOVE: // TrackMouseEvent() would disturb too much
+ if(!settingAutoTipDelay) break;
+ if(cursorPos==lParam) break;
+ cursorPos=lParam;
+ case WM_LBUTTONDOWN:
+ case WM_LBUTTONUP:
+ case WM_MOUSEWHEEL:
+ if(!settingAutoTipDelay) break;
+ if(msg!=WM_MOUSEMOVE && !idMouseMoveTimer) break;
+ if(openedAutoTip && IsWindow(hwndHelpDlg)) DestroyWindow(hwndHelpDlg);
+ openedAutoTip=0;
+ hwndMouseMoveDlg=hwndDlg;
+ if(hwndHelpDlg==NULL)
+ idMouseMoveTimer=SetTimer(NULL,idMouseMoveTimer,settingAutoTipDelay,NoMouseMoveForDelayTimerProc);
+ break;
+ case WM_CAPTURECHANGED:
+ if((HWND)lParam==hwndDlg) break;
+ case WM_SHOWWINDOW:
+ case WM_WINDOWPOSCHANGING:
+ case WM_MOVING:
+ case WM_SIZING:
+ case WM_CANCELMODE:
+ case WM_CHILDACTIVATE:
+ case WM_MOUSEACTIVATE:
+ case WM_ACTIVATEAPP:
+ case WM_ACTIVATE:
+ if(idMouseMoveTimer) KillTimer(NULL,idMouseMoveTimer);
+ idMouseMoveTimer=0;
+ break;
+ case WM_SYSCOMMAND:
+ if((UINT)wParam==SC_CONTEXTHELP_DIALOG) { // alt. "What's this Dialog?"
+ if(idMouseMoveTimer) KillTimer(NULL,idMouseMoveTimer);
+ idMouseMoveTimer=0;
+ if(hwndHelpDlg==NULL) {
+ hwndHelpDlg=CreateDialog(hInst,MAKEINTRESOURCE(IDD_HELP),NULL,HelpDlgProc);
+ if(hwndHelpDlg==NULL) break;
+ }
+ SendMessage(hwndHelpDlg,M_CHANGEHELPCONTROL,0,(LPARAM)hwndDlg);
+ return 0;
+ }
+ break;
+ case WM_CONTEXTMENU:
+ { POINT pt;
+ HWND hwndCtl;
+ struct FindChildAtPointData fcap;
+
+ // workaround for badly coded plugins that do display a context menu
+ // and pass the message to DefWindowProc afterwards (doing a "break;").
+ if(GetTickCount()-GetMessageTime()>10) return 0;
+
+ if(idMouseMoveTimer) KillTimer(NULL,idMouseMoveTimer);
+ idMouseMoveTimer=0;
+
+ ZeroMemory(&fcap,sizeof(fcap));
+ POINTSTOPOINT(pt,MAKEPOINTS(lParam));
+ // ChildWindowFromPoint() messes up with group boxes
+ fcap.hwnd=NULL;
+ fcap.pt=pt;
+ EnumChildWindows(hwndDlg,FindChildAtPointEnumProc,(LPARAM)&fcap);
+ hwndCtl=fcap.hwnd;
+ if(hwndCtl==NULL) {
+ ScreenToClient(hwndDlg,&pt);
+ hwndCtl=ChildWindowFromPointEx(hwndDlg,pt,CWP_SKIPINVISIBLE);
+ if(hwndCtl==NULL) break;
+ POINTSTOPOINT(pt,MAKEPOINTS(lParam));
+ }
+ { LONG flags=(LONG)GetProp(hwndCtl,PROP_CONTEXTSTATE);
+ if(flags&PROPF_MENUDISABLED) break;
+ else if(!(flags&PROPF_MENUFORCED)) {
+ int type=GetControlType(hwndCtl);
+ // showing a context menu on these looks silly (multi components)
+ if(type==CTLTYPE_TOOLBAR || type==CTLTYPE_LISTVIEW || type==CTLTYPE_TREEVIEW || type==CTLTYPE_STATUSBAR || type==CTLTYPE_CLC)
+ break;
+ }
+ }
+ if(IsRealChild(hwndDlg,hwndCtl)) {
+ HMENU hMenu=CreatePopupMenu();
+ AppendMenu(hMenu,MF_STRING,SC_CONTEXTHELP,(hwndCtl==hwndDlg)?TranslateT("&What's this Dialog?"):TranslateT("&What's this?"));
+ if(TrackPopupMenuEx(hMenu,TPM_LEFTALIGN|TPM_TOPALIGN|TPM_HORPOSANIMATION|TPM_VERPOSANIMATION|TPM_RIGHTBUTTON|TPM_RETURNCMD|TPM_NONOTIFY,pt.x,pt.y,hwndDlg,NULL)) {
+ if(hwndHelpDlg==NULL) {
+ hwndHelpDlg=CreateDialog(hInst,MAKEINTRESOURCE(IDD_HELP),NULL,HelpDlgProc);
+ if(hwndHelpDlg==NULL) {
+ DestroyMenu(hMenu);
+ break;
+ }
+ }
+ SendMessage(hwndHelpDlg,M_CHANGEHELPCONTROL,0,(LPARAM)hwndCtl);
+ }
+ DestroyMenu(hMenu);
+ }
+ return 0;
+ }
+ case WM_HELP:
+ { HELPINFO *hi=(HELPINFO*)lParam;
+ if(hi->iContextType!=HELPINFO_WINDOW) break;
+ // fix for SHBrowseForFolder() dialog, which sends unhandled help to parent
+ if(!IsRealChild(hwndDlg,hi->hItemHandle)) break;
+
+ if(idMouseMoveTimer) KillTimer(NULL,idMouseMoveTimer);
+ idMouseMoveTimer=0;
+
+ if(!IsWindow(hwndHelpDlg)) {
+ hwndHelpDlg=CreateDialog(hInst,MAKEINTRESOURCE(IDD_HELP),NULL,HelpDlgProc);
+ if(hwndHelpDlg==NULL) break;
+ }
+ SendMessage(hwndHelpDlg,M_CHANGEHELPCONTROL,0,(LPARAM)hi->hItemHandle);
+ // we need to eat the next WM_LBUTTONDOWN (if invoked by mouse)
+ if(GetKeyState(GetSystemMetrics(SM_SWAPBUTTON)?VK_RBUTTON:VK_LBUTTON)&0x8000 && hEatNextMouseHook==NULL)
+ hEatNextMouseHook=SetWindowsHookEx(WH_MOUSE,EatNextMouseButtonUpHookProc,NULL,GetCurrentThreadId());
+ return TRUE;
+ }
+ case WM_NCDESTROY:
+ if(idMouseMoveTimer) KillTimer(NULL,idMouseMoveTimer);
+ idMouseMoveTimer=0;
+ EnumChildWindows(hwndDlg,RemovePropForAllChildsEnumProc,(LPARAM)PROP_CONTEXTSTATE);
+ { TCHAR text[64];
+ mir_sntprintf(text,SIZEOF(text),_T("unhooked window 0x%X for context help\n"),hwndDlg);
+ OutputDebugString(text);
+ }
+ SetWindowLong(hwndDlg,GWL_WNDPROC,(LONG)pfnWndProc);
+ break;
+ }
+ return CallWindowProc(pfnWndProc,hwndDlg,msg,wParam,lParam);
+}
+
+static LRESULT CALLBACK HelpSendMessageHookProc(int code,WPARAM wParam,LPARAM lParam)
+{
+ if(code>=0) {
+ CWPSTRUCT *msg=(CWPSTRUCT*)lParam;
+ switch(msg->message) {
+ case WM_INITDIALOG: // dialogs and message boxes
+ if(GetClassLong(msg->hwnd,GCW_ATOM)!=32770) // class="#32770"
+ break;
+ if(msg->hwnd==hwndHelpDlg || (DLGPROC)GetWindowLong(msg->hwnd,DWL_DLGPROC)==HelpDlgProc)
+ break;
+#ifndef EDITOR
+ if((DLGPROC)GetWindowLong(msg->hwnd,DWL_DLGPROC)==ShadowDlgProc) break;
+#endif
+ { DWORD style,exStyle;
+ struct DlgBoxSubclassData *buf;
+
+ exStyle=GetWindowLong(msg->hwnd,GWL_EXSTYLE);
+ if(exStyle&WS_EX_CONTEXTHELP) break;
+ style=GetWindowLong(msg->hwnd,GWL_STYLE);
+
+ EnterCriticalSection(&csDlgBoxSubclass);
+ buf=(struct DlgBoxSubclassData*)mir_realloc(dlgBoxSubclass,sizeof(struct DlgBoxSubclassData)*(dlgBoxSubclassCount+1));
+ if(buf==NULL) {
+ LeaveCriticalSection(&csDlgBoxSubclass);
+ break;
+ }
+ dlgBoxSubclass=buf;
+ dlgBoxSubclass[dlgBoxSubclassCount].hwndDlg=msg->hwnd;
+ dlgBoxSubclass[dlgBoxSubclassCount].pfnOldWndProc=(WNDPROC)SetWindowLong(msg->hwnd,GWL_WNDPROC,(LONG)DialogBoxSubclassProc);
+ dlgBoxSubclass[dlgBoxSubclassCount].flags=0;
+
+ // WS_EX_CONTEXTHELP cannot be used in conjunction WS_MINIMIZEBOX or WS_MAXIMIZEBOX
+ // solution: switch off WS_MINIMIZEBOX or WS_MAXIMIZEBOX when only one of them is present
+ if(!(style&WS_MINIMIZEBOX) || !(style&WS_MAXIMIZEBOX)) {
+ if(style&WS_MINIMIZEBOX) dlgBoxSubclass[dlgBoxSubclassCount].flags|=DBSDF_MINIMIZABLE;
+ if(style&WS_MAXIMIZEBOX) dlgBoxSubclass[dlgBoxSubclassCount].flags|=DBSDF_MAXIMIZABLE;
+ SetWindowLong(msg->hwnd,GWL_STYLE,style&(~(WS_MINIMIZEBOX|WS_MAXIMIZEBOX)));
+ SetWindowLong(msg->hwnd,GWL_EXSTYLE,exStyle|WS_EX_CONTEXTHELP);
+ }
+ dlgBoxSubclassCount++;
+ LeaveCriticalSection(&csDlgBoxSubclass);
+ }
+ { HMENU hMenu;
+ hMenu=GetSystemMenu(msg->hwnd,FALSE);
+ if(hMenu!=NULL && AppendMenu(hMenu,MF_SEPARATOR,SC_CONTEXTHELP_SEPARATOR,NULL)) {
+ AppendMenu(hMenu,MF_STRING,SC_CONTEXTHELP,TranslateT("&What's this?"));
+ AppendMenu(hMenu,MF_STRING,SC_CONTEXTHELP_DIALOG,TranslateT("&What's this Dialog?"));
+ }
+ }
+ { TCHAR text[64];
+ mir_sntprintf(text,SIZEOF(text),_T("hooked window 0x%X for context help\n"),msg->hwnd);
+ OutputDebugString(text);
+ }
+ break;
+ }
+ }
+ return CallNextHookEx(hMessageHook,code,wParam,lParam);
+}
+
+static int ServiceShowHelp(WPARAM wParam,LPARAM lParam)
+{
+ UNREFERENCED_PARAMETER(lParam);
+ if(!IsWindow((HWND)wParam)) return 1;
+ if(idMouseMoveTimer) KillTimer(NULL,idMouseMoveTimer);
+ idMouseMoveTimer=0;
+ if(hwndHelpDlg==NULL) {
+ hwndHelpDlg=CreateDialog(hInst,MAKEINTRESOURCE(IDD_HELP),NULL,HelpDlgProc);
+ if(hwndHelpDlg==NULL) return 2;
+ }
+ PostMessage(hwndHelpDlg,M_CHANGEHELPCONTROL,0,(LPARAM)wParam);
+ return 0;
+}
+
+static int ServiceSetContextState(WPARAM wParam,LPARAM lParam)
+{
+ int i;
+ LONG flags;
+ EnterCriticalSection(&csDlgBoxSubclass);
+ for(i=0;i<dlgBoxSubclassCount;i++)
+ if(IsRealChild(dlgBoxSubclass[i].hwndDlg,(HWND)wParam)) break;
+ if(i==dlgBoxSubclassCount) {
+
+ LeaveCriticalSection(&csDlgBoxSubclass);
+
+ return 2;
+
+ }
+ LeaveCriticalSection(&csDlgBoxSubclass);
+ flags=(lParam&HCSF_CONTEXTMENU)?PROPF_MENUFORCED:PROPF_MENUDISABLED;
+ flags|=(lParam&HCSF_AUTOTIP)?PROPF_AUTOTIPFORCED:PROPF_AUTOTIPDISABLED;
+ return !SetProp((HWND)wParam,PROP_CONTEXTSTATE,(HANDLE)flags);
+}
+
+int InstallDialogBoxHook(void)
+{
+ InitializeCriticalSection(&csDlgBoxSubclass);
+ hServiceShowHelp=CreateServiceFunction(MS_HELP_SHOWHELP,ServiceShowHelp);
+ hServiceSetContext=CreateServiceFunction(MS_HELP_SETCONTEXTSTATE,ServiceSetContextState);
+ hMessageHook=SetWindowsHookEx(WH_CALLWNDPROC,HelpSendMessageHookProc,NULL,GetCurrentThreadId()); // main thread
+ hKeyboardHook=SetWindowsHookEx(IsWinVerNT()?WH_KEYBOARD_LL:WH_KEYBOARD,KeyboardInputHookProc,NULL,GetCurrentThreadId()); // main thread
+ return hMessageHook==NULL;
+}
+
+int RemoveDialogBoxHook(void)
+{
+ int i;
+ DestroyServiceFunction(hServiceShowHelp); // does NULL check
+ DestroyServiceFunction(hServiceSetContext); // does NULL check
+ UnhookWindowsHookEx(hMessageHook);
+ if(hKeyboardHook) UnhookWindowsHookEx(hMessageHook);
+ if(hEatNextMouseHook) UnhookWindowsHookEx(hEatNextMouseHook);
+ DeleteCriticalSection(&csDlgBoxSubclass);
+ for(i=0;i<dlgBoxSubclassCount;i++)
+ SetWindowLong(dlgBoxSubclass[i].hwndDlg,GWL_WNDPROC,(LONG)dlgBoxSubclass[i].pfnOldWndProc);
+ mir_free(dlgBoxSubclass); // does NULL check
+ return 0;
+}
diff --git a/Help/docs/Help-Developer.txt b/Help/docs/Help-Developer.txt
new file mode 100644
index 0000000..28326ee
--- /dev/null
+++ b/Help/docs/Help-Developer.txt
@@ -0,0 +1,93 @@
+
+Help Plugin 0.2.1.2 for Miranda IM 0.6+
+------------------------------------------------------------------------
+ Developer Information
+
+ Contents: -------------------------------
+ | Help Packs, Translation, Debug Symbols,
+ | Coding Language, Rebase Info
+
+Help Packs
+-----------------
+ Help texts are stored in a file named 'helppack_*.txt'
+ To use the file, place it in the same directory as miranda32.exe, and call it
+ helppack_*.txt where * can be anything, however it is recommended that it
+ be the language.
+
+ An entry in the help file looks like this:
+
+ [context_identifier]
+ Some text shown as title=Some text<br>that might contain simple html code
+
+ IMPORTANT HINT:
+ When you press the 'Ctrl' key while opening up the context help tooltip
+ it will display the help identifier used in the help file, instead of
+ the help text. This is helpful when writing your help file.
+ When you press 'Ctrl'-C while a helptip is opened, its text will get
+ copied to clipboard.
+
+ A list of available HTML tags that might be helpful when writing
+ help texts:
+ styles: <i>italic</i>, <b>bold</b>, <u>underlined</u>
+ linebreak: <br>
+ sizes: <big>large text</big>, <small>tiny text</small>
+ hyperlinks: <a href="url">link title</a>
+ paragraph: <p>text</p>
+ colors: <font color="#colorcode">colmred text</font>
+ instead of #hexcode you can also use the following 16 default color names:
+ black, maroon, green, olive, navy, purple, teal, silver,
+ gray, red, lime, yellow, blue, fuchsia, aqua, white
+
+ Be careful when using those html tags.
+ Do not use them massively, instead pick them when appropriate to
+ guide the reader. Keep in mind that it is still a *help* text.
+
+ Some special symbols must be specified differently:
+ instead of < use &lt;
+ instead of > use &gt;
+ instead of & use &amp;
+ instead of " use &quot;
+ A space can be also specified as &nbsp;
+
+ To specify a specific Unicode character
+ you can use a special numeric representation:
+ &#[x][Number];
+ Examples: &#945; and &#x3B1;
+ When you place an x in in front the number needs to be hexadecimal.
+
+ Please refer to 'helppack_sample.txt' for an example help file.
+
+Translation
+-----------------
+ Translation strings for language pack maintainers can be found in
+ 'Help-Translation.txt'.
+
+Debug Symbols
+-----------------
+ Debug symbols are also available for debugging purposes.
+ Copy the PDB-files into the same directory as the
+ corresponding DLL-files.
+ To debug crashes the supplied MAP-file file might be helpful.
+
+Coding Language
+-----------------
+ Help Plugin was written using Microsoft Visual C++ 6.0 SP6
+ and the Microsoft Platform SDK shipped along with it.
+
+ The project files for VS 7 and 8 (*.vcproj and *.vspscc) are not
+ kept up-to-date.
+ The working project files are the ones of VS 6 (*.dsw and *.dsp).
+
+Rebase Info
+-----------------
+ Help Plugin has set its base address to:
+ 0x20100000
+
+ Please avoid using this base address for your plugins because it will
+ slow down the start of Miranda IM.
+ Try to choose a unique base address for each plugin you create.
+
+ Using Microsoft Visual C++, the base address can be configured at:
+ 'Project' -> 'Settings' -> 'Linker' -> 'Output' -> 'Base Address'
+
+H. Herkenrath (hrathh at users.sourceforge.net)
diff --git a/Help/docs/Help-License.txt b/Help/docs/Help-License.txt
new file mode 100644
index 0000000..a726a52
--- /dev/null
+++ b/Help/docs/Help-License.txt
@@ -0,0 +1,278 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
diff --git a/Help/docs/Help-Readme.txt b/Help/docs/Help-Readme.txt
new file mode 100644
index 0000000..20859ca
--- /dev/null
+++ b/Help/docs/Help-Readme.txt
@@ -0,0 +1,196 @@
+
+Help Plugin 0.2.1.2
+------------------------------------------------------------------------
+ Plugin for Miranda IM 0.6 and +
+
+ Plugin Info: ----------------------------
+ | Version: 0.2.1.2
+ | Filename: help.dll
+ | Authors: R. Hughes, H. Herkenrath (hrathh at users.sourceforge.net)
+ | Description: Provides context sensitive help in all of the Miranda IM dialog boxes.
+
+ Contents: -------------------------------
+ | Features, Requirements, Usage, Installation,
+ | Bugs and Wishes, Version History,
+ | Translation, License and Copyright
+
+Features
+----------------------
+ + Display help tooltips on request for every component in a window
+ + Tooltips always occur below the element to show help for
+ + All help texts are stored in a Help Pack file ('helppack_<language>.txt')
+ + Allows to switch installed Help Packs easily
+ + Displays all information about the Help Packs in one place
+ + Shows which Help Pack includes support for what plugins
+ + Auto-Updates for all installed Help Packs
+ + Wizard helping you to download and install your native language
+ + Right-click on a help pack entry to be able to uninstall it
+ + Help API file for developers to control the help in their dialogs
+ + Full Unicode support
+ + Automatic installation of all files, just unzip into Plugins directory
+ + Supported plugins: Database Editor, Country Flags
+
+Requirements
+----------------------
+ -> Miranda IM 0.6+:
+ Miranda IM is needed in version 0.6 or greater.
+
+Usage
+----------------------
+ Provides support for context-sensitive help in all of Miranda's dialog boxes.
+ Right click, press F1 or use the ? button in the title bar.
+
+ When a dialog supports context sensitive help, you can right click
+ on every control element to get more information about it.
+ Dialogs that don't have a minimize or maximize box in their caption do also show
+ an additional button with a '?'-symbol in their window caption.
+ The F1 key is also recognized as a context help call in dialogs.
+
+ The used Help Pack file can be selected here:
+ 'Options' -> 'Customize' -> 'Help'
+
+Installation
+----------------------
+ Find 'miranda32.exe' on your computer.
+
+ Just copy all the contents of the zip-file as they are into the 'Plugins' directory
+ in the Miranda IM folder.
+ The Help Plugin will detect the files and move them into the appropriate
+ directories on it's first run.
+
+ You can also do all the installation by hand, if you want to:
+
+ Main Plugin: Copy the file 'help.dll' into the 'Plugins' directory
+ in the Miranda IM folder.
+ The file 'helppack_english.txt' needs to copied into the main directory
+ of Miranda IM.
+
+ The Unicode version of the plugin will only work on Windows NT/2000/XP,
+ Windows Server 2000, Windows Vista or later with an installed
+ Unicode version of Miranda IM.
+ To use it on Windows 95/98/Me, please download the ANSI version of the plugin.
+
+ Documentation: The txt-files should be moved along with the SDK-zip into the
+ 'Docs' directory in the Miranda IM folder.
+
+ That's it!
+
+Bugs and Wishes
+----------------------
+ Feel free to mail me your wishes about 'Language Pack Manager' and tell
+ me all the bugs you may find.
+ My email address is: hrathh at users.sourceforge.net
+
+Version History
+----------------------
+ 0.2.1.2 - CTRL-key: copies a proposed ctl title for ctl identifier
+ - corrected user-agent
+ - minor fixes
+ 0.2.1.1 - corrected exported version number
+ - temporarily deactivated the download wizard on first run
+ (as there is nothing yet to be downloaded)
+ - removed 'cache expiry' setting from options, auto-detects file change
+ 0.2.1.0 - added auto-updates
+ - added native language download wizard
+ - updated to use new miranda headers
+ - added automatic installation for helppack files and docs
+ (move them to correct directory)
+ - obeys win context ids when set
+ - synced with last official help.dll
+ - added v0.8 support
+ 0.2.0.6 - minor fix for ownerdefined window classes
+ - hyperlink cursor was incorrectly destroyed
+ - corrected <a></a> tag parsing when improperly formated
+ - hyperlinks now use correct system color (was problem with richedit)
+ 0.2.0.5 - fixed focus stealing due to WM_ACTIVATE recursion
+ - adjustments for helptips about editable controls (autotip)
+ - fix for WM_HELP causing an additional WM_LBUTTONUP (fixes help about buttons)
+ - fixed issue with SHBrowseForFiles and other 'owned' windows
+ - corrected richedit offset (approx. 2px)
+ - shows endellipsis if title text is too long
+ - adjusted spinner control handling
+ - small fix for caching
+ - disallow empty title/text
+ - fixed <p></p> tag parsing
+ - removed unnecessary services of 0.2.0.0
+ - minor cleanups
+ 0.2.0.4 - minor fix for unhooking
+ - pressing ctrl-c on tip copies helptip text to clipboard
+ - minor locale related fix
+ 0.2.0.1 - Added: optional shows autotips (see option page, experimental, feature might be dropped eventually)
+ - Fixed: discovered minor problem with threading conncurrency
+ - Modified: now also shows '?' box for minizable dialogs (especially options dialog)
+ - Minor fixes
+ 0.2.0.0 - New generation release
+ - Now the plugin uses a text file (helppack_*.txt) to store its data
+ The server method was defunct and nobody ever updated/stored
+ help texts. You even needed a password.
+ Now the functionality is similar to the langpacks.
+ The syntax of the helppack files is kept *very* similar to the
+ langpack ones
+ - Updated: control type detection to recgnize newer controls
+ - Replaced: netlib/networking code with file reading code
+ - Added: Help API (m_help.h) for developers
+ - Added: Full unicode support
+ - Fixed: Help support for MessageBoxes (was buggy)
+ - Added: press 'Ctrl' while showing the help tooltip to get
+ the identifier used in the helppack file
+ - Fixed: DlgId handling was not well though out
+ - Fixed: some memory leaks in low memory conditions in conjunction with realloc
+ - Fixed: some rare occuring errors were not handled
+ - Fixed: help on help tooltip is disabled (was buggy)
+ - Fixed: some unicode problems
+ - Fixed: thread safety (MS_SYSTEM_THREAD_PUSH/POP was not used)
+ - Fixed: now also supports generating IDs for IDC_STATIC(-1) controls
+ - Fixed: created some services to avoid conflicting context menus
+ - Fixed: codepage usage
+ - Replaced: uses miranda's simple memory problems catcher
+ - Verified all code, used SAME PROGRAMMING STYLE AS ORIGINAL
+ - Fixed: some minor issues with unchecked return values
+ - Changed: Moved the Cache Expiry setting to the options (was hardcoded)
+ - Some other minor fixes and updated code
+ 0.1.2.2 - previous help plugin using http requests
+
+Translation
+----------------------
+ Translation strings and available bad words strings can be found
+ in 'Help-Translation.txt' of the SDK package.
+
+License and Copyright
+----------------------
+ Help Plugin is released under the terms of the
+ GNU General Public License.
+ See 'Help-License.txt' for more details.
+
+ Copyright (c) 2002 Richard Hughes, 2005-2006 Heiko Herkenrath.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. The origin of this software must not be misrepresented; you must
+ not claim that you wrote the original software. If you use this
+ software in a product, an acknowledgment in the product
+ documentation would be appreciated but is not required.
+ 3. Altered source versions must be plainly marked as such, and must
+ not be misrepresented as being the original software.
+ 4. The name of the author may not be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESS
+ OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+H. Herkenrath (hrathh at users.sourceforge.net)
diff --git a/Help/docs/Help-Translation.txt b/Help/docs/Help-Translation.txt
new file mode 100644
index 0000000..ed3dc1d
--- /dev/null
+++ b/Help/docs/Help-Translation.txt
@@ -0,0 +1,217 @@
+
+Help Plugin 0.2.1.2 for Miranda IM 0.6+
+------------------------------------------------------------------------
+ Translator Information
+
+ Contents: -------------------------------
+ | Help Texts, Plugin Texts, String Listing
+
+Help Texts
+-----------------------------
+ The help texts can be translated using the help pack files.
+ To get an explanation on how such a file needs to be formated
+ please refer to 'helppack_sample.txt'.
+
+Plugin Texts
+-----------------------------
+ The Help Plugin can be translated with the Miranda IM
+ language files.
+
+ Put the following strings in a file called 'langpack_<language>.txt'
+ in the Miranda IM directory and translate them into your
+ language.
+ If you need more info on Miranda IM language files visit:
+ http://miranda.svn.sourceforge.net/viewvc/*checkout*/miranda/trunk/miranda/i18n/readme.txt
+
+String Listing
+-----------------------------
+
+; --- Plugin: Help Plugin 0.2.1.2 (German) ---
+
+; Translation by hrathh
+; Please report any mistakes or missing strings in here.
+
+[Help]
+Hilfe
+[Provides context sensitive help in the Miranda IM dialog boxes.]
+Bietet kontextsensitive Hilfe in allen Dialogen von Miranda IM.
+
+; Errors
+[Help Plugin]
+Hilfe-Plugin
+[The Help Plugin can not be loaded. It requires Miranda IM %hs or later.]
+Das Hilfe-Plugin kann nicht geladen werden. Es benötigt Miranda IM %hs oder neuer.
+[The Help Plugin can not be loaded, riched20.dll is missing. If you are using Windows 95 or WINE please make sure you have riched20.dll installed.\n\nPress 'Yes' to continue loading the Help Plugin.]
+Das Hilfe-Plugin kann nicht geladen werden, da riched20.dll fehlt. Sofern Windows 95 oder WINE verwendet wird stellen Sie bitte sicher, dass riched20.dll installiert ist.\n\nKlicken Sie auf "Ja" um das Hilfe-Plugin trotzdem zu laden.
+
+; Context Menu
+[&What's this?]
+Direkt&hilfe
+[&What's this Dialog?]
+Direkt&hilfe zum Dialog
+
+; Tooltip
+[Loading...]
+Bitte warten...
+[No Help Pack installed!]
+Keine Hilfe-Datei installiert!
+[No help available for this item.]
+Diesem Eintrag ist kein Hilfethema zugeordnet.
+[&Copy]
+&Kopieren
+
+; Advanced Options
+;[Customize]
+[Help]
+Hilfe
+[Advanced]
+Erweitert
+[Context Help]
+Context-Sensitive Hilfe
+[&Automatically show help when hovered]
+&Automatisch Hilfe anbieten bei Stillstand der Maus
+[&Delay:]
+&Verzögerung:
+[milliseconds]
+Millisekunden
+
+; Language Options
+;[Customize]
+;[Help]
+[Language]
+Sprachen
+[&Remove...]
+&Entfernen...
+[Installed Languages]
+Installierte Sprachen
+[File]
+Datei
+[built-in]
+enthalten
+[Author(s):]
+Autor(en):
+[E-mail:]
+E-Mail:
+[Last modified using:]
+Verwendung von:
+[Date:]
+Datum:
+;[Version:]
+;[Locale:]
+[(incompatible)]
+(inkompatibel)
+[Unknown]
+Unbekannt
+[Current]
+Aktuell
+[Not included:]
+Nicht enthalten:
+;[%hs (%s)]
+[All installed plugins are included.]
+Alle installierten Plugins sind enthalten.
+;[No Help Pack installed!]
+[Download more Help Packs]
+Weitere Hilfedateien herunterladen
+[Check for new &versions of Help Packs periodically]
+Regelmäßig auf neue Hilfedatei-&Versionen überprüfen
+[&Download Language]
+Sprache &herunterladen
+
+; All names of the language packs can be translated
+[English (default)]
+Englisch (Standard)
+
+; Update Notify
+[Help Pack Update Now Available]
+Update für Hilfedatei ist jetzt verfügbar
+[A new version of a Help Pack is now available. Click the install button to download and install this new update.]
+Eine neue Version einer Hilfedatei ist verfügbar. Klicken Sie auf "Jetzt installieren" um das neue Update herunterzuladen und zu installieren.
+[Language:]
+Sprache:
+[Current:]
+Aktuell:
+[New:]
+Neu:
+[&Install Now]
+Jetzt &installieren
+;[Close]
+[Help Pack Update succeeded]
+Hilfedatei-Update erfolgreich
+[The help pack "%s" has been sucessfully downloaded and installed.]
+Die Hilfedatei "%s" wurde erfolgreich heruntergeladen und aktualisiert.
+[Help Pack Update failed]
+Hilfedatei-Update fehlgeschlagen
+[The help pack "%s" could not be downloaded or extracted.]
+Die Hilfedatei "%s" konnte nicht heruntergeladen oder extrahiert werden.
+
+; Download Language
+[Select your help language]
+Sprache der Hilfetexte wählen
+[Help is available in different languages.\nHere is a list of all available languages of the file listing, please select your native &language:]
+Hilfe is in vielen Sprachen verfügbar.\nEs folgt eine Liste aller verfügbaren Sprachen auf der Website. Bitte wählen Sie Ihre gewünschte &Sprache aus:
+[Download &all languages]
+&Alle Sprachen herunterladen
+[Note: This will download and install the newest help pack available for the selected language. There might be help packs from other authors available on the file listing.]
+Hinweis: Es wird die jeweils neueste Hilfedatei für die gewählte Sprache heruntergeladen. Es könnten noch weitere Hilfedateien von anderen Autoren auf der Website verfügbar sein.
+[downloading]
+downloaden
+;[OK]
+;[Cancel]
+[Help Pack Download finished]
+Hilfedatei-Download beendet
+[The download succeeded!]
+Der Download war erfolgreich!
+[The download failed!\n\nThe help pack could not be downloaded or extracted.]
+Der Download schlug fehl!\n\nDie Hilfedatei konnte nicht heruntergeladen oder extrahiert werden.
+
+; All language subcategory names on the website can be translated
+;[English (default)]
+[Chinese]
+Chinesisch
+[Portuguese]
+Portugiesisch
+[French]
+Französisch
+[Hebrew]
+Hebräisch
+[Hungarian]
+Ungarisch
+[Italian]
+Italienisch
+[Spanish]
+Spanisch
+[Ukrainian]
+Ukrainisch
+[Russian]
+Russisch
+[German]
+Deutsch
+[Dutch]
+Holländisch
+[Bulgarian]
+Bulgarisch
+[Czech]
+Tschechisch
+[Korean]
+Koreanisch
+[Polish]
+Polnisch
+[Turkish]
+Türkisch
+[Swedish]
+Schwedisch
+[Japanese]
+Japanisch
+[Belarusian]
+Weißrussisch
+[Danish]
+Dänisch
+[Finnish]
+Finnisch
+[Croatian]
+Kroatisch
+
+; ---
+
+
+H. Herkenrath (hrathh at users.sourceforge.net)
diff --git a/Help/docs/helppack_english.txt b/Help/docs/helppack_english.txt
new file mode 100644
index 0000000..ef7ffb1
--- /dev/null
+++ b/Help/docs/helppack_english.txt
@@ -0,0 +1,193 @@
+Miranda Help Pack Version 1
+Language: English (default)
+Locale: 0809
+Last-Modified-Using: Miranda IM 0.6
+Authors: hrathh, -pv-
+Author-email: hrathh at users.sourceforge.net
+Plugins-included: clist_classic,clist_nicer
+
+; options dialog
+[miranda32:0@AgEAAgIAAgMAD6IEA0IF]
+Options=In this window you can view and modify all settings relevant for Miranda IM, its Protocols and all other enabled plugins.
+[miranda32:1377@AgEAAgIAAgMAD6IEA0IF]
+Select a subentry from the list=When you see this you have not selected any option page in the list on the left or the selected item does not have any options to set.
+[miranda32:1@AgEAAgIAAgMAD6IEA0IF]
+OK=Saves all the changes you have made on the various opened option pages and closes the options window.
+[miranda32:2@AgEAAgIAAgMAD6IEA0IF]
+Cancel=Discards changes you have made and closes the options window.
+[miranda32:3@AgEAAgIAAgMAD6IEA0IF]
+Apply=Saves all the changes you have made on the various opened option pages without closing the options window.
+[miranda32:1346@AgEAAgIAAgMAD6IEA0IF]
+Show expert options=Enable this to get more option possibilities shown which are normally not interesting for average users.
+[miranda32:1186@AgEAAgIAAgMAD6IEA0IF]
+List with option pages=Shows all available option categories. Pick one category to get its options shown on the right side of the list.
+
+; sounds options
+[miranda32:0@AowEAo0EE7AED3kG]
+Sounds=On this options page you can view and modify all audible events of Miranda IM and its plugins.
+[miranda32:-2@AowEAo0EE7AED3kG]
+[miranda32:1657@AowEAo0EE7AED3kG]
+List of all sounds=Shows all available audible events to which sounds can be associated.<br>To specify a sound file select an item in the list. A checkmark means playing the sound is enabled for this event.
+[miranda32:1660@AowEAo0EE7AED3kG]
+Sound Information=View or modify the sound file associated with the event selected in the list above.
+[miranda32:1009@AowEAo0EE7AED3kG]
+[miranda32:1010@AowEAo0EE7AED3kG]
+Name=The name of the sound event as also shown in the list above. Summarizes section name and event name.
+[miranda32:1661@AowEAo0EE7AED3kG]
+[miranda32:1659@AowEAo0EE7AED3kG]
+Location=Shows the path of the sound file selected by clicking the <b>Change...</b> button. When no sound file was yet selected <i>&lt;not specified&gt;</i> is shown instead.
+[miranda32:1165@AowEAo0EE7AED3kG]
+Preview=Plays the sound file specified at <b>Location</b>.
+[miranda32:1164@AowEAo0EE7AED3kG]
+Change...=Opens up a window where you can select a sound file to be played when the sound event occurs.
+[miranda32:1200@AowEAo0EE7AED3kG]
+Download more sounds=Opens up your default browser pointing it to the <i>Sounds</i> download section at Miranda IM's website.
+
+; plugins options
+[miranda32:0@DowGB40GB48GB5EGE5IGE5QG]
+Plugins=On this options page you can view and modify the state of the modules installed for Miranda IM.
+[miranda32:1676@DowGB40GB48GB5EGE5IGE5QG]
+List of plugins=In the list you find all installed modules whether they are running or disabled. This list includes protocols, the database driver and contact list interfaces. You can enable or disable any module you like by ticking or unticking its list item.<br><i>You need to restart Miranda IM after enabling or disabling a module for the changes to take effect!</i>
+[miranda32:1680@DowGB40GB48GB5EGE5IGE5QG]
+Plugin Information=Shows all a descriptive information about the plugin you have selected in the list above. When nothing is selected this part is empty.
+[miranda32:-2@DowGB40GB48GB5EGE5IGE5QG]
+[miranda32:1677@DowGB40GB48GB5EGE5IGE5QG]
+Description=A description of the plugin you selected in the list above.
+[miranda32:-3@DowGB40GB48GB5EGE5IGE5QG]
+[miranda32:1679@DowGB40GB48GB5EGE5IGE5QG]
+Author(s)=Shows all people involved in developing the selected plugin.
+[miranda32:-5@DowGB40GB48GB5EGE5IGE5QG]
+[miranda32:1684@DowGB40GB48GB5EGE5IGE5QG]
+E-mail=Shows the E-mail address of the plugin maintainer.
+[miranda32:-6@DowGB40GB48GB5EGE5IGE5QG]
+[miranda32:1682@DowGB40GB48GB5EGE5IGE5QG]
+Homepage=The homepage of the plugin. This usually refers to a page belonging to the addons section at the website of Miranda IM.
+[miranda32:1692@DowGB40GB48GB5EGE5IGE5QG]
+Please restart Miranda IM=You need to restart Miranda IM for your changes to take effect. This occurs when you enabled or disabled a plugin in the list above.
+
+; ignore options
+[miranda32:0@Bl8FBmAFBrYEBgEABrcEBrgEBrkEFDcEBgYG]
+[miranda32:-10@Bl8FBmAFBrYEBgEABrcEBrgEBrkEFDcEBgYG]
+Ignore=On this options page you can ignore or un-ignore events of all protocols in Miranda IM.
+[miranda32:-2@Bl8FBmAFBrYEBgEABrcEBrgEBrkEFDcEBgYG]
+[miranda32:1079@Bl8FBmAFBrYEBgEABrcEBrgEBrkEFDcEBgYG]
+List of events being ignored=List of all contacts in your database you can toggle any ignore settings for each use by clicking the small icons on their right.<br>Icon slots not being enabled for contacts are not appropriate for them.<p><b>*** All contacts ***</b> helps you to set ignore settings for all the contact in the list.<br>To do this just for contact belonging to a group, set the settings for their group item instead.</p><p><b>*** Unknown contacts ***</b> refers to all contact to added by you to your contact list, but who are trying to contact you though.
+[miranda32:1375@Bl8FBmAFBrYEBgEABrcEBrgEBrkEFDcEBgYG]
+[miranda32:-3@Bl8FBmAFBrYEBgEABrcEBrgEBrkEFDcEBgYG]
+Ignore messages=When this icon is displayed on the right side of a contact, all incoming messages sent by him/her will be dropped. You will not be notified.
+[miranda32:1376@Bl8FBmAFBrYEBgEABrcEBrgEBrkEFDcEBgYG]
+[miranda32:-4@Bl8FBmAFBrYEBgEABrcEBrgEBrkEFDcEBgYG]
+Ignore URLs=When this icon is displayed on the right side of a contact, all incoming URL messages sent by him/her will be dropped. You will not be notified.
+[miranda32:1206@Bl8FBmAFBrYEBgEABrcEBrgEBrkEFDcEBgYG]
+[miranda32:-5@Bl8FBmAFBrYEBgEABrcEBrgEBrkEFDcEBgYG]
+Ignore files=When this icon is displayed on the right side of a contact, all file transfers initiated by him/her will be automatically denied.
+[miranda32:1@Bl8FBmAFBrYEBgEABrcEBrgEBrkEFDcEBgYG]
+[miranda32:-6@Bl8FBmAFBrYEBgEABrcEBrgEBrkEFDcEBgYG]
+Suppress auth requests=When this icon is displayed on the right side of a contact, all requests for authorisation to add you to his/her contact list will be suppressed.
+[miranda32:1207@Bl8FBmAFBrYEBgEABrcEBrgEBrkEFDcEBgYG]
+[miranda32:-7@Bl8FBmAFBrYEBgEABrcEBrgEBrkEFDcEBgYG]
+Suppress online notification=When this icon is displayed on the right side of a contact, you will never be notified when the contact goes online.
+[miranda32:1542@Bl8FBmAFBrYEBgEABrcEBrgEBrkEFDcEBgYG]
+[miranda32:-11@Bl8FBmAFBrYEBgEABrcEBrgEBrkEFDcEBgYG]
+Suppress added notification=When this icon is displayed on the right side of a contact, you will not be notified when the contact added you to his/her contact list sending you a notification.
+[miranda32:1208@Bl8FBmAFBrYEBgEABrcEBrgEBrkEFDcEBgYG]
+[miranda32:-8@Bl8FBmAFBrYEBgEABrcEBrgEBrkEFDcEBgYG]
+Ignore all=Clicking this icon next to a contact will set all possible ignorable events to being ignored.
+[miranda32:1209@Bl8FBmAFBrYEBgEABrcEBrgEBrkEFDcEBgYG]
+[miranda32:-9@Bl8FBmAFBrYEBgEABrcEBrgEBrkEFDcEBgYG]
+Ignore none=Clicking this icon next to a contact will un-ignore all events for it. No event will be ignored or be suppressed in the future.
+[miranda32:1380@Bl8FBmAFBrYEBgEABrcEBrgEBrkEFDcEBgYG]
+Only ticked contacts will be shown=The list above also shows some checkboxes in front of the contacts and groups.<br>Only contacts with a checkmark in front of them will actually be shown on your contact list interface. All un-ticked ones will be hidden.
+
+; contact display options
+[miranda32:0@D9IE]
+[miranda32:-2@D9IE]
+Contact Display=On this options page you can set how the contact names on your list will be displayed.
+[miranda32:-3@D9IE]
+[miranda32:1234@D9IE]
+Name display order=Normally contacts are displayed by their nickname of the contact list. However, this behaviour can be adjusted.<br>The list you see display the order in which the contact lists tried to get a name for a contact. If the first element in the shown list does not provide a name the next list item below is queried.<p><b>My custom name</b> is not movable. The customized name of a contact you entered by hand will always be shown regardless what you set here.</p><p>When all ways to get a name for a contact do fail it will be displayed as <b>'(Unknown Contact)'. That item is not movable, too.</p>
+
+
+; ### contribution by -pv-, thanks a lot!!! ###
+; [x] checked for typos
+; [x] added dialog tooltip
+; [x] added some unhandled context-identifiers
+
+; file transfers options
+[miranda32:0@B70EAsMFA8wFA+0DA+wDBNMFBNIFBNEFCc0FAsQFA9AFBOwFBNkFBN0FBO8F]
+File Transfers=On this options page you can view and modify all settings regarding to file transfers that can be initiated by most of the protocols of Miranda IM.
+[miranda32:-2@B70EAsMFA8wFA+0DA+wDBNMFBNIFBNEFCc0FAsQFA9AFBOwFBNkFBN0FBO8F]
+Receiving files=These options control the file receiving process itself.
+[miranda32:-3@B70EAsMFA8wFA+0DA+wDBNMFBNIFBNEFCc0FAsQFA9AFBOwFBNkFBN0FBO8F]
+[miranda32:1213@B70EAsMFA8wFA+0DA+wDBNMFBNIFBNEFCc0FAsQFA9AFBOwFBNkFBN0FBO8F]
+Received files folder=Type in a path where received files will be stored in or use the button on the right labeled with '<b>...</b>'.
+[miranda32:-7@B70EAsMFA8wFA+0DA+wDBNMFBNIFBNEFCc0FAsQFA9AFBOwFBNkFBN0FBO8F]
+Variables Allowed=You do not need to provide a fixed path where all received files go in. Instead, you can enrich your path specification by using some variables refering to the user the file is received from.<br><br>Allowed variables are:<br><b>%userid%</b> gets replaced by the contact's UID specify to the protocol.<br><b>%nick%</b> represents the nickname of the contact.<br><b>%proto%</b> stands for the protocol name associated withe the contact.
+[miranda32:1475@B70EAsMFA8wFA+0DA+wDBNMFBNIFBNEFCc0FAsQFA9AFBOwFBNkFBN0FBO8F]
+Browse for folder=Opens a window where you can choose a folder to store received files into.
+[miranda32:1484@B70EAsMFA8wFA+0DA+wDBNMFBNIFBNEFCc0FAsQFA9AFBOwFBNkFBN0FBO8F]
+Auto-accept files from people on my contact list=When this is ticked and someone from your contact list is trying to send you a file, the transfer will be accepted automatically.
+[miranda32:1005@B70EAsMFA8wFA+0DA+wDBNMFBNIFBNEFCc0FAsQFA9AFBOwFBNkFBN0FBO8F]
+Minimize the file transfer window=Enable this to have the transfer window minimized each time you accept the transfer or when it got accepted automatically according to the <b>Auto-accept incoming files from people on my contact list</b> option.
+[miranda32:1004@B70EAsMFA8wFA+0DA+wDBNMFBNIFBNEFCc0FAsQFA9AFBOwFBNkFBN0FBO8F]
+Close window when transfer completes=After a file or the group of files is successfully transferred, enabling this will close the window automatically
+[miranda32:1520@B70EAsMFA8wFA+0DA+wDBNMFBNIFBNEFCc0FAsQFA9AFBOwFBNkFBN0FBO8F]
+Virus scanner=Using these options you can have your preferred anti-virus software scan downloaded files as soon as they are downloaded.
+[miranda32:-4@B70EAsMFA8wFA+0DA+wDBNMFBNIFBNEFCc0FAsQFA9AFBOwFBNkFBN0FBO8F]
+[miranda32:1489@B70EAsMFA8wFA+0DA+wDBNMFBNIFBNEFCc0FAsQFA9AFBOwFBNkFBN0FBO8F]
+[miranda32:1490@B70EAsMFA8wFA+0DA+wDBNMFBNIFBNEFCc0FAsQFA9AFBOwFBNkFBN0FBO8F]
+[miranda32:1491@B70EAsMFA8wFA+0DA+wDBNMFBNIFBNEFCc0FAsQFA9AFBOwFBNkFBN0FBO8F]
+Scan files=You can have your preferred anti-virus software scan downloaded files as soon as they are downloaded. If you choose <b>When all files have been downloaded</b> or <b>As each file finishes downloading</b> you have to specify a command-line to your scanner application. Some well-known command-lines will be predefined for you.
+[miranda32:1492@B70EAsMFA8wFA+0DA+wDBNMFBNIFBNEFCc0FAsQFA9AFBOwFBNkFBN0FBO8F]
+[miranda32:1485@B70EAsMFA8wFA+0DA+wDBNMFBNIFBNEFCc0FAsQFA9AFBOwFBNkFBN0FBO8F]
+[miranda32:1493@B70EAsMFA8wFA+0DA+wDBNMFBNIFBNEFCc0FAsQFA9AFBOwFBNkFBN0FBO8F]
+Command line=Enter a file-system path to your anti-virus scanner including parameters to scan the files or folders here.<br>When a well-known scanner is found on your system some, a command-line will be predefined for you. Pick the one you like to use.<br>Use <i>%f</i> as filename parameter. The variable gets replaced by the actual file path to be checked.
+[miranda32:1488@B70EAsMFA8wFA+0DA+wDBNMFBNIFBNEFCc0FAsQFA9AFBOwFBNkFBN0FBO8F]
+Warn me before opening a file that has not been scanned=Displays a warning if some of the received files were not scanned.
+[miranda32:1476@B70EAsMFA8wFA+0DA+wDBNMFBNIFBNEFCc0FAsQFA9AFBOwFBNkFBN0FBO8F]
+Browse for files=Brings up a window where you can easily browse the file-system to search for your anti-virus command-line application.
+[miranda32:-5@B70EAsMFA8wFA+0DA+wDBNMFBNIFBNEFCc0FAsQFA9AFBOwFBNkFBN0FBO8F]
+[miranda32:1516@B70EAsMFA8wFA+0DA+wDBNMFBNIFBNEFCc0FAsQFA9AFBOwFBNkFBN0FBO8F]
+[miranda32:-6@B70EAsMFA8wFA+0DA+wDBNMFBNIFBNEFCc0FAsQFA9AFBOwFBNkFBN0FBO8F]
+If incoming files already exists=Choose how to treat a file that has the same location and filename as the file which is going to be received. When you choose <b>Ask me</b> you need to make this decision every time such a conflict occurs.<br>You will <u>always</u> be asked when a file already exists for a contact not added to your contact list.
+[miranda32:1501@B70EAsMFA8wFA+0DA+wDBNMFBNIFBNEFCc0FAsQFA9AFBOwFBNkFBN0FBO8F]
+Overwrite=When this is enabled conflicting files will be overwritten silently.
+[miranda32:1497@B70EAsMFA8wFA+0DA+wDBNMFBNIFBNEFCc0FAsQFA9AFBOwFBNkFBN0FBO8F]
+Resume=The protocol will try to resume file transfer assuming the already existing file was caused by a dropped file transfer. It will be tried to download the previous file correctly.
+[miranda32:1519@B70EAsMFA8wFA+0DA+wDBNMFBNIFBNEFCc0FAsQFA9AFBOwFBNkFBN0FBO8F]
+Rename=The new file being downloaded will get renamed so it no longer has the same name as an already existing file. The file will have <i>(1)</i> etc. appended to its name.
+
+; hotkeys options (clist_classic, clist_nicer)
+; [x] checked for typos
+; [x] added dialog tooltip
+; [x] added some unhandled context-identifiers
+
+[clist_classic:0@A0wEF4oEA04EF4sEA1AEF4wEB1IEA6QEA1EEF40E]
+[clist_classic:-2@A0wEF4oEA04EF4sEA1AEF4wEB1IEA6QEA1EEF40E]
+[clist_nicer:0@A5IEF4oEA18EFzsEA00EFzwEB1IEA3MEA5YEFz4E]
+[clist_nicer:-2@A5IEF4oEA18EFzsEA00EFzwEB1IEA3MEA5YEFz4E]
+Hotkeys=On this options page you can set some basic global hotkeys for Miranda IM.
+[clist_classic:1100@A0wEF4oEA04EF4sEA1AEF4wEB1IEA6QEA1EEF40E]
+[clist_classic:1162@A0wEF4oEA04EF4sEA1AEF4wEB1IEA6QEA1EEF40E]
+[clist_nicer:1170@A5IEF4oEA18EFzsEA00EFzwEB1IEA3MEA5YEFz4E]
+[clist_nicer:1162@A5IEF4oEA18EFzsEA00EFzwEB1IEA3MEA5YEFz4E]
+Show/Hide=Hotkey to show or hide the main contact list window as when clicking the tray icon.<br>To enable check the box. Enable the edit box on the right and assign a hotkey by pressing the desired combination.<br>The default combination is <b>Ctrl + Shift + A</b>.
+[clist_classic:1102@A0wEF4oEA04EF4sEA1AEF4wEB1IEA6QEA1EEF40E]
+[clist_classic:1163@A0wEF4oEA04EF4sEA1AEF4wEB1IEA6QEA1EEF40E]
+[clist_nicer:1119@A5IEF4oEA18EFzsEA00EFzwEB1IEA3MEA5YEFz4E]
+[clist_nicer:1083@A5IEF4oEA18EFzsEA00EFzwEB1IEA3MEA5YEFz4E]
+Read Message=Hotkey to open the message window when a incoming message is notified in the system tray.<br>To enable check the box. Enable the edit box on the right and assign a hotkey by pressing the desired combination.<br>The default combination is <b>Ctrl + Shift + I</b>.
+[clist_classic:1104@A0wEF4oEA04EF4sEA1AEF4wEB1IEA6QEA1EEF40E]
+[clist_classic:1164@A0wEF4oEA04EF4sEA1AEF4wEB1IEA6QEA1EEF40E]
+[clist_classic:1106@A0wEF4oEA04EF4sEA1AEF4wEB1IEA6QEA1EEF40E]
+[clist_classic:1188@A0wEF4oEA04EF4sEA1AEF4wEB1IEA6QEA1EEF40E]
+[clist_nicer:1101@A5IEF4oEA18EFzsEA00EFzwEB1IEA3MEA5YEFz4E]
+[clist_nicer:1084@A5IEF4oEA18EFzsEA00EFzwEB1IEA3MEA5YEFz4E]
+[clist_nicer:1106@A5IEF4oEA18EFzsEA00EFzwEB1IEA3MEA5YEFz4E]
+[clist_nicer:1139@A5IEF4oEA18EFzsEA00EFzwEB1IEA3MEA5YEFz4E]
+Net Search=You can make Miranda IM work together with your favourite search engine. Check the <B>Net Search</b> box, enter a keystroke into the hotkey box and put the URL to your search engine into the <b>URL</b> box. Alternatively, you can use the given default search engine. You can fine-tune the behaviour by checking <b>Open in new browser window.</b> in which case a new and not an existing browser window will be used.<br>The default browser will be used for this action.<br>The default combination is <b>Ctrl + Shift + S</b>.
+[clist_classic:1105@A0wEF4oEA04EF4sEA1AEF4wEB1IEA6QEA1EEF40E]
+[clist_classic:1165@A0wEF4oEA04EF4sEA1AEF4wEB1IEA6QEA1EEF40E]
+Show Options=Hotkey to open the options window of Miranda IM just as opening it via the main menu.<br>To enable check the box. Enable the edit box on the right and assign a hotkey by pressing the desired combination.<br>The default combination is <b>Ctrl + Shift + O</b>.
+
+
diff --git a/Help/docs/helppack_sample.txt b/Help/docs/helppack_sample.txt
new file mode 100644
index 0000000..4489b4b
--- /dev/null
+++ b/Help/docs/helppack_sample.txt
@@ -0,0 +1,256 @@
+Miranda Help Pack Version 1
+Language: English (sample)
+Locale: 0809
+Last-Modified-Using: Miranda IM 0.6
+Authors: hrathh
+Author-email: hrathh at users.sourceforge.net
+Plugins-included: help
+
+; This is a sample help package, documenting the file format.
+; For some example help text look at the end of the file.
+
+
+; *** GENERAL ***
+; Blank lines and lines starting with ; are ignored.
+; You cannot use "[identifier] ;this is a comment"
+; The first line must be maintained as-is, or the file will not be recognised
+; Subsequent lines are in HTTP header format. Do not translate anything before
+; the :
+;
+; You normally do not need to restart Miranda IM for changes in this file to take effect.
+; When you add a new context identifier to this file it will be loaded on next request.
+; However, when you update an existing context identifier and you opened up the
+; associated dialog before, you might need to wait until the cache period has elapsed.
+; The chache can be configured in the help options.
+;
+; Spaces are trimmed from the beginning and end of all strings before parsing.
+; Context identifiers that cannot be found in this file will show "No help available".
+;
+; If a context identifier is duplicated, the first occurence in the file will be used.
+
+
+
+; *** HELP TEXTS ***
+; Help texts are formated using regular text which also can contain
+; some simple HTML code.
+;
+; An entry in the help file looks like this:
+;
+; [context_identifier]
+; Some text shown as title=Some text<br>that might contain simple html code
+;
+; A list of available HTML tags that might be helpful when writing
+; help texts:
+; styles: <i>italic</i>, <b>bold</b>, <u>underlined</u>
+; linebreak: <br>
+; sizes: <big>large text</big>, <small>tiny text</small>
+; hyperlinks: <a href="url">link title</a>
+; paragraph: <p>text</p>
+; colors: <font color="#hexcode">colored text</font>
+; instead of #hexcode you can also use the following 16 default color names:
+; black, maroon, green, olive, navy, purple, teal, silver,
+; gray, red, lime, yellow, blue, fuchsia, aqua, white
+
+; Be careful when using those html tags.
+; Do not use them massively, instead pick them when appropriate to
+; guide the reader. Keep in mind that it is still a *help* text.
+;
+; Some special symbols must be specified differently:
+; instead of < use &lt;
+; instead of > use &gt;
+; instead of & use &amp;
+; instead of " use &quot;
+; A space can be also specified as &nbsp;
+;
+; To specify a specific Unicode character
+; you can use a special numeric representation:
+; &#[x][Number];
+; Examples: &#945; &#x3B1;
+; When you place an x in in front the number needs to be hexadecimal.
+
+; If you maintain a help package and want to find out for which element you can write a help text
+; just do the following:
+; When you press the 'ctrl' key while opening up the context help tooltip
+; it will display the help identifier used in the help file instead of
+; the help text. You can use this identifier to add your help text to the text file.
+; When you press 'ctrl'+C when a helptip is already opened, its text will get
+; copied to clipboard.
+;
+
+; If you would like to assign one single help text to multiple context identifiers just group the
+; identifiers together. The following shows for both identifiers the same text:
+; [identifier1]
+; [identifier2]
+; title=text
+
+
+
+; *** GUIDELINES ***
+; (Subject to change)
+; * Avoid the words 'This is...' or 'This shows...' or something like that at the beginning of
+; a help tip. It is a bit annoying when every tip begins with the same words.
+; Example: A tip could begin immediately by 'Shows... or 'Allows you...')
+; * Try to use efficient language to express everything is a quick manner.
+; * Use correct language ;) I know this is difficult.
+; Hint: MS Word helps a lot for language checking the whole helppack ;)
+; Use English (GB) for the default english helppack.
+; * Bundle together logically individable cuntext-identifiers.
+; Radio buttons should not show a different text for each. Instead, create one single helptext
+; for all grouped together radio buttons. However, this is not a 'fixed' quideline. Let's see when it is appropriate.
+; * Always use the term 'Miranda IM' (not just 'Miranda') when you refer to
+; the whole application. We have to keep this consistent somehow.
+; * Please try to avoid refering to 'Miranda IM' as a whole.
+; Try to reformulate the sentence when you would like to use that term.
+; When reformulating is not possible, its usage is all right.
+
+; Some guidelines about links in the help texts:
+; Those <a href> tags should be used _very_ rarely.
+; I think a good rule is: No use of href tags in general. Use them only in exceptional and reasonable situations.
+; Do not set links just because it is possible.
+; Ah...and only link to offical sources as help.miranda-im.org (at least for the default helppack)
+; Linking to following pages is general no good idea:
+; - inofficial pages
+: - (wiki) pages being still empty or almost empty
+; - forum threads (forums do not provide instant help, summarize important points instead)
+; The help yearning user wan't to work with the window and not dig through some webpage.
+; If he would like to visit the forum he would not do so directly.
+; Acceptable links are (for example):
+; - wiki links to help.miranda-im.org
+; Warning: A link to http://help.miranda-im.org/Plugin:SmileyAdd is not a good idea.
+; The user does not need general info about the plugin anymore because he already installed it!
+; Another Warning: Just a link in the helptip is not very helpful.
+; Links can only be an enrichment and not sole purpose on the tip.
+;
+; A very good academic ;) example for a link would be the following:
+; http://help.miranda-im.org/Installing_smileys_in_Miranda
+; Which could be placed on the tooltip of the '...' button of the 'Events'->'Smileys' page.
+; Of course, with additional text describing it.
+
+
+
+; *** HEADER ***
+; The used Help Pack file can be selected using the Language Pack Manager plugin.
+;
+; The information that is shown in the options about your
+; Help Pack file is taken from the header provided in that file.
+; If you are the author of a langpack file, please make sure the information
+; you give there accurate and does follow the offical rules.
+;
+; The information that is shown in the options about your
+; Help Pack file is taken from the header provided in that file.
+; If you are the author of a langpack file, please make sure the information
+; you give there accurate and does follow the offical rules.
+;
+; The official names of the header tags and what they specify are described here:
+; http://svn.sourceforge.net/viewcvs.cgi/*checkout*/miranda/trunk/miranda/i18n/readme.txt
+; They are exactly the same as the ones for a Language Pack file.
+;
+; Following, I provide a summary of the available tags and
+; I also provide some ideas on how those data should/could be formated.
+; You do not need to follow those suggestions, but I think it would
+; make the provided information more comfortable to read and more informative.
+
+; 'Language' header:
+; A full description of the language in the file, in English, e.g.
+; "English (UK)", "English (US) humorous" or "German".
+; This field should really be in in English so everybody knows what is is about.
+; The string is translated using the current langpack before is is displayed.
+;
+; Just provide a country abbreviation in brackets if it is useful.
+; A value of "French (fr-FR)" is not very senseful. "German (AT)" would be a useful example.
+; Just be a bit smart to find out when those brackets are necessary and when not.
+; Several langpack files for the same language are possible using this field, e.g.
+; "German" pack using "Sie" and "German (informal)" using "Du".
+
+; 'Locale' header:
+; The Windows language code. A complete list is available at
+; http://msdn.microsoft.com/library/default.asp?url=/library/en-us/intl/nls_238z.asp
+; Please make sure this is a correct value and not the english one!
+
+; 'Last-Modified-Using' header:
+; Please keep this line up-to-date, containing the last version of Miranda IM
+; you made changes with, so people can compare files containing the same
+; language to see which is the most up-to-date. The formatting of the value is
+; unimportant, as long as it's human-readable.
+; However, it is more comfortable to read when all Language Packs use
+; the same format.
+; I think we could agree upon the following format: "Miranda IM 0.5"
+; When you used an alpha build the following format fits well:
+; "Miranda IM 0.5 alpha build #60" (as shown in About dialog).
+
+; 'Authors' header:
+; A list of people who have worked on this file. When you do something, add (or
+; move) your name to the front, and put a comma (", ") between each name, e.g.
+; "Hari Seldon, Gaal Dornick"
+; By the nature of the options dialog the place to display this value is very limited.
+; Important and actively developing people should be listed first.
+; Real names should be prefered instead of just nicknames.
+
+; 'Author-email' header:
+; Should contain the e-mail of the person that last changed the file only, on the
+; assumption that that person is qualified to manage the file.
+; It is enough when the user knows one single email address he can write to.
+; If you would like that email address to be obfuscated and not to be retrievable by
+; spambots or viruses scanning harddrives, you can use " at " instead of "@", e.g.
+; "joe.farmer at miranda-im.org". This will be recognized by the plugin.
+
+; 'Plugins-included' header:
+; Contains a list of the plugins that are also translated in this file. It
+; should be a comma-delimited list of the plugin DLL filenames!, e.g.:
+; Plugins-included: splitmsgdialogs,import,historyp
+; As stated in the official specification!
+; You really should follow standards here.
+; The Language Pack Manager uses this list to display a list of installed plugins
+; that are not included in this package.
+; "miranda32" or something like that does not really need to be listed here.
+; The list is case-insensitive, but it is a good idea to use exactly the same
+; case of the DLL file.
+; Just use filenames of the plugin DLLs here, e.g.
+; the plugin named "AimOSCAR.dll" should be listed as "AimOSCAR".
+; It is a good idea to even include plugins into this list that do not have any dialogs
+; where help can be shown, as "png2dib.dll".
+; The inclusion list states which plugins are fully covered by context help texts.
+; "png2dib" is, so it should be listed in the header.
+
+
+
+; ** FILENAME ***
+; Something about the 'helppack_*.txt' file name:
+; To use the file, place it in the same directory as miranda32.exe, and call it
+; helppack_*.txt where * can be anything, however it is recommended that it
+; be the language.
+; It makes sense when the * part of the file name is in English and lower case, e.g.
+; "langpack_chineset.txt" for the "Chinese (Traditional)" package.
+; The file name is never displayed so there should be no problems with it being english.
+; Please avoid using any other character than a-z, 0-9 in this name to keep it portable.
+; Important: Do not include a version number in the file name!
+; It is very hard to update the file when the file name changes all the time.
+; This might also result in multiple files of the same language
+; listed in the options.
+
+
+
+; *** EXAMPLES ***
+; The rest of the file are some example help texts.
+; All identifiers of the help plugin's option page are listed.
+
+; Note: I used nonsense text, no productive helptexts...
+
+[help:0@C+kDC+oD]
+dialog help=this is the option pane with the help options
+
+[help:-2@C+kDC+oD]
+[help:-3@C+kDC+oD]
+Cache Expiry together with context help group=some description here and a <a href="http://forums.miranda-im.org">link</a>.
+
+;[help:1001@C+kDC+oD]
+;editbox example=here you can <i>input</i> some value.
+
+[help:1002@C+kDC+oD]
+spin example=here you can press up to move <font color="red">one up</font>, down to move down.
+
+[help:-4@C+kDC+oD]
+static example=the value is stored in seconds, etc.
+
+[help:-5@C+kDC+oD]
+another example=text here
diff --git a/Help/help.def b/Help/help.def
new file mode 100644
index 0000000..9da7ef0
--- /dev/null
+++ b/Help/help.def
@@ -0,0 +1,11 @@
+LIBRARY help BASE=0x20100000
+SECTIONS
+ ; obfuscated email address
+ .rdata READ WRITE
+EXPORTS
+ MirandaPluginInfo PRIVATE
+ Load PRIVATE
+ Unload PRIVATE
+ ; v0.8 support
+ MirandaPluginInfoEx PRIVATE
+ MirandaPluginInterfaces PRIVATE
diff --git a/Help/help.dep b/Help/help.dep
new file mode 100644
index 0000000..9cc9458
--- /dev/null
+++ b/Help/help.dep
@@ -0,0 +1,120 @@
+# Microsoft Developer Studio erstellte Abhängigkeitsdatei, einbezogen von help.mak
+
+.\datastore.c : \
+ ".\help.h"\
+ ".\include\m_database.h"\
+ ".\include\m_langpack.h"\
+ ".\include\m_plugins.h"\
+ ".\include\m_system.h"\
+ ".\include\m_utils.h"\
+ ".\include\newpluginapi.h"\
+ ".\include\win2k.h"\
+
+
+.\dlgboxsubclass.c : \
+ ".\help.h"\
+ ".\include\m_langpack.h"\
+ ".\include\m_plugins.h"\
+ ".\include\m_system.h"\
+ ".\include\m_utils.h"\
+ ".\include\newpluginapi.h"\
+ ".\include\win2k.h"\
+ ".\m_help.h"\
+
+
+.\helpdlg.c : \
+ ".\help.h"\
+ ".\include\m_langpack.h"\
+ ".\include\m_plugins.h"\
+ ".\include\m_system.h"\
+ ".\include\m_utils.h"\
+ ".\include\newpluginapi.h"\
+ ".\include\win2k.h"\
+
+
+.\helppack.c : \
+ ".\help.h"\
+ ".\include\m_plugins.h"\
+ ".\include\m_system.h"\
+ ".\include\m_utils.h"\
+ ".\include\newpluginapi.h"\
+ ".\include\win2k.h"\
+
+
+.\main.c : \
+ ".\help.h"\
+ ".\include\m_database.h"\
+ ".\include\m_langpack.h"\
+ ".\include\m_plugins.h"\
+ ".\include\m_system.h"\
+ ".\include\m_utils.h"\
+ ".\include\newpluginapi.h"\
+ ".\include\win2k.h"\
+ ".\m_help.h"\
+ ".\version.h"\
+
+
+.\options.c : \
+ ".\help.h"\
+ ".\include\m_database.h"\
+ ".\include\m_flags.h"\
+ ".\include\m_langpack.h"\
+ ".\include\m_options.h"\
+ ".\include\m_plugins.h"\
+ ".\include\m_system.h"\
+ ".\include\m_utils.h"\
+ ".\include\newpluginapi.h"\
+ ".\include\win2k.h"\
+ ".\m_help.h"\
+
+
+.\streaminout.c : \
+ ".\help.h"\
+ ".\include\m_plugins.h"\
+ ".\include\m_system.h"\
+ ".\include\newpluginapi.h"\
+ ".\include\win2k.h"\
+
+
+.\unzip.c : \
+ ".\include\m_plugins.h"\
+ ".\include\m_system.h"\
+ ".\include\newpluginapi.h"\
+ ".\unzip.h"\
+
+
+.\update.c : \
+ ".\help.h"\
+ ".\include\m_clist.h"\
+ ".\include\m_database.h"\
+ ".\include\m_icolib.h"\
+ ".\include\m_langpack.h"\
+ ".\include\m_netlib.h"\
+ ".\include\m_plugins.h"\
+ ".\include\m_skin.h"\
+ ".\include\m_system.h"\
+ ".\include\m_utils.h"\
+ ".\include\newpluginapi.h"\
+ ".\include\statusmodes.h"\
+ ".\include\win2k.h"\
+ ".\m_help.h"\
+ ".\unzip.h"\
+ ".\version.h"\
+
+
+.\utils.c : \
+ ".\help.h"\
+ ".\include\m_button.h"\
+ ".\include\m_clc.h"\
+ ".\include\m_netlib.h"\
+ ".\include\m_plugins.h"\
+ ".\include\m_system.h"\
+ ".\include\m_utils.h"\
+ ".\include\newpluginapi.h"\
+ ".\include\win2k.h"\
+
+
+.\resource.rc : \
+ ".\include\m_utils.h"\
+ ".\version.rc"\
+
diff --git a/Help/help.dsp b/Help/help.dsp
new file mode 100644
index 0000000..8fc325d
--- /dev/null
+++ b/Help/help.dsp
@@ -0,0 +1,335 @@
+# Microsoft Developer Studio Project File - Name="help" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** NICHT BEARBEITEN **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=help - Win32 Debug Unicode
+!MESSAGE Dies ist kein gültiges Makefile. Zum Erstellen dieses Projekts mit NMAKE
+!MESSAGE verwenden Sie den Befehl "Makefile exportieren" und führen Sie den Befehl
+!MESSAGE
+!MESSAGE NMAKE /f "help.mak".
+!MESSAGE
+!MESSAGE Sie können beim Ausführen von NMAKE eine Konfiguration angeben
+!MESSAGE durch Definieren des Makros CFG in der Befehlszeile. Zum Beispiel:
+!MESSAGE
+!MESSAGE NMAKE /f "help.mak" CFG="help - Win32 Debug Unicode"
+!MESSAGE
+!MESSAGE Für die Konfiguration stehen zur Auswahl:
+!MESSAGE
+!MESSAGE "help - Win32 Release" (basierend auf "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "help - Win32 Debug" (basierend auf "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "help - Win32 Release Unicode" (basierend auf "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "help - Win32 Debug Unicode" (basierend auf "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""$/Miranda/miranda/plugins/help", YKIAAAAA"
+# PROP Scc_LocalPath "."
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "help - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "release/ANSI"
+# PROP BASE Intermediate_Dir "temp/Release/ANSI"
+# PROP BASE Target_Dir "release/ANSI"
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "temp/release/ANSI"
+# PROP Intermediate_Dir "temp/Release/ANSI"
+# PROP Ignore_Export_Lib 1
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "HELP_EXPORTS" /YX /FD /c
+# ADD CPP /nologo /MD /W4 /GX /O2 /I ".\include" /D "NDEBUG" /D "_MBCS" /D "WIN32" /D "_WINDOWS" /D "_USRDLL" /D "STRICT" /D "HELP_EXPORTS" /U "NO_STRICT" /FR /FD /opt:nowin98 /c
+# SUBTRACT CPP /YX
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /win32
+# SUBTRACT MTL /mktyplib203 /Oicf
+# ADD BASE RSC /l 0x809 /i ".\include" /d "NDEBUG"
+# ADD RSC /l 0x809 /i ".\include" /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib comctl32.lib /nologo /dll /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib comctl32.lib shell32.lib /nologo /base:"0x20100000" /dll /pdb:".\release\ANSI\help.pdb" /map:".\release\ANSI\help.map" /debug /machine:I386 /nodefaultlib:"uuid.lib" /nodefaultlib:"OLDNAMES" /def:"help.def" /out:"./release/ANSI/help.dll" /mapinfo:lines /opt:nowin98 /ignore:4108 /release
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF "$(CFG)" == "help - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "temp/Debug/ANSI"
+# PROP BASE Intermediate_Dir "temp/Debug/ANSI"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "temp/Debug/ANSI"
+# PROP Intermediate_Dir "temp/Debug/ANSI"
+# PROP Ignore_Export_Lib 1
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "HELP_EXPORTS" /YX /FD /GZ /c
+# ADD CPP /nologo /MTd /W4 /Gm /Gi /GX /ZI /Od /I ".\include" /D "_DEBUG" /D "_MBCS" /D "WIN32" /D "_WINDOWS" /D "_USRDLL" /D "STRICT" /D "HELP_EXPORTS" /U "NO_STRICT" /FR /FD /GZ /c
+# SUBTRACT CPP /WX /YX
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x809 /i ".\include" /d "_DEBUG"
+# ADD RSC /l 0x809 /i ".\include" /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib comctl32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib comctl32.lib shell32.lib /nologo /base:"0x20100000" /dll /pdb:"D:\Miranda IM\ANSI\Plugins\help.pdb" /map /debug /machine:I386 /nodefaultlib:"uuid.lib" /nodefaultlib:"OLDNAMES" /def:"help.def" /out:"D:\Miranda IM\ANSI\Plugins\help.dll" /pdbtype:sept /mapinfo:lines
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF "$(CFG)" == "help - Win32 Release Unicode"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "release/Unicode"
+# PROP BASE Intermediate_Dir "temp/Release/Unicode"
+# PROP BASE Target_Dir "release/Unicode"
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "temp/Release/Unicode"
+# PROP Intermediate_Dir "temp/Release/Unicode"
+# PROP Ignore_Export_Lib 1
+# PROP Target_Dir "release/Unicode"
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "HELP_EXPORTS" /YX /FD /c
+# ADD CPP /nologo /MD /W4 /GX /O2 /I ".\include" /D "NDEBUG" /D "UNICODE" /D "_UNICODE" /D "WIN32" /D "_WINDOWS" /D "_USRDLL" /D "STRICT" /D "HELP_EXPORTS" /U "_MBCS" /U "NO_STRICT" /FR /FD /opt:nowin98 /c
+# SUBTRACT CPP /YX
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /win32
+# SUBTRACT MTL /mktyplib203 /Oicf
+# ADD BASE RSC /l 0x809 /i ".\include" /d "NDEBUG" /d "_UNICODE" /d "UNICODE"
+# ADD RSC /l 0x809 /i ".\include" /d "NDEBUG" /d "_UNICODE" /d "UNICODE"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib comctl32.lib /nologo /dll /machine:I386
+# SUBTRACT BASE LINK32 /pdb:none
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib comctl32.lib shell32.lib /nologo /base:"0x20100000" /dll /pdb:".\release\Unicode\help.pdb" /map:".\release\Unicode\help.map" /debug /machine:I386 /nodefaultlib:"uuid.lib" /nodefaultlib:"OLDNAMES" /def:"help.def" /out:".\release\Unicode\help.dll" /mapinfo:lines /opt:nowin98 /ignore:4078 /release
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF "$(CFG)" == "help - Win32 Debug Unicode"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "temp/Debug/Unicode"
+# PROP BASE Intermediate_Dir "temp/Debug/Unicode"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "temp/Debug/Unicode"
+# PROP Intermediate_Dir "temp/Debug/Unicode"
+# PROP Ignore_Export_Lib 1
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "HELP_EXPORTS" /YX /FD /GZ /c
+# ADD CPP /nologo /MTd /W4 /Gm /Gi /GX /ZI /Od /I ".\include" /D "_DEBUG" /D "UNICODE" /D "_UNICODE" /D "WIN32" /D "_WINDOWS" /D "_USRDLL" /D "STRICT" /D "HELP_EXPORTS" /U "_MBCS" /U "NO_STRICT" /FR /FD /GZ /c
+# SUBTRACT CPP /WX /YX
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# SUBTRACT MTL /Oicf
+# ADD BASE RSC /l 0x809 /i ".\include" /d "_DEBUG" /d "_UNICODE" /d "UNICODE"
+# ADD RSC /l 0x809 /i ".\include" /d "_DEBUG" /d "_UNICODE" /d "UNICODE"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib comctl32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib comctl32.lib shell32.lib /nologo /base:"0x20100000" /dll /pdb:"D:\Miranda IM\Unicode\Plugins\help.pdb" /map /debug /machine:I386 /nodefaultlib:"uuid.lib" /nodefaultlib:"OLDNAMES" /def:"help.def" /out:"D:\Miranda IM\Unicode\Plugins\help.dll" /pdbtype:sept /mapinfo:lines
+# SUBTRACT LINK32 /pdb:none
+
+!ENDIF
+
+# Begin Target
+
+# Name "help - Win32 Release"
+# Name "help - Win32 Debug"
+# Name "help - Win32 Release Unicode"
+# Name "help - Win32 Debug Unicode"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=.\datastore.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\dlgboxsubclass.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\helpdlg.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\helppack.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\main.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\options.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\streaminout.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\unzip.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\update.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\utils.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=.\help.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_help.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\unzip.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# Begin Source File
+
+SOURCE=.\resource.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\resource.rc
+# End Source File
+# Begin Source File
+
+SOURCE=.\version.h
+# End Source File
+# End Group
+# Begin Group "SDK"
+
+# PROP Default_Filter "h"
+# Begin Source File
+
+SOURCE=.\include\m_button.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\m_clc.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\m_clist.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\m_database.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\m_flags.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\m_icolib.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\m_langpack.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\m_netlib.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\m_options.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\m_plugins.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\m_skin.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\m_system.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\m_utils.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\newpluginapi.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\statusmodes.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\win2k.h
+# End Source File
+# End Group
+# Begin Group "Docs"
+
+# PROP Default_Filter "txt"
+# Begin Source File
+
+SOURCE=".\docs\Help-Developer.txt"
+# End Source File
+# Begin Source File
+
+SOURCE=".\docs\Help-License.txt"
+# End Source File
+# Begin Source File
+
+SOURCE=".\docs\Help-Readme.txt"
+# End Source File
+# Begin Source File
+
+SOURCE=".\docs\Help-Translation.txt"
+# End Source File
+# Begin Source File
+
+SOURCE=.\docs\helppack_english.txt
+# End Source File
+# Begin Source File
+
+SOURCE=.\docs\helppack_sample.txt
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_help.inc
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/Help/help.dsw b/Help/help.dsw
new file mode 100644
index 0000000..7c33b2a
--- /dev/null
+++ b/Help/help.dsw
@@ -0,0 +1,29 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "help"=".\help.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/Help/help.h b/Help/help.h
new file mode 100644
index 0000000..924a603
--- /dev/null
+++ b/Help/help.h
@@ -0,0 +1,142 @@
+/*
+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.
+*/
+
+// dlgboxsubclass.c
+int InstallDialogBoxHook(void);
+int RemoveDialogBoxHook(void);
+
+// utils.c
+#define CTLTYPE_UNKNOWN 0
+#define CTLTYPE_DIALOG 1
+#define CTLTYPE_BUTTON 2
+#define CTLTYPE_CHECKBOX 3
+#define CTLTYPE_RADIO 4
+#define CTLTYPE_TEXT 5
+#define CTLTYPE_IMAGE 6
+#define CTLTYPE_EDIT 7
+#define CTLTYPE_GROUP 8
+#define CTLTYPE_COMBO 9
+#define CTLTYPE_LIST 10
+#define CTLTYPE_SPINEDIT 11
+#define CTLTYPE_PROGRESS 12
+#define CTLTYPE_SLIDER 13
+#define CTLTYPE_LISTVIEW 14
+#define CTLTYPE_TREEVIEW 15
+#define CTLTYPE_DATETIME 16
+#define CTLTYPE_IP 17
+#define CTLTYPE_STATUSBAR 18
+#define CTLTYPE_HYPERLINK 19
+#define CTLTYPE_CLC 20
+#define CTLTYPE_SCROLL 21
+#define CTLTYPE_ANIMATION 22
+#define CTLTYPE_HOTKEY 23
+#define CTLTYPE_TABS 24
+#define CTLTYPE_COLOUR 25
+#define CTLTYPE_TOOLBAR 26
+#define CTLTYPE_SIZEGRIP 27
+extern const TCHAR *szControlTypeNames[];
+int GetControlType(HWND hwndCtl);
+HWND GetControlDialog(HWND hwndCtl);
+int GetControlTitle(HWND hwndCtl,TCHAR *pszTitle,int cchTitle);
+char *GetControlModuleName(HWND hwndCtl);
+int GetControlID(HWND hwndCtl);
+char *CreateDialogIdString(HWND hwndDlg);
+struct ResizableCharBuffer {
+ char *sz;
+ int iEnd,cbAlloced;
+};
+void AppendCharToCharBuffer(struct ResizableCharBuffer *rcb,char c);
+void AppendToCharBuffer(struct ResizableCharBuffer *rcb,const char *fmt,...);
+
+// helpdlg.c
+#define M_CHANGEHELPCONTROL (WM_APP+0x100)
+#define M_HELPLOADED (WM_APP+0x101)
+#ifdef EDITOR
+#define M_SAVECOMPLETE (WM_APP+0x102)
+#endif
+#define M_LOADHELP (WM_APP+0x103)
+#define M_HELPLOADFAILED (WM_APP+0x104)
+#define M_CLIPBOARDCOPY (WM_APP+0x105)
+BOOL CALLBACK HelpDlgProc(HWND hwndDlg,UINT msg,WPARAM wParam,LPARAM lParam);
+BOOL CALLBACK ShadowDlgProc(HWND hwndDlg,UINT msg,WPARAM wParam,LPARAM lParam);
+
+// streaminout.c
+void StreamInHtml(HWND hwndEdit,const char *szHtml,UINT codepage,COLORREF clrBkgrnd);
+#ifdef EDITOR
+char *StreamOutHtml(HWND hwndEdit);
+#endif
+#define TEXTSIZE_BIG 18 // in half points
+#define TEXTSIZE_NORMAL 16
+#define TEXTSIZE_SMALL 13
+#ifndef EDITOR
+void FreeHyperlinkData(void);
+int IsHyperlink(LONG cpPos,LONG *pcpMin,LONG *pcpMax,char **ppszLink);
+#endif
+
+// datastore.c
+void InitDialogCache(void);
+void FreeDialogCache(void);
+#define GCHF_DONTLOAD 1
+int GetControlHelp(HWND hwndCtl,const char *pszDlgId,const char *pszModule,int ctrlId,TCHAR **ppszTitle,char **ppszText,int *pType,LCID *pLocaleID,UINT *pCodePage,BOOL *pIsRTL,DWORD flags);
+#ifdef EDITOR
+void SetControlHelp(const char *pszDlgId,const char *pszModule,int ctrlId,TCHAR *pszTitle,char *pszText,int type);
+void SaveDialogCache(void);
+#else
+char *CreateControlIdentifier(const char *pszDlgId,const char *pszModule,int ctrlId,HWND hwndCtl);
+#endif
+void RegisterFileChange(void);
+void CloseFileChange(void);
+
+// options.c
+void ReloadLangOptList(void);
+void InitOptions(void);
+void UninitOptions(void);
+
+// helppack.c
+void TrimStringSimple(char *str);
+void TrimString(char *str);
+BOOL IsEmpty(const char *str);
+typedef struct {
+ TCHAR szLanguage[64];
+ LCID Locale;
+ WORD codepage;
+ char szAuthors[1024];
+ char szAuthorEmail[128];
+ char szLastModifiedUsing[64];
+ char szPluginsIncluded[4080];
+ char szVersion[21];
+ char szFLName[128];
+ FILETIME ftFileDate;
+ TCHAR szFileName[MAX_PATH]; /* just the file name itself */
+ BYTE flags; /* see HPIF_* flags */
+} HELPPACK_INFO;
+#define HPF_ENABLED 0x01 // pack is enabled
+#define HPF_NOLOCALE 0x02 // pack has no valid locale
+#define HPF_DEFAULT 0x04 // pack is english default
+BOOL GetPackPath(TCHAR *pszPath,int nSize,BOOL fEnabledPacks,const TCHAR *pszFile);
+typedef BOOL (CALLBACK *ENUM_PACKS_CALLBACK)(HELPPACK_INFO *pack,WPARAM wParam,LPARAM lParam);
+BOOL EnumPacks(ENUM_PACKS_CALLBACK callback,const TCHAR *pszFilePattern,const char *pszFileVersionHeader,WPARAM wParam,LPARAM lParam);
+BOOL IsPluginIncluded(const HELPPACK_INFO *pack,char *pszFileBaseName);
+BOOL EnablePack(const HELPPACK_INFO *pack,const TCHAR *pszFilePattern);
+void CorrectPacks(const TCHAR *pszFilePattern,const TCHAR *pszDefaultFile,BOOL fDisableAll);
+
+/* update.c */
+int ServiceShowLangDialog(WPARAM wParam,LPARAM lPARAM);
+void InitUpdate(void);
+void UninitUpdate(void);
diff --git a/Help/help.mak b/Help/help.mak
new file mode 100644
index 0000000..60dd115
--- /dev/null
+++ b/Help/help.mak
@@ -0,0 +1,581 @@
+# Microsoft Developer Studio Generated NMAKE File, Based on help.dsp
+!IF "$(CFG)" == ""
+CFG=help - Win32 Debug Unicode
+!MESSAGE Keine Konfiguration angegeben. help - Win32 Debug Unicode wird als Standard verwendet.
+!ENDIF
+
+!IF "$(CFG)" != "help - Win32 Release" && "$(CFG)" != "help - Win32 Debug" && "$(CFG)" != "help - Win32 Release Unicode" && "$(CFG)" != "help - Win32 Debug Unicode"
+!MESSAGE Ungltige Konfiguration "$(CFG)" angegeben.
+!MESSAGE Sie k”nnen beim Ausfhren von NMAKE eine Konfiguration angeben
+!MESSAGE durch Definieren des Makros CFG in der Befehlszeile. Zum Beispiel:
+!MESSAGE
+!MESSAGE NMAKE /f "help.mak" CFG="help - Win32 Debug Unicode"
+!MESSAGE
+!MESSAGE Fr die Konfiguration stehen zur Auswahl:
+!MESSAGE
+!MESSAGE "help - Win32 Release" (basierend auf "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "help - Win32 Debug" (basierend auf "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "help - Win32 Release Unicode" (basierend auf "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "help - Win32 Debug Unicode" (basierend auf "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+!ERROR Eine ungltige Konfiguration wurde angegeben.
+!ENDIF
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE
+NULL=nul
+!ENDIF
+
+!IF "$(CFG)" == "help - Win32 Release"
+
+OUTDIR=.\temp/release/ANSI
+INTDIR=.\temp/Release/ANSI
+# Begin Custom Macros
+OutDir=.\temp/release/ANSI
+# End Custom Macros
+
+ALL : ".\release\ANSI\help.dll" "$(OUTDIR)\help.bsc"
+
+
+CLEAN :
+ -@erase "$(INTDIR)\datastore.obj"
+ -@erase "$(INTDIR)\datastore.sbr"
+ -@erase "$(INTDIR)\dlgboxsubclass.obj"
+ -@erase "$(INTDIR)\dlgboxsubclass.sbr"
+ -@erase "$(INTDIR)\helpdlg.obj"
+ -@erase "$(INTDIR)\helpdlg.sbr"
+ -@erase "$(INTDIR)\helppack.obj"
+ -@erase "$(INTDIR)\helppack.sbr"
+ -@erase "$(INTDIR)\main.obj"
+ -@erase "$(INTDIR)\main.sbr"
+ -@erase "$(INTDIR)\options.obj"
+ -@erase "$(INTDIR)\options.sbr"
+ -@erase "$(INTDIR)\resource.res"
+ -@erase "$(INTDIR)\streaminout.obj"
+ -@erase "$(INTDIR)\streaminout.sbr"
+ -@erase "$(INTDIR)\unzip.obj"
+ -@erase "$(INTDIR)\unzip.sbr"
+ -@erase "$(INTDIR)\update.obj"
+ -@erase "$(INTDIR)\update.sbr"
+ -@erase "$(INTDIR)\utils.obj"
+ -@erase "$(INTDIR)\utils.sbr"
+ -@erase "$(INTDIR)\vc60.idb"
+ -@erase "$(OUTDIR)\help.bsc"
+ -@erase "$(OUTDIR)\help.exp"
+ -@erase ".\release\ANSI\help.dll"
+ -@erase ".\release\ANSI\help.map"
+ -@erase ".\release\ANSI\help.pdb"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MD /W4 /GX /O2 /I ".\include" /D "NDEBUG" /D "_MBCS" /D "WIN32" /D "_WINDOWS" /D "_USRDLL" /D "STRICT" /D "HELP_EXPORTS" /U "NO_STRICT" /FR"$(INTDIR)\\" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /opt:nowin98 /c
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+MTL=midl.exe
+MTL_PROJ=/nologo /D "NDEBUG" /win32
+RSC=rc.exe
+RSC_PROJ=/l 0x809 /fo"$(INTDIR)\resource.res" /i ".\include" /d "NDEBUG"
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\help.bsc"
+BSC32_SBRS= \
+ "$(INTDIR)\datastore.sbr" \
+ "$(INTDIR)\dlgboxsubclass.sbr" \
+ "$(INTDIR)\helpdlg.sbr" \
+ "$(INTDIR)\helppack.sbr" \
+ "$(INTDIR)\main.sbr" \
+ "$(INTDIR)\options.sbr" \
+ "$(INTDIR)\streaminout.sbr" \
+ "$(INTDIR)\unzip.sbr" \
+ "$(INTDIR)\update.sbr" \
+ "$(INTDIR)\utils.sbr"
+
+"$(OUTDIR)\help.bsc" : "$(OUTDIR)" $(BSC32_SBRS)
+ $(BSC32) @<<
+ $(BSC32_FLAGS) $(BSC32_SBRS)
+<<
+
+LINK32=link.exe
+LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib comctl32.lib shell32.lib /nologo /base:"0x20100000" /dll /incremental:no /pdb:".\release\ANSI\help.pdb" /map:".\release\ANSI\help.map" /debug /machine:I386 /nodefaultlib:"uuid.lib" /nodefaultlib:"OLDNAMES" /def:"help.def" /out:"./release/ANSI/help.dll" /implib:"$(OUTDIR)\help.lib" /mapinfo:lines /opt:nowin98 /ignore:4108 /release
+LINK32_OBJS= \
+ "$(INTDIR)\datastore.obj" \
+ "$(INTDIR)\dlgboxsubclass.obj" \
+ "$(INTDIR)\helpdlg.obj" \
+ "$(INTDIR)\helppack.obj" \
+ "$(INTDIR)\main.obj" \
+ "$(INTDIR)\options.obj" \
+ "$(INTDIR)\streaminout.obj" \
+ "$(INTDIR)\unzip.obj" \
+ "$(INTDIR)\update.obj" \
+ "$(INTDIR)\utils.obj" \
+ "$(INTDIR)\resource.res"
+
+".\release\ANSI\help.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ELSEIF "$(CFG)" == "help - Win32 Debug"
+
+OUTDIR=.\temp/Debug/ANSI
+INTDIR=.\temp/Debug/ANSI
+# Begin Custom Macros
+OutDir=.\temp/Debug/ANSI
+# End Custom Macros
+
+ALL : "..\Miranda IM\ANSI\Plugins\help.dll" "$(OUTDIR)\help.bsc"
+
+
+CLEAN :
+ -@erase "$(INTDIR)\datastore.obj"
+ -@erase "$(INTDIR)\datastore.sbr"
+ -@erase "$(INTDIR)\dlgboxsubclass.obj"
+ -@erase "$(INTDIR)\dlgboxsubclass.sbr"
+ -@erase "$(INTDIR)\helpdlg.obj"
+ -@erase "$(INTDIR)\helpdlg.sbr"
+ -@erase "$(INTDIR)\helppack.obj"
+ -@erase "$(INTDIR)\helppack.sbr"
+ -@erase "$(INTDIR)\main.obj"
+ -@erase "$(INTDIR)\main.sbr"
+ -@erase "$(INTDIR)\options.obj"
+ -@erase "$(INTDIR)\options.sbr"
+ -@erase "$(INTDIR)\resource.res"
+ -@erase "$(INTDIR)\streaminout.obj"
+ -@erase "$(INTDIR)\streaminout.sbr"
+ -@erase "$(INTDIR)\unzip.obj"
+ -@erase "$(INTDIR)\unzip.sbr"
+ -@erase "$(INTDIR)\update.obj"
+ -@erase "$(INTDIR)\update.sbr"
+ -@erase "$(INTDIR)\utils.obj"
+ -@erase "$(INTDIR)\utils.sbr"
+ -@erase "$(INTDIR)\vc60.idb"
+ -@erase "$(INTDIR)\vc60.pdb"
+ -@erase "$(OUTDIR)\help.bsc"
+ -@erase "$(OUTDIR)\help.exp"
+ -@erase "$(OUTDIR)\help.map"
+ -@erase "..\Miranda IM\ANSI\Plugins\help.dll"
+ -@erase "..\Miranda IM\ANSI\Plugins\help.ilk"
+ -@erase "..\Miranda IM\ANSI\Plugins\help.pdb"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MTd /W4 /Gm /Gi /GX /ZI /Od /I ".\include" /D "_DEBUG" /D "_MBCS" /D "WIN32" /D "_WINDOWS" /D "_USRDLL" /D "STRICT" /D "HELP_EXPORTS" /U "NO_STRICT" /FR"$(INTDIR)\\" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /GZ /c
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+MTL=midl.exe
+MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32
+RSC=rc.exe
+RSC_PROJ=/l 0x809 /fo"$(INTDIR)\resource.res" /i ".\include" /d "_DEBUG"
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\help.bsc"
+BSC32_SBRS= \
+ "$(INTDIR)\datastore.sbr" \
+ "$(INTDIR)\dlgboxsubclass.sbr" \
+ "$(INTDIR)\helpdlg.sbr" \
+ "$(INTDIR)\helppack.sbr" \
+ "$(INTDIR)\main.sbr" \
+ "$(INTDIR)\options.sbr" \
+ "$(INTDIR)\streaminout.sbr" \
+ "$(INTDIR)\unzip.sbr" \
+ "$(INTDIR)\update.sbr" \
+ "$(INTDIR)\utils.sbr"
+
+"$(OUTDIR)\help.bsc" : "$(OUTDIR)" $(BSC32_SBRS)
+ $(BSC32) @<<
+ $(BSC32_FLAGS) $(BSC32_SBRS)
+<<
+
+LINK32=link.exe
+LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib comctl32.lib shell32.lib /nologo /base:"0x20100000" /dll /incremental:yes /pdb:"D:\Miranda IM\ANSI\Plugins\help.pdb" /map:"$(INTDIR)\help.map" /debug /machine:I386 /nodefaultlib:"uuid.lib" /nodefaultlib:"OLDNAMES" /def:"help.def" /out:"D:\Miranda IM\ANSI\Plugins\help.dll" /implib:"$(OUTDIR)\help.lib" /pdbtype:sept /mapinfo:lines
+LINK32_OBJS= \
+ "$(INTDIR)\datastore.obj" \
+ "$(INTDIR)\dlgboxsubclass.obj" \
+ "$(INTDIR)\helpdlg.obj" \
+ "$(INTDIR)\helppack.obj" \
+ "$(INTDIR)\main.obj" \
+ "$(INTDIR)\options.obj" \
+ "$(INTDIR)\streaminout.obj" \
+ "$(INTDIR)\unzip.obj" \
+ "$(INTDIR)\update.obj" \
+ "$(INTDIR)\utils.obj" \
+ "$(INTDIR)\resource.res"
+
+"..\Miranda IM\ANSI\Plugins\help.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ELSEIF "$(CFG)" == "help - Win32 Release Unicode"
+
+OUTDIR=.\temp/Release/Unicode
+INTDIR=.\temp/Release/Unicode
+# Begin Custom Macros
+OutDir=.\temp/Release/Unicode
+# End Custom Macros
+
+ALL : ".\release\Unicode\help.dll" "$(OUTDIR)\help.bsc"
+
+
+CLEAN :
+ -@erase "$(INTDIR)\datastore.obj"
+ -@erase "$(INTDIR)\datastore.sbr"
+ -@erase "$(INTDIR)\dlgboxsubclass.obj"
+ -@erase "$(INTDIR)\dlgboxsubclass.sbr"
+ -@erase "$(INTDIR)\helpdlg.obj"
+ -@erase "$(INTDIR)\helpdlg.sbr"
+ -@erase "$(INTDIR)\helppack.obj"
+ -@erase "$(INTDIR)\helppack.sbr"
+ -@erase "$(INTDIR)\main.obj"
+ -@erase "$(INTDIR)\main.sbr"
+ -@erase "$(INTDIR)\options.obj"
+ -@erase "$(INTDIR)\options.sbr"
+ -@erase "$(INTDIR)\resource.res"
+ -@erase "$(INTDIR)\streaminout.obj"
+ -@erase "$(INTDIR)\streaminout.sbr"
+ -@erase "$(INTDIR)\unzip.obj"
+ -@erase "$(INTDIR)\unzip.sbr"
+ -@erase "$(INTDIR)\update.obj"
+ -@erase "$(INTDIR)\update.sbr"
+ -@erase "$(INTDIR)\utils.obj"
+ -@erase "$(INTDIR)\utils.sbr"
+ -@erase "$(INTDIR)\vc60.idb"
+ -@erase "$(OUTDIR)\help.bsc"
+ -@erase "$(OUTDIR)\help.exp"
+ -@erase ".\release\Unicode\help.dll"
+ -@erase ".\release\Unicode\help.map"
+ -@erase ".\release\Unicode\help.pdb"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MD /W4 /GX /O2 /I ".\include" /D "NDEBUG" /D "UNICODE" /D "_UNICODE" /D "WIN32" /D "_WINDOWS" /D "_USRDLL" /D "STRICT" /D "HELP_EXPORTS" /U "_MBCS" /U "NO_STRICT" /FR"$(INTDIR)\\" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /opt:nowin98 /c
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+MTL=midl.exe
+MTL_PROJ=/nologo /D "NDEBUG" /win32
+RSC=rc.exe
+RSC_PROJ=/l 0x809 /fo"$(INTDIR)\resource.res" /i ".\include" /d "NDEBUG" /d "_UNICODE" /d "UNICODE"
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\help.bsc"
+BSC32_SBRS= \
+ "$(INTDIR)\datastore.sbr" \
+ "$(INTDIR)\dlgboxsubclass.sbr" \
+ "$(INTDIR)\helpdlg.sbr" \
+ "$(INTDIR)\helppack.sbr" \
+ "$(INTDIR)\main.sbr" \
+ "$(INTDIR)\options.sbr" \
+ "$(INTDIR)\streaminout.sbr" \
+ "$(INTDIR)\unzip.sbr" \
+ "$(INTDIR)\update.sbr" \
+ "$(INTDIR)\utils.sbr"
+
+"$(OUTDIR)\help.bsc" : "$(OUTDIR)" $(BSC32_SBRS)
+ $(BSC32) @<<
+ $(BSC32_FLAGS) $(BSC32_SBRS)
+<<
+
+LINK32=link.exe
+LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib comctl32.lib shell32.lib /nologo /base:"0x20100000" /dll /incremental:no /pdb:".\release\Unicode\help.pdb" /map:".\release\Unicode\help.map" /debug /machine:I386 /nodefaultlib:"uuid.lib" /nodefaultlib:"OLDNAMES" /def:"help.def" /out:".\release\Unicode\help.dll" /implib:"$(OUTDIR)\help.lib" /mapinfo:lines /opt:nowin98 /ignore:4078 /release
+LINK32_OBJS= \
+ "$(INTDIR)\datastore.obj" \
+ "$(INTDIR)\dlgboxsubclass.obj" \
+ "$(INTDIR)\helpdlg.obj" \
+ "$(INTDIR)\helppack.obj" \
+ "$(INTDIR)\main.obj" \
+ "$(INTDIR)\options.obj" \
+ "$(INTDIR)\streaminout.obj" \
+ "$(INTDIR)\unzip.obj" \
+ "$(INTDIR)\update.obj" \
+ "$(INTDIR)\utils.obj" \
+ "$(INTDIR)\resource.res"
+
+".\release\Unicode\help.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ELSEIF "$(CFG)" == "help - Win32 Debug Unicode"
+
+OUTDIR=.\temp/Debug/Unicode
+INTDIR=.\temp/Debug/Unicode
+# Begin Custom Macros
+OutDir=.\temp/Debug/Unicode
+# End Custom Macros
+
+ALL : "..\Miranda IM\Unicode\Plugins\help.dll" "$(OUTDIR)\help.bsc"
+
+
+CLEAN :
+ -@erase "$(INTDIR)\datastore.obj"
+ -@erase "$(INTDIR)\datastore.sbr"
+ -@erase "$(INTDIR)\dlgboxsubclass.obj"
+ -@erase "$(INTDIR)\dlgboxsubclass.sbr"
+ -@erase "$(INTDIR)\helpdlg.obj"
+ -@erase "$(INTDIR)\helpdlg.sbr"
+ -@erase "$(INTDIR)\helppack.obj"
+ -@erase "$(INTDIR)\helppack.sbr"
+ -@erase "$(INTDIR)\main.obj"
+ -@erase "$(INTDIR)\main.sbr"
+ -@erase "$(INTDIR)\options.obj"
+ -@erase "$(INTDIR)\options.sbr"
+ -@erase "$(INTDIR)\resource.res"
+ -@erase "$(INTDIR)\streaminout.obj"
+ -@erase "$(INTDIR)\streaminout.sbr"
+ -@erase "$(INTDIR)\unzip.obj"
+ -@erase "$(INTDIR)\unzip.sbr"
+ -@erase "$(INTDIR)\update.obj"
+ -@erase "$(INTDIR)\update.sbr"
+ -@erase "$(INTDIR)\utils.obj"
+ -@erase "$(INTDIR)\utils.sbr"
+ -@erase "$(INTDIR)\vc60.idb"
+ -@erase "$(INTDIR)\vc60.pdb"
+ -@erase "$(OUTDIR)\help.bsc"
+ -@erase "$(OUTDIR)\help.exp"
+ -@erase "$(OUTDIR)\help.map"
+ -@erase "..\Miranda IM\Unicode\Plugins\help.dll"
+ -@erase "..\Miranda IM\Unicode\Plugins\help.ilk"
+ -@erase "..\Miranda IM\Unicode\Plugins\help.pdb"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MTd /W4 /Gm /Gi /GX /ZI /Od /I ".\include" /D "_DEBUG" /D "UNICODE" /D "_UNICODE" /D "WIN32" /D "_WINDOWS" /D "_USRDLL" /D "STRICT" /D "HELP_EXPORTS" /U "_MBCS" /U "NO_STRICT" /FR"$(INTDIR)\\" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /GZ /c
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+MTL=midl.exe
+MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32
+RSC=rc.exe
+RSC_PROJ=/l 0x809 /fo"$(INTDIR)\resource.res" /i ".\include" /d "_DEBUG" /d "_UNICODE" /d "UNICODE"
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\help.bsc"
+BSC32_SBRS= \
+ "$(INTDIR)\datastore.sbr" \
+ "$(INTDIR)\dlgboxsubclass.sbr" \
+ "$(INTDIR)\helpdlg.sbr" \
+ "$(INTDIR)\helppack.sbr" \
+ "$(INTDIR)\main.sbr" \
+ "$(INTDIR)\options.sbr" \
+ "$(INTDIR)\streaminout.sbr" \
+ "$(INTDIR)\unzip.sbr" \
+ "$(INTDIR)\update.sbr" \
+ "$(INTDIR)\utils.sbr"
+
+"$(OUTDIR)\help.bsc" : "$(OUTDIR)" $(BSC32_SBRS)
+ $(BSC32) @<<
+ $(BSC32_FLAGS) $(BSC32_SBRS)
+<<
+
+LINK32=link.exe
+LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib comctl32.lib shell32.lib /nologo /base:"0x20100000" /dll /incremental:yes /pdb:"D:\Miranda IM\Unicode\Plugins\help.pdb" /map:"$(INTDIR)\help.map" /debug /machine:I386 /nodefaultlib:"uuid.lib" /nodefaultlib:"OLDNAMES" /def:"help.def" /out:"D:\Miranda IM\Unicode\Plugins\help.dll" /implib:"$(OUTDIR)\help.lib" /pdbtype:sept /mapinfo:lines
+LINK32_OBJS= \
+ "$(INTDIR)\datastore.obj" \
+ "$(INTDIR)\dlgboxsubclass.obj" \
+ "$(INTDIR)\helpdlg.obj" \
+ "$(INTDIR)\helppack.obj" \
+ "$(INTDIR)\main.obj" \
+ "$(INTDIR)\options.obj" \
+ "$(INTDIR)\streaminout.obj" \
+ "$(INTDIR)\unzip.obj" \
+ "$(INTDIR)\update.obj" \
+ "$(INTDIR)\utils.obj" \
+ "$(INTDIR)\resource.res"
+
+"..\Miranda IM\Unicode\Plugins\help.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ENDIF
+
+
+!IF "$(NO_EXTERNAL_DEPS)" != "1"
+!IF EXISTS("help.dep")
+!INCLUDE "help.dep"
+!ELSE
+!MESSAGE Warning: cannot find "help.dep"
+!ENDIF
+!ENDIF
+
+
+!IF "$(CFG)" == "help - Win32 Release" || "$(CFG)" == "help - Win32 Debug" || "$(CFG)" == "help - Win32 Release Unicode" || "$(CFG)" == "help - Win32 Debug Unicode"
+SOURCE=.\datastore.c
+
+"$(INTDIR)\datastore.obj" "$(INTDIR)\datastore.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\dlgboxsubclass.c
+
+"$(INTDIR)\dlgboxsubclass.obj" "$(INTDIR)\dlgboxsubclass.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\helpdlg.c
+
+"$(INTDIR)\helpdlg.obj" "$(INTDIR)\helpdlg.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\helppack.c
+
+"$(INTDIR)\helppack.obj" "$(INTDIR)\helppack.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\main.c
+
+"$(INTDIR)\main.obj" "$(INTDIR)\main.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\options.c
+
+"$(INTDIR)\options.obj" "$(INTDIR)\options.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\streaminout.c
+
+"$(INTDIR)\streaminout.obj" "$(INTDIR)\streaminout.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\unzip.c
+
+"$(INTDIR)\unzip.obj" "$(INTDIR)\unzip.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\update.c
+
+"$(INTDIR)\update.obj" "$(INTDIR)\update.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\utils.c
+
+"$(INTDIR)\utils.obj" "$(INTDIR)\utils.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\resource.rc
+
+"$(INTDIR)\resource.res" : $(SOURCE) "$(INTDIR)"
+ $(RSC) $(RSC_PROJ) $(SOURCE)
+
+
+
+!ENDIF
+
diff --git a/Help/help.vcproj b/Help/help.vcproj
new file mode 100644
index 0000000..1f63315
--- /dev/null
+++ b/Help/help.vcproj
@@ -0,0 +1,498 @@
+<?xml version="1.0" encoding="windows-1251"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.10"
+ Name="help"
+ SccProjectName="&quot;$/Miranda/miranda/plugins/help&quot;, YKIAAAAA"
+ SccAuxPath=""
+ SccLocalPath="."
+ SccProvider="MSSCCI:Microsoft Visual SourceSafe">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)/Plugins"
+ IntermediateDirectory="$(SolutionDir)$(ConfigurationName)/Obj/$(ProjectName)"
+ ConfigurationType="2"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="3"
+ GlobalOptimizations="TRUE"
+ InlineFunctionExpansion="1"
+ FavorSizeOrSpeed="2"
+ AdditionalIncludeDirectories="../../include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;HELP_EXPORTS"
+ StringPooling="TRUE"
+ ExceptionHandling="FALSE"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="TRUE"
+ UsePrecompiledHeader="3"
+ PrecompiledHeaderThrough="help.h"
+ AssemblerOutput="3"
+ BrowseInformationFile="$(IntDir)/"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"
+ DebugInformationFormat="3"
+ CompileAs="0"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ IgnoreImportLibrary="TRUE"
+ AdditionalOptions="/ALIGN:4096 /ignore:4108"
+ AdditionalDependencies="odbc32.lib odbccp32.lib wsock32.lib"
+ LinkIncremental="1"
+ SuppressStartupBanner="TRUE"
+ GenerateDebugInformation="TRUE"
+ GenerateMapFile="TRUE"
+ MapFileName="$(OutDir)/$(ProjectName).map"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ OptimizeForWindows98="1"
+ BaseAddress="0x20100000"
+ ImportLibrary="$(IntDir)/$(TargetName).lib"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="NDEBUG"
+ MkTypLibCompatible="TRUE"
+ SuppressStartupBanner="TRUE"
+ TargetEnvironment="1"
+ TypeLibraryName=".\Release/help.tlb"
+ HeaderFileName=""/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="2057"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)/Plugins"
+ IntermediateDirectory="$(SolutionDir)$(ConfigurationName)/Obj/$(ProjectName)"
+ ConfigurationType="2"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../../include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;HELP_EXPORTS"
+ ExceptionHandling="FALSE"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="3"
+ PrecompiledHeaderThrough="help.h"
+ BrowseInformationFile="$(IntDir)/"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"
+ DebugInformationFormat="4"
+ CompileAs="0"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ IgnoreImportLibrary="TRUE"
+ AdditionalDependencies="odbc32.lib odbccp32.lib wsock32.lib"
+ LinkIncremental="2"
+ SuppressStartupBanner="TRUE"
+ GenerateDebugInformation="TRUE"
+ ImportLibrary="$(IntDir)/$(TargetName).lib"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="_DEBUG"
+ MkTypLibCompatible="TRUE"
+ SuppressStartupBanner="TRUE"
+ TargetEnvironment="1"
+ TypeLibraryName=".\Debug/help.tlb"
+ HeaderFileName=""/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="2057"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Debug Unicode|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)/Plugins"
+ IntermediateDirectory="$(SolutionDir)$(ConfigurationName)/Obj/$(ProjectName)"
+ ConfigurationType="2"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ CharacterSet="1">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../../include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;HELP_EXPORTS"
+ ExceptionHandling="FALSE"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ BufferSecurityCheck="TRUE"
+ UsePrecompiledHeader="3"
+ PrecompiledHeaderThrough="help.h"
+ BrowseInformationFile="$(IntDir)/"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"
+ DebugInformationFormat="4"
+ CompileAs="0"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ IgnoreImportLibrary="TRUE"
+ AdditionalDependencies="odbc32.lib odbccp32.lib wsock32.lib"
+ LinkIncremental="2"
+ SuppressStartupBanner="TRUE"
+ GenerateDebugInformation="TRUE"
+ ImportLibrary="$(IntDir)/$(TargetName).lib"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="_DEBUG"
+ MkTypLibCompatible="TRUE"
+ SuppressStartupBanner="TRUE"
+ TargetEnvironment="1"
+ TypeLibraryName=".\Debug/help.tlb"
+ HeaderFileName=""/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="2057"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Release Unicode|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)/Plugins"
+ IntermediateDirectory="$(SolutionDir)$(ConfigurationName)/Obj/$(ProjectName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ WholeProgramOptimization="FALSE">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="3"
+ GlobalOptimizations="TRUE"
+ InlineFunctionExpansion="1"
+ FavorSizeOrSpeed="2"
+ AdditionalIncludeDirectories="../../include"
+ StringPooling="TRUE"
+ ExceptionHandling="FALSE"
+ RuntimeLibrary="2"
+ BufferSecurityCheck="TRUE"
+ UsePrecompiledHeader="3"
+ PrecompiledHeaderThrough="help.h"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ IgnoreImportLibrary="TRUE"
+ GenerateDebugInformation="TRUE"
+ GenerateMapFile="TRUE"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ OptimizeForWindows98="1"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat">
+ <File
+ RelativePath="datastore.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;HELP_EXPORTS;$(NoInherit)"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;HELP_EXPORTS;$(NoInherit)"
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="dlgboxsubclass.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;HELP_EXPORTS;$(NoInherit)"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;HELP_EXPORTS;$(NoInherit)"
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="helpdlg.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;HELP_EXPORTS;$(NoInherit)"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;HELP_EXPORTS;$(NoInherit)"
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="main.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;HELP_EXPORTS;$(NoInherit)"
+ UsePrecompiledHeader="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;HELP_EXPORTS;$(NoInherit)"
+ BasicRuntimeChecks="3"
+ UsePrecompiledHeader="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ BasicRuntimeChecks="3"
+ UsePrecompiledHeader="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="options.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;HELP_EXPORTS;$(NoInherit)"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;HELP_EXPORTS;$(NoInherit)"
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="streaminout.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;HELP_EXPORTS;$(NoInherit)"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;HELP_EXPORTS;$(NoInherit)"
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="utils.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;HELP_EXPORTS;$(NoInherit)"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;HELP_EXPORTS;$(NoInherit)"
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl">
+ <File
+ RelativePath="help.h">
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe">
+ <File
+ RelativePath="resource.rc">
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/Help/help_8.vcproj b/Help/help_8.vcproj
new file mode 100644
index 0000000..5482437
--- /dev/null
+++ b/Help/help_8.vcproj
@@ -0,0 +1,1038 @@
+<?xml version="1.0" encoding="windows-1251"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8,00"
+ Name="help"
+ ProjectGUID="{4AD5A72D-C667-4902-844D-C09F74CE7245}"
+ RootNamespace="help"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Editor Release|Win32"
+ OutputDirectory=".\help___Win32_Editor_Release"
+ IntermediateDirectory=".\help___Win32_Editor_Release"
+ ConfigurationType="2"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="NDEBUG"
+ MkTypLibCompatible="true"
+ SuppressStartupBanner="true"
+ TargetEnvironment="1"
+ TypeLibraryName=".\help___Win32_Editor_Release/help.tlb"
+ HeaderFileName=""
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ InlineFunctionExpansion="1"
+ AdditionalIncludeDirectories="../../include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;HELP_EXPORTS;EDITOR"
+ StringPooling="true"
+ ExceptionHandling="0"
+ RuntimeLibrary="0"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderThrough="help.h"
+ AssemblerListingLocation=".\help___Win32_Editor_Release/"
+ ObjectFile=".\help___Win32_Editor_Release/"
+ ProgramDataBaseFileName=".\help___Win32_Editor_Release/"
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ CompileAs="0"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="2057"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ IgnoreImportLibrary="true"
+ AdditionalDependencies="odbc32.lib odbccp32.lib wsock32.lib"
+ OutputFile="../../bin/release/plugins/help.dll"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ ProgramDatabaseFile=".\help___Win32_Editor_Release/help.pdb"
+ GenerateMapFile="true"
+ MapFileName=".\help___Win32_Editor_Release/help.map"
+ BaseAddress="0x20100000"
+ ImportLibrary=".\help___Win32_Editor_Release/help.lib"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)/Release/Plugins"
+ IntermediateDirectory="$(SolutionDir)/Release/Obj/$(ProjectName)"
+ ConfigurationType="2"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="NDEBUG"
+ MkTypLibCompatible="true"
+ SuppressStartupBanner="true"
+ TargetEnvironment="1"
+ TypeLibraryName=".\Release/help.tlb"
+ HeaderFileName=""
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="3"
+ InlineFunctionExpansion="1"
+ FavorSizeOrSpeed="2"
+ AdditionalIncludeDirectories="../../include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;HELP_EXPORTS"
+ StringPooling="true"
+ ExceptionHandling="0"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderThrough="help.h"
+ AssemblerOutput="3"
+ BrowseInformationFile="$(IntDir)/"
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ DebugInformationFormat="3"
+ CompileAs="0"
+ DisableSpecificWarnings="4996"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="2057"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ IgnoreImportLibrary="true"
+ AdditionalOptions="/ALIGN:4096 /ignore:4108"
+ AdditionalDependencies="odbc32.lib odbccp32.lib wsock32.lib"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ GenerateDebugInformation="true"
+ GenerateMapFile="true"
+ MapFileName="$(OutDir)/$(ProjectName).map"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ OptimizeForWindows98="1"
+ BaseAddress="0x20100000"
+ ImportLibrary="$(IntDir)/$(TargetName).lib"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Editor Debug|Win32"
+ OutputDirectory=".\help___Win32_Editor_Debug"
+ IntermediateDirectory=".\help___Win32_Editor_Debug"
+ ConfigurationType="2"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="_DEBUG"
+ MkTypLibCompatible="true"
+ SuppressStartupBanner="true"
+ TargetEnvironment="1"
+ TypeLibraryName=".\help___Win32_Editor_Debug/help.tlb"
+ HeaderFileName=""
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../../include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;HELP_EXPORTS;EDITOR"
+ ExceptionHandling="0"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderThrough="help.h"
+ AssemblerListingLocation=".\help___Win32_Editor_Debug/"
+ ObjectFile=".\help___Win32_Editor_Debug/"
+ ProgramDataBaseFileName=".\help___Win32_Editor_Debug/"
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ DebugInformationFormat="4"
+ CompileAs="0"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="2057"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ IgnoreImportLibrary="true"
+ AdditionalDependencies="odbc32.lib odbccp32.lib wsock32.lib"
+ OutputFile="../../bin/debug/plugins/help.dll"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile=".\help___Win32_Editor_Debug/help.pdb"
+ ImportLibrary=".\help___Win32_Editor_Debug/help.lib"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)Debug/Plugins"
+ IntermediateDirectory="$(SolutionDir)Debug/Obj/$(PluginName)"
+ ConfigurationType="2"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="_DEBUG"
+ MkTypLibCompatible="true"
+ SuppressStartupBanner="true"
+ TargetEnvironment="1"
+ TypeLibraryName=".\Debug/help.tlb"
+ HeaderFileName=""
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../../include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;HELP_EXPORTS"
+ ExceptionHandling="0"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderThrough="help.h"
+ BrowseInformationFile="$(IntDir)/"
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ DebugInformationFormat="4"
+ CompileAs="0"
+ DisableSpecificWarnings="4996"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="2057"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ IgnoreImportLibrary="true"
+ AdditionalDependencies="odbc32.lib odbccp32.lib wsock32.lib"
+ SuppressStartupBanner="true"
+ GenerateDebugInformation="true"
+ ImportLibrary="$(IntDir)/$(TargetName).lib"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug Unicode|Win32"
+ OutputDirectory="$(SolutionDir)Debug/Plugins"
+ IntermediateDirectory="$(SolutionDir)Debug/Obj/$(ProjectName)"
+ ConfigurationType="2"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="_DEBUG"
+ MkTypLibCompatible="true"
+ SuppressStartupBanner="true"
+ TargetEnvironment="1"
+ TypeLibraryName=".\Debug/help.tlb"
+ HeaderFileName=""
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../../include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;HELP_EXPORTS"
+ ExceptionHandling="0"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderThrough="help.h"
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ DebugInformationFormat="4"
+ CompileAs="0"
+ DisableSpecificWarnings="4996"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="2057"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ IgnoreImportLibrary="true"
+ AdditionalDependencies="odbc32.lib odbccp32.lib wsock32.lib"
+ SuppressStartupBanner="true"
+ GenerateDebugInformation="true"
+ ImportLibrary="$(IntDir)/$(TargetName).lib"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release Unicode|Win32"
+ OutputDirectory="$(SolutionDir)/Release/Plugins"
+ IntermediateDirectory="$(SolutionDir)/Release/Obj/$(ProjectName)"
+ ConfigurationType="2"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="3"
+ InlineFunctionExpansion="1"
+ FavorSizeOrSpeed="2"
+ OmitFramePointers="true"
+ WholeProgramOptimization="true"
+ AdditionalIncludeDirectories="../../include"
+ StringPooling="true"
+ ExceptionHandling="0"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderThrough="help.h"
+ DisableSpecificWarnings="4996"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ IgnoreImportLibrary="true"
+ LinkIncremental="0"
+ SuppressStartupBanner="true"
+ AdditionalManifestDependencies="type=&apos;Win32&apos; name=&apos;Microsoft.Windows.Common-Controls&apos; version=&apos;6.0.0.0&apos; processorArchitecture=&apos;X86&apos; publicKeyToken=&apos;6595b64144ccf1df&apos; language=&apos;*&apos;"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ OptimizeForWindows98="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+ >
+ <File
+ RelativePath="datastore.cpp"
+ >
+ <FileConfiguration
+ Name="Editor Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;HELP_EXPORTS;EDITOR;$(NoInherit)"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;HELP_EXPORTS;$(NoInherit)"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Editor Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;HELP_EXPORTS;EDITOR;$(NoInherit)"
+ BasicRuntimeChecks="3"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;HELP_EXPORTS;$(NoInherit)"
+ BasicRuntimeChecks="3"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ BasicRuntimeChecks="3"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="dlgboxsubclass.cpp"
+ >
+ <FileConfiguration
+ Name="Editor Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;HELP_EXPORTS;EDITOR;$(NoInherit)"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;HELP_EXPORTS;$(NoInherit)"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Editor Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;HELP_EXPORTS;EDITOR;$(NoInherit)"
+ BasicRuntimeChecks="3"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;HELP_EXPORTS;$(NoInherit)"
+ BasicRuntimeChecks="3"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ BasicRuntimeChecks="3"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="helpdlg.cpp"
+ >
+ <FileConfiguration
+ Name="Editor Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;HELP_EXPORTS;EDITOR;$(NoInherit)"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;HELP_EXPORTS;$(NoInherit)"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Editor Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;HELP_EXPORTS;EDITOR;$(NoInherit)"
+ BasicRuntimeChecks="3"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;HELP_EXPORTS;$(NoInherit)"
+ BasicRuntimeChecks="3"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ BasicRuntimeChecks="3"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="main.cpp"
+ >
+ <FileConfiguration
+ Name="Editor Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;HELP_EXPORTS;EDITOR;$(NoInherit)"
+ UsePrecompiledHeader="1"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;HELP_EXPORTS;$(NoInherit)"
+ UsePrecompiledHeader="1"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Editor Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;HELP_EXPORTS;EDITOR;$(NoInherit)"
+ BasicRuntimeChecks="3"
+ UsePrecompiledHeader="1"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;HELP_EXPORTS;$(NoInherit)"
+ BasicRuntimeChecks="3"
+ UsePrecompiledHeader="1"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ BasicRuntimeChecks="3"
+ UsePrecompiledHeader="1"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="1"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="options.cpp"
+ >
+ <FileConfiguration
+ Name="Editor Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;HELP_EXPORTS;EDITOR;$(NoInherit)"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;HELP_EXPORTS;$(NoInherit)"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Editor Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;HELP_EXPORTS;EDITOR;$(NoInherit)"
+ BasicRuntimeChecks="3"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;HELP_EXPORTS;$(NoInherit)"
+ BasicRuntimeChecks="3"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ BasicRuntimeChecks="3"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="streaminout.cpp"
+ >
+ <FileConfiguration
+ Name="Editor Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;HELP_EXPORTS;EDITOR;$(NoInherit)"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;HELP_EXPORTS;$(NoInherit)"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Editor Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;HELP_EXPORTS;EDITOR;$(NoInherit)"
+ BasicRuntimeChecks="3"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;HELP_EXPORTS;$(NoInherit)"
+ BasicRuntimeChecks="3"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ BasicRuntimeChecks="3"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="utils.cpp"
+ >
+ <FileConfiguration
+ Name="Editor Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;HELP_EXPORTS;EDITOR;$(NoInherit)"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;HELP_EXPORTS;$(NoInherit)"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Editor Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;HELP_EXPORTS;EDITOR;$(NoInherit)"
+ BasicRuntimeChecks="3"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;HELP_EXPORTS;$(NoInherit)"
+ BasicRuntimeChecks="3"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ BasicRuntimeChecks="3"
+ />
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl"
+ >
+ <File
+ RelativePath="help.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+ >
+ <File
+ RelativePath="resource.rc"
+ >
+ <FileConfiguration
+ Name="Editor Release|Win32"
+ >
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="EDITOR"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Editor Debug|Win32"
+ >
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="EDITOR"
+ />
+ </FileConfiguration>
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/Help/helpdlg.c b/Help/helpdlg.c
new file mode 100644
index 0000000..8fa78bd
--- /dev/null
+++ b/Help/helpdlg.c
@@ -0,0 +1,700 @@
+/*
+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 <tchar.h>
+#include <stdio.h>
+#define _WIN32_WINNT 0x0500
+#define __RPCASYNC_H__ /* header shows warnings in VS6 */
+#include <windows.h>
+#include <win2k.h>
+
+#define MIRANDA_VER 0x0600
+#include <newpluginapi.h>
+#include <m_utils.h>
+#include <m_langpack.h>
+#include <m_system.h>
+#include "help.h"
+
+#include <richedit.h>
+#pragma warning(disable:4201) /* nonstandard extension used : nameless struct/union */
+#include <commctrl.h>
+#pragma warning(default:4201) /* nonstandard extension used : nameless struct/union */
+#include "resource.h"
+
+extern HINSTANCE hInst;
+HWND hwndHelpDlg;
+
+static int HelpDialogResize(HWND hwndDlg,LPARAM lParam,UTILRESIZECONTROL *urc)
+{
+ UNREFERENCED_PARAMETER(hwndDlg);
+ UNREFERENCED_PARAMETER(lParam);
+ switch(urc->wId) {
+ case IDC_CTLTEXT:
+#ifdef EDITOR
+ case IDC_DLGID:
+ case IDC_MODULE:
+#endif
+ return RD_ANCHORX_WIDTH|RD_ANCHORY_TOP;
+ case IDC_TEXT:
+ return RD_ANCHORX_WIDTH|RD_ANCHORY_HEIGHT;
+ }
+ return RD_ANCHORX_LEFT|RD_ANCHORY_TOP;
+}
+
+#ifndef EDITOR
+BOOL CALLBACK ShadowDlgProc(HWND hwndDlg,UINT msg,WPARAM wParam,LPARAM lParam)
+{
+ UNREFERENCED_PARAMETER(wParam);
+ switch(msg) {
+ case WM_INITDIALOG:
+ { BOOL (WINAPI *pfnSetLayeredWindowAttributes)(HWND,COLORREF,BYTE,DWORD);
+ *(FARPROC*)&pfnSetLayeredWindowAttributes=GetProcAddress(GetModuleHandleA("USER32"),"SetLayeredWindowAttributes");
+ if(!pfnSetLayeredWindowAttributes) {
+ *(HANDLE*)lParam=NULL; // hwndShadowDlg reset
+ DestroyWindow(hwndDlg);
+ return FALSE;
+ }
+ EnableWindow(hwndDlg,FALSE);
+ SetWindowLong(hwndDlg,GWL_EXSTYLE,GetWindowLong(hwndDlg,GWL_EXSTYLE)|WS_EX_LAYERED);
+ pfnSetLayeredWindowAttributes(hwndDlg,RGB(0,0,0),96,LWA_ALPHA);
+ return FALSE;
+ }
+ case WM_CTLCOLORDLG:
+ return (BOOL)GetSysColorBrush(COLOR_WINDOWFRAME);
+ }
+ return FALSE;
+}
+
+// in client coordinates
+int GetCharRangeRect(HWND hwndEdit,LONG *cpMin,LONG cpMax,RECT *rcRange)
+{
+ LONG cpLineBreak;
+ { LONG nLine,nLinePrev;
+ if(*cpMin>cpMax) return 1;
+ nLine=SendMessage(hwndEdit,EM_EXLINEFROMCHAR,0,*cpMin);
+ for(cpLineBreak=*cpMin+1;cpLineBreak<=cpMax;cpLineBreak++) {
+ nLinePrev=nLine;
+ nLine=SendMessage(hwndEdit,EM_EXLINEFROMCHAR,0,cpLineBreak);
+ if(nLine!=nLinePrev) break;
+ }
+ cpMax=cpLineBreak-1;
+ }
+ { POINTL pt;
+ if(SendMessage(hwndEdit,EM_SETTYPOGRAPHYOPTIONS,0,0)) { // test for richedit v3.0
+ SendMessage(hwndEdit,EM_POSFROMCHAR,(WPARAM)&pt,*cpMin);
+ rcRange->left=pt.x; rcRange->top=pt.y;
+ SendMessage(hwndEdit,EM_POSFROMCHAR,(WPARAM)&pt,cpMax);
+ rcRange->right=pt.x; rcRange->bottom=pt.y;
+ }
+ else {
+ DWORD pos;
+ pos=SendMessage(hwndEdit,EM_POSFROMCHAR,(WPARAM)*cpMin,0);
+ POINTSTOPOINT(pt,MAKEPOINTS(pos));
+ rcRange->left=pt.x; rcRange->top=pt.y;
+ pos=SendMessage(hwndEdit,EM_POSFROMCHAR,(WPARAM)cpMax,0);
+ POINTSTOPOINT(pt,MAKEPOINTS(pos));
+ rcRange->right=pt.x; rcRange->bottom=pt.y;
+ }
+ }
+ { FORMATRANGE fr;
+ ZeroMemory(&fr,sizeof(fr));
+ fr.chrg.cpMin=*cpMin;
+ fr.chrg.cpMax=cpMax;
+ fr.hdc=fr.hdcTarget=GetDC(hwndEdit);
+ if(fr.hdc==NULL) return 1;
+ SendMessage(hwndEdit,EM_FORMATRANGE,0,(LPARAM)&fr);
+ PostMessage(hwndEdit,EM_FORMATRANGE,0,0); // clear memory
+ rcRange->bottom+=MulDiv(fr.rc.bottom,GetDeviceCaps(fr.hdc,LOGPIXELSY),1440); // twips to pixels
+ ReleaseDC(hwndEdit,fr.hdc);
+ }
+ *cpMin=cpLineBreak;
+ return 0;
+}
+
+static HCURSOR hHandCursor;
+static LRESULT CALLBACK HelpSubclassProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
+{
+ switch(msg) {
+ case WM_KEYDOWN:
+ if(GetKeyState(VK_CONTROL)&0x8000 && wParam=='C') {
+ SendMessage(GetParent(hwnd),M_CLIPBOARDCOPY,0,0);
+ return 0;
+ }
+ break;
+ case WM_LBUTTONDBLCLK:
+ DestroyWindow(GetParent(hwnd));
+ return 0;
+ case WM_CONTEXTMENU:
+ return DefWindowProc(hwnd,msg,wParam,lParam); // redirect to parent
+ case WM_SETCURSOR: // not available via EN_MSGFILTER
+ if(GetDlgCtrlID((HWND)wParam)==IDC_TEXT) {
+ POINT pt;
+ DWORD pos;
+ CHARRANGE rng;
+ pos=GetMessagePos();
+ POINTSTOPOINT(pt,MAKEPOINTS(pos));
+ ScreenToClient((HWND)wParam,&pt);
+ pos=SendMessage((HWND)wParam,EM_CHARFROMPOS,0,(WPARAM)&pt);
+ if(IsHyperlink(pos,&rng.cpMin,&rng.cpMax,NULL)) {
+ RECT rc;
+ while(!GetCharRangeRect((HWND)wParam,&rng.cpMin,rng.cpMax,&rc))
+ if(PtInRect(&rc,pt)) {
+ SetCursor(hHandCursor);
+ return TRUE;
+ }
+ }
+ }
+ break;
+ }
+ return CallWindowProc((WNDPROC)GetWindowLong(hwnd,GWL_USERDATA),hwnd,msg,wParam,lParam);
+}
+#endif // !defined EDITOR
+
+BOOL CALLBACK HelpDlgProc(HWND hwndDlg,UINT msg,WPARAM wParam,LPARAM lParam)
+{
+ HWND hwndCtl=(HWND)GetWindowLong(hwndDlg,GWL_USERDATA);
+ static LCID locale;
+#ifndef EDITOR
+ static HWND hwndShadowDlg;
+ static HWND hwndToolTip;
+#endif
+
+ switch(msg) {
+ case WM_INITDIALOG:
+ hwndHelpDlg=hwndDlg;
+#ifdef EDITOR
+ TranslateDialogDefault(hwndDlg);
+ SetWindowLong(GetDlgItem(hwndDlg,IDC_DLGID),GWL_STYLE,GetWindowLong(GetDlgItem(hwndDlg,IDC_DLGID),GWL_STYLE)|SS_ENDELLIPSIS);
+ SendDlgItemMessage(hwndDlg,IDC_TEXT,EM_SETEVENTMASK,0,ENM_KEYEVENTS);
+ { RECT rcDlg,rcWork;
+ if(SystemParametersInfo(SPI_GETWORKAREA,0,&rcWork,FALSE) && GetWindowRect(hwndDlg,&rcDlg))
+ SetWindowPos(hwndDlg,0,rcDlg.left,rcWork.bottom-rcDlg.bottom+rcDlg.top,0,0,SWP_NOZORDER|SWP_NOSIZE);
+ }
+#else
+ { RECT rc,rcBuf;
+ SendDlgItemMessage(hwndDlg,IDC_CTLTEXT,EM_GETRECT,0,(LPARAM)&rcBuf);
+ SendDlgItemMessage(hwndDlg,IDC_TEXT,EM_GETRECT,0,(LPARAM)&rc);
+ rc.left=rcBuf.left; // sync richedit offset with edit
+ rc.right=rcBuf.right;
+ SendDlgItemMessage(hwndDlg,IDC_TEXT,EM_SETRECTNP,0,(LPARAM)&rc);
+ }
+ SetWindowLong(GetDlgItem(hwndDlg,IDC_CTLTEXT),GWL_USERDATA,SetWindowLong(GetDlgItem(hwndDlg,IDC_CTLTEXT),GWL_WNDPROC,(LONG)HelpSubclassProc));
+ SetWindowLong(GetDlgItem(hwndDlg,IDC_CARETSUCKER),GWL_USERDATA,SetWindowLong(GetDlgItem(hwndDlg,IDC_CARETSUCKER),GWL_WNDPROC,(LONG)HelpSubclassProc));
+ SendDlgItemMessage(hwndDlg,IDC_TEXT,EM_SETEVENTMASK,0,ENM_KEYEVENTS|ENM_MOUSEEVENTS|ENM_REQUESTRESIZE);
+ SendDlgItemMessage(hwndDlg,IDC_TEXT,EM_SETBKGNDCOLOR,0,GetSysColor(COLOR_INFOBK));
+ SendDlgItemMessage(hwndDlg,IDC_TEXT,EM_SETEDITSTYLE,SES_EXTENDBACKCOLOR,SES_EXTENDBACKCOLOR);
+ SetWindowLong(GetDlgItem(hwndDlg,IDC_TEXT),GWL_USERDATA,SetWindowLong(GetDlgItem(hwndDlg,IDC_TEXT),GWL_WNDPROC,(LONG)HelpSubclassProc));
+ hwndShadowDlg=CreateDialogParam(hInst,MAKEINTRESOURCE(IDD_SHADOW),hwndDlg,ShadowDlgProc,(LPARAM)&hwndShadowDlg);
+ hwndToolTip=CreateWindowEx(WS_EX_TOPMOST,TOOLTIPS_CLASS,NULL,WS_POPUP|TTS_ALWAYSTIP|TTS_NOPREFIX,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,hwndDlg,NULL,hInst,NULL);
+ if(hwndToolTip!=NULL) {
+ SetWindowPos(hwndToolTip,HWND_TOPMOST,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
+ SendMessage(hwndToolTip,TTM_SETTIPBKCOLOR,GetSysColor(COLOR_WINDOW),0); // yelleow on yellow looks silly
+ SendMessage(hwndToolTip,TTM_SETDELAYTIME,TTDT_AUTOMATIC,GetDoubleClickTime()*3);
+ }
+ hHandCursor=(HCURSOR)LoadImage(NULL,IDC_HAND,IMAGE_CURSOR,0,0,LR_DEFAULTSIZE|LR_SHARED);
+ if(hHandCursor==NULL) // use fallback out of miranda32.exe
+ hHandCursor=(HCURSOR)LoadImage(GetModuleHandle(NULL),MAKEINTRESOURCE(214),IMAGE_CURSOR,0,0,LR_DEFAULTSIZE|LR_SHARED);
+#endif
+ SendDlgItemMessage(hwndDlg,IDC_TEXT,EM_SETLANGOPTIONS,0,SendDlgItemMessage(hwndDlg,IDC_TEXT,EM_GETLANGOPTIONS,0,0)|IMF_UIFONTS);
+ SetWindowPos(hwndDlg,HWND_TOPMOST,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
+ return TRUE;
+ case WM_SIZE:
+ { UTILRESIZEDIALOG urd;
+ ZeroMemory(&urd,sizeof(urd));
+ urd.cbSize=sizeof(urd);
+ urd.hInstance=hInst;
+ urd.hwndDlg=hwndDlg;
+ urd.lpTemplate=MAKEINTRESOURCEA(IDD_HELP);
+ urd.pfnResizer=HelpDialogResize;
+ CallService(MS_UTILS_RESIZEDIALOG,0,(LPARAM)&urd);
+ InvalidateRect(hwndDlg,NULL,TRUE);
+#ifdef EDITOR
+ break;
+#endif
+ }
+#ifndef EDITOR
+ case WM_MOVE:
+ if(IsWindow(hwndShadowDlg)) {
+ RECT rc;
+ HRGN hRgnShadow,hRgnDlg;
+ if(!GetWindowRect(hwndDlg,&rc)) break;
+ hRgnShadow=CreateRectRgnIndirect(&rc);
+ if(hRgnShadow==NULL) break;
+ OffsetRgn(hRgnShadow,5,5);
+ hRgnDlg=CreateRectRgnIndirect(&rc);
+ if(hRgnDlg==NULL) break;
+ if(CombineRgn(hRgnShadow,hRgnShadow,hRgnDlg,RGN_DIFF)==ERROR) {
+ DeleteObject(hRgnShadow);
+ DeleteObject(hRgnDlg);
+ break;
+ }
+ DeleteObject(hRgnDlg);
+ OffsetRgn(hRgnShadow,-rc.left-5,-rc.top-5);
+ SetWindowRgn(hwndShadowDlg,hRgnShadow,FALSE); // system gets ownership of hRgnShadow
+ SetWindowPos(hwndShadowDlg,HWND_TOPMOST,rc.left+5,rc.top+5,rc.right-rc.left,rc.bottom-rc.top,SWP_SHOWWINDOW);
+ SetWindowPos(hwndDlg,HWND_TOPMOST,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE);
+ }
+ break;
+ case WM_KEYDOWN:
+ if(GetKeyState(VK_CONTROL)&0x8000 && wParam=='C') {
+ SendMessage(hwndDlg,M_CLIPBOARDCOPY,0,0);
+ return TRUE;
+ }
+ break;
+ case WM_CONTEXTMENU:
+ { HMENU hMenu;
+ POINT pt;
+ POINTSTOPOINT(pt,MAKEPOINTS(lParam));
+ hMenu=CreatePopupMenu();
+ AppendMenu(hMenu,MF_STRING,WM_COPY,TranslateT("&Copy"));
+ if(TrackPopupMenuEx(hMenu,TPM_LEFTALIGN|TPM_TOPALIGN|TPM_HORPOSANIMATION|TPM_VERPOSANIMATION|TPM_RIGHTBUTTON|TPM_RETURNCMD|TPM_NONOTIFY,pt.x,pt.y,hwndDlg,NULL))
+ SendMessage(hwndDlg,M_CLIPBOARDCOPY,0,0);
+ DestroyMenu(hMenu);
+ }
+ return 0;
+ case WM_LBUTTONDBLCLK:
+ DestroyWindow(hwndDlg);
+ return TRUE;
+ case M_CLIPBOARDCOPY:
+ { HWND hwnd=GetFocus();
+ if(hwnd==GetDlgItem(hwndDlg,IDC_CTLTEXT) || hwnd==GetDlgItem(hwndDlg,IDC_TEXT)) {
+ CHARRANGE sel;
+ ZeroMemory(&sel,sizeof(sel));
+ SendMessage(hwnd,EM_GETSEL,(WPARAM)&sel.cpMin,(LPARAM)&sel.cpMax);
+ if(sel.cpMin!=sel.cpMax) {
+ SendMessage(hwnd,WM_COPY,0,0);
+ return TRUE;
+ }
+ }
+ }
+ if(OpenClipboard(hwndDlg)) {
+ HGLOBAL hglb;
+ int cch,len;
+ EmptyClipboard();
+ hglb=GlobalAlloc(GMEM_MOVEABLE,sizeof(LCID));
+ if(hglb!=NULL) {
+ LCID *plocale=GlobalLock(hglb);
+ if(plocale!=NULL) {
+ *plocale=locale;
+ GlobalUnlock(hglb);
+ if(!SetClipboardData(CF_LOCALE,hglb)) GlobalFree(hglb); // shell takes ownership
+ } else GlobalFree(hglb);
+ }
+ cch=GetWindowTextLength(GetDlgItem(hwndDlg,IDC_CTLTEXT))+GetWindowTextLength(GetDlgItem(hwndDlg,IDC_TEXT))+3;
+ hglb=GlobalAlloc(GMEM_MOVEABLE,(cch+1)*sizeof(TCHAR));
+ if(hglb!=NULL) {
+ TCHAR *pszText=GlobalLock(hglb);
+ if(pszText!=NULL) {
+ if(!GetWindowText(GetDlgItem(hwndDlg,IDC_CTLTEXT),pszText,cch-2)) pszText[0]=_T('\0');
+ len=lstrlen(pszText);
+ if(GetWindowText(GetDlgItem(hwndDlg,IDC_TEXT),pszText+len+2,cch-2-len) && len) {
+ pszText[len]=_T('\r');
+ pszText[len+1]=_T('\n');
+ }
+ GlobalUnlock(hglb);
+#if defined(_UNICODE)
+ if(!SetClipboardData(CF_UNICODETEXT,hglb)) GlobalFree(hglb); // shell takes ownership
+#else
+ if(!SetClipboardData(CF_TEXT,hglb)) GlobalFree(hglb); // shell takes ownership
+#endif
+ } else GlobalFree(hglb);
+ }
+ CloseClipboard();
+ }
+ return TRUE;
+ case WM_CTLCOLORDLG:
+ case WM_CTLCOLORSTATIC:
+ SetTextColor((HDC)wParam,GetSysColor(COLOR_INFOTEXT));
+ SetBkColor((HDC)wParam,GetSysColor(COLOR_INFOBK));
+ return (BOOL)GetSysColorBrush(COLOR_INFOBK);
+ case WM_ACTIVATE:
+ if(LOWORD(wParam)!=WA_INACTIVE) break;
+ if(GetParent((HWND)lParam)==hwndDlg) break;
+ // fall through
+ case WM_SYSCOLORCHANGE:
+ case WM_ACTIVATEAPP:
+ PostMessage(hwndDlg,WM_CLOSE,0,0); // no DestroyWindow() here! would cause recursion
+ break;
+#endif // !defined EDITOR
+ case M_CHANGEHELPCONTROL:
+ if(hwndCtl==(HWND)lParam) break;
+ SetWindowLong(hwndDlg,GWL_USERDATA,lParam);
+ hwndCtl=(HWND)lParam;
+ SetDlgItemText(hwndDlg,IDC_CTLTEXT,NULL);
+#ifdef EDITOR
+ { TCHAR text[1024];
+ char *szModule,*szDlgId;
+
+ GetControlTitle(hwndCtl,text,SIZEOF(text));
+ SetDlgItemText(hwndDlg,IDC_CTLTEXT,text);
+ mir_sntprintf(text,SIZEOF(text),TranslateT("Control ID: %d"),GetControlID(hwndCtl));
+ SetDlgItemText(hwndDlg,IDC_CTLID,text);
+
+ szDlgId=CreateDialogIdString(GetControlDialog(hwndCtl));
+ mir_sntprintf(text,SIZEOF(text),TranslateT("Dialog ID: %hs"),(szDlgId!=NULL)?szDlgId:Translate("Unknown"));
+ mir_free(szDlgId); // does NULL check
+ SetDlgItemText(hwndDlg,IDC_DLGID,text);
+
+ mir_sntprintf(text,SIZEOF(text),TranslateT("Type: %s"),TranslateTS(szControlTypeNames[GetControlType(hwndCtl)]));
+ SetDlgItemText(hwndDlg,IDC_CTLTYPE,text);
+
+ szModule=GetControlModuleName(hwndCtl);
+ mir_sntprintf(text,SIZEOF(text),TranslateT("Module: %hs"),szModule?szModule:Translate("Unknown"));
+ mir_free(szModule); // does NULL check
+ SetDlgItemText(hwndDlg,IDC_MODULE,text);
+ }
+#endif // defined EDITOR
+ SetDlgItemText(hwndDlg,IDC_TEXT,NULL);
+ SendMessage(hwndDlg,M_LOADHELP,0,0);
+#ifdef EDITOR
+ ShowWindow(hwndDlg,SW_SHOWNORMAL);
+#else
+ SendDlgItemMessage(hwndDlg,IDC_TEXT,EM_REQUESTRESIZE,0,0);
+ return FALSE;
+#endif
+ return TRUE;
+ case M_HELPLOADFAILED:
+ if(hwndCtl!=(HWND)lParam) break;
+#ifdef EDITOR
+ EnableWindow(GetDlgItem(hwndDlg,IDC_TEXT),TRUE);
+ { TCHAR text[2024];
+ GetControlTitle(hwndCtl,text,SIZEOF(text));
+ SetDlgItemText(hwndDlg,IDC_CTLTEXT,text);
+ }
+#else
+ SetDlgItemText(hwndDlg,IDC_CTLTEXT,TranslateT("No Help Pack installed!"));
+#endif
+ SetDlgItemText(hwndDlg,IDC_TEXT,NULL);
+ MessageBeep(MB_ICONERROR);
+ break;
+#ifdef EDITOR
+ case M_SAVECOMPLETE:
+#endif
+ case M_HELPLOADED:
+ if(hwndCtl!=(HWND)lParam) break;
+ case M_LOADHELP:
+ { TCHAR *szTitle;
+ char *szText;
+ char *szDlgId,*szModule;
+ UINT codepage;
+ BOOL isRTL;
+ int id,loading;
+#ifdef EDITOR
+ EnableWindow(GetDlgItem(hwndDlg,IDC_TEXT),TRUE);
+#endif
+ szDlgId=CreateDialogIdString(GetControlDialog(hwndCtl));
+ szModule=GetControlModuleName(hwndCtl);
+ id=GetControlID(hwndCtl);
+#ifndef EDITOR
+ // show id string instead of help text when 'ctrl' key pressed
+ if(msg==M_LOADHELP && GetAsyncKeyState(VK_CONTROL)&0x8000) {
+ char *buf;
+ HWND hwnd;
+ buf=CreateControlIdentifier(szDlgId?szDlgId:"unknown",szModule?szModule:"unknown",id,hwndCtl);
+ hwnd=GetDlgItem(hwndDlg,IDC_CTLTEXT);
+ SetWindowTextA(hwnd,buf); // accepts NULL
+ SetDlgItemText(hwndDlg,IDC_TEXT,NULL);
+ mir_free(buf); // does NULL check
+ mir_free(szDlgId); // does NULL check
+ mir_free(szModule); // does NULL check
+ break;
+ }
+#endif
+ if(szDlgId==NULL || szModule==NULL) {
+ SetDlgItemText(hwndDlg,IDC_TEXT,NULL);
+#ifndef EDITOR
+ SetDlgItemText(hwndDlg,IDC_CTLTEXT,TranslateT("No help available for this item."));
+#endif
+ mir_free(szDlgId); // does NULL check
+ mir_free(szModule); // does NULL check
+ break;
+ }
+
+ loading=GetControlHelp(hwndCtl,szDlgId,szModule,id,&szTitle,&szText,NULL,&locale,&codepage,&isRTL,(msg==M_HELPLOADED)?GCHF_DONTLOAD:0);
+ if(!loading) {
+ if(szText) StreamInHtml(GetDlgItem(hwndDlg,IDC_TEXT),szText,codepage,RGB(255,0,0));
+ else SetDlgItemText(hwndDlg,IDC_TEXT,NULL);
+ if(szTitle) {
+ TCHAR buf[128];
+ RECT rc;
+ HFONT hFontPrev;
+ DWORD exStyle;
+ HWND hwndCtlText;
+ HDC hdc;
+ hwndCtlText=GetDlgItem(hwndDlg,IDC_CTLTEXT);
+ exStyle=GetWindowLong(GetDlgItem(hwndDlg,IDC_CTLTEXT),GWL_EXSTYLE);
+ hdc=GetDC(hwndCtlText);
+ { DWORD (WINAPI *pfnGetLayout)(HDC); // obey right-to-left languages
+ *(FARPROC*)&pfnGetLayout=GetProcAddress(GetModuleHandleA("GDI32"),"GetLayout");
+ if(pfnGetLayout) isRTL=(isRTL && !pfnGetLayout(hdc));
+ if(isRTL) exStyle|=WS_EX_RTLREADING|WS_EX_RIGHT;
+ else exStyle&=~(WS_EX_RTLREADING|WS_EX_RIGHT);
+ }
+ mir_sntprintf(buf,SIZEOF(buf)-4,_T("%s"),szTitle);
+ if(hdc!=NULL && hwndCtlText!=NULL) {
+ SendMessage(hwndCtlText,EM_GETRECT,0,(LPARAM)&rc);
+ hFontPrev=SelectObject(hdc,(HFONT)SendMessage(hwndCtlText,WM_GETFONT,0,0));
+ // doesn't actually draw the string due to DT_CALCRECT
+ DrawTextEx(hdc,buf,-1,&rc,DT_MODIFYSTRING|DT_CALCRECT|DT_EDITCONTROL|DT_END_ELLIPSIS|DT_INTERNAL|(isRTL?(DT_RTLREADING|DT_RIGHT):DT_LEFT)|DT_NOPREFIX|DT_SINGLELINE,NULL);
+ SelectObject(hdc,hFontPrev);
+ ReleaseDC(hwndCtlText,hdc);
+ }
+ SetWindowLong(GetDlgItem(hwndDlg,IDC_CTLTEXT),GWL_EXSTYLE,exStyle);
+ SetWindowText(hwndCtlText,buf);
+ } else SetDlgItemText(hwndDlg,IDC_CTLTEXT,NULL);
+ }
+ else {
+ if(msg==M_HELPLOADED) {
+ SetDlgItemText(hwndDlg,IDC_TEXT,NULL);
+#ifndef EDITOR
+ SetDlgItemText(hwndDlg,IDC_CTLTEXT,TranslateT("No help available for this item."));
+#endif
+ }
+ else {
+#ifdef EDITOR
+ EnableWindow(GetDlgItem(hwndDlg,IDC_TEXT),FALSE);
+ SetDlgItemText(hwndDlg,IDC_TEXT,TranslateT("Loading..."));
+#else
+ SetDlgItemText(hwndDlg,IDC_CTLTEXT,TranslateT("Loading..."));
+ SetDlgItemText(hwndDlg,IDC_TEXT,NULL);
+#endif
+ }
+ }
+ mir_free(szDlgId);
+ mir_free(szModule);
+ break;
+ }
+ case WM_NOTIFY:
+ switch(((NMHDR*)lParam)->idFrom) {
+ case IDC_TEXT:
+ switch(((NMHDR*)lParam)->code) {
+#ifdef EDITOR
+ case EN_MSGFILTER:
+ switch(((MSGFILTER*)lParam)->msg) {
+ case WM_CHAR:
+ switch(((MSGFILTER*)lParam)->wParam) {
+ case 'B'-'A'+1:
+ case 'I'-'A'+1:
+ case 'U'-'A'+1:
+ case 'H'-'A'+1:
+ case 'L'-'A'+1:
+ case 'S'-'A'+1:
+ case 'G'-'A'+1:
+ SetWindowLong(hwndDlg,DWL_MSGRESULT,TRUE);
+ return TRUE;
+ }
+ break;
+ case WM_KEYDOWN:
+ { CHARFORMAT cf;
+ int changes=0;
+
+ ZeroMemory(&cf,sizeof(cf));
+ if(!(GetKeyState(VK_CONTROL)&0x8000)) break;
+ cf.cbSize=sizeof(cf);
+ SendDlgItemMessage(hwndDlg,IDC_TEXT,EM_GETCHARFORMAT,TRUE,(LPARAM)&cf);
+ switch(((MSGFILTER*)lParam)->wParam) {
+ case 'B':
+ cf.dwEffects^=CFE_BOLD;
+ cf.dwMask=CFM_BOLD;
+ changes=1;
+ break;
+ case 'I':
+ cf.dwEffects^=CFE_ITALIC;
+ cf.dwMask=CFM_ITALIC;
+ changes=1;
+ break;
+ case 'U':
+ cf.dwEffects^=CFE_UNDERLINE;
+ cf.dwMask=CFM_UNDERLINE;
+ changes=1;
+ break;
+ case 'L':
+ { CHOOSECOLOR cc;
+ COLORREF custCol[16];
+ ZeroMemory(&custCol,sizeof(custCol));
+ ZeroMemory(&cc,sizeof(cc));
+ cc.lStructSize=sizeof(cc);
+ cc.hwndOwner=hwndDlg;
+ cc.lpCustColors=custCol;
+ cc.rgbResult=cf.crTextColor;
+ cc.Flags=CC_ANYCOLOR|CC_FULLOPEN|CC_RGBINIT;
+ if(!ChooseColor(&cc)) break;
+ cf.crTextColor=0;
+ cf.dwEffects=0;
+ if(cc.rgbResult) cf.crTextColor=cc.rgbResult;
+ else cf.dwEffects=CFE_AUTOCOLOR;
+ cf.dwMask=CFM_COLOR;
+ changes=1;
+ break;
+ }
+ case 'H':
+ cf.dwEffects^=CFE_STRIKEOUT;
+ cf.dwMask=CFM_STRIKEOUT;
+ changes=1;
+ break;
+ case VK_OEM_PLUS:
+ cf.yHeight=((GetKeyState(VK_SHIFT)&0x8000)?TEXTSIZE_BIG:TEXTSIZE_NORMAL)*10;
+ cf.dwMask=CFM_SIZE;
+ changes=1;
+ break;
+ case VK_OEM_MINUS:
+ cf.yHeight=TEXTSIZE_SMALL*10;
+ cf.dwMask=CFM_SIZE;
+ changes=1;
+ break;
+ case 'S':
+ { TCHAR szTitle[1024];
+ char *szText,*szDlgId,*szModule;
+ if(!GetDlgItemText(hwndDlg,IDC_CTLTEXT,szTitle,SIZEOF(szTitle))) break;
+ szDlgId=CreateDialogIdString(GetControlDialog(hwndCtl));
+ if(szDlgId==NULL) break;
+ szText=StreamOutHtml(GetDlgItem(hwndDlg,IDC_TEXT));
+ szModule=GetControlModuleName(hwndCtl);
+ if(szModule==NULL) {
+ mir_free(szDlgId);
+ break;
+ }
+ SetControlHelp(szDlgId,szModule,GetControlID(hwndCtl),szTitle,szText,GetControlType(hwndCtl));
+ mir_free(szText);
+ mir_free(szDlgId);
+ mir_free(szModule);
+ SaveDialogCache();
+ SetWindowLong(hwndDlg,DWL_MSGRESULT,TRUE);
+ return TRUE;
+ }
+ case 'G':
+ SendMessage(hwndDlg,M_LOADHELP,0,0);
+ SetWindowLong(hwndDlg,DWL_MSGRESULT,TRUE);
+ return TRUE;
+ }
+ if(changes) {
+ SendDlgItemMessage(hwndDlg,IDC_TEXT,EM_SETCHARFORMAT,SCF_WORD|SCF_SELECTION,(LPARAM)&cf);
+ SetWindowLong(hwndDlg,DWL_MSGRESULT,TRUE);
+ return TRUE;
+ }
+ break;
+ }
+ }
+ break;
+#else // defined EDITOR
+ case EN_MSGFILTER:
+ { MSGFILTER *msgf=(MSGFILTER*)lParam;
+ switch(msgf->msg) {
+ case WM_LBUTTONUP:
+ { POINT pt;
+ DWORD pos;
+ CHARRANGE sel;
+ char *pszLink;
+ HWND hwndEdit=msgf->nmhdr.hwndFrom;
+
+ ZeroMemory(&sel,sizeof(sel));
+ SendMessage(msgf->nmhdr.hwndFrom,EM_EXGETSEL,0,(LPARAM)&sel);
+ if(sel.cpMin!=sel.cpMax) break;
+ POINTSTOPOINT(pt,MAKEPOINTS(msgf->lParam));
+ pos=SendMessage(hwndEdit,EM_CHARFROMPOS,0,(WPARAM)&pt);
+ if(IsHyperlink(pos,NULL,NULL,&pszLink)) {
+ CallService(MS_UTILS_OPENURL,1,(LPARAM)pszLink); // pszLink is MBCS string in CP_ACP
+ SetWindowLong(hwndDlg,DWL_MSGRESULT,TRUE);
+ return TRUE;
+ }
+ }
+ break;
+ case WM_MOUSEMOVE: // register hyperlink tooltips when current
+ if(hwndToolTip!=NULL) {
+ POINTL pt;
+ DWORD pos;
+ CHARRANGE rng;
+ char *pszLink;
+
+ POINTSTOPOINT(pt,MAKEPOINTS(msgf->lParam));
+ pos=SendMessage(msgf->nmhdr.hwndFrom,EM_CHARFROMPOS,0,(WPARAM)&pt);
+ if(IsHyperlink(pos,&rng.cpMin,&rng.cpMax,&pszLink)) { // pszLink is MBCS in CP_ACP
+ TTTOOLINFOA ti;
+ ZeroMemory(&ti,sizeof(ti));
+ ti.cbSize=sizeof(ti);
+ ti.hwnd=msgf->nmhdr.hwndFrom;
+ ti.uId=(UINT)rng.cpMin;
+ if(!SendMessage(hwndToolTip,TTM_GETTOOLINFOA,0,(LPARAM)&ti)) {
+ LONG cpRectMin;
+ ti.uFlags=TTF_SUBCLASS;
+ ti.lpszText=pszLink;
+ cpRectMin=rng.cpMin;
+ while(!GetCharRangeRect(ti.hwnd,&rng.cpMin,rng.cpMax,&ti.rect)) {
+ ti.uId=(UINT)cpRectMin;
+ SendMessage(hwndToolTip,TTM_ADDTOOLA,0,(LPARAM)&ti);
+ cpRectMin=rng.cpMin;
+ }
+ }
+ }
+ }
+ break;
+ }
+ }
+ break;
+ case EN_REQUESTRESIZE:
+ { RECT rcDlg,rcEdit,rcCtl,rcNew;
+ REQRESIZE *rr=(REQRESIZE*)lParam;
+ POINT ptScreenBottomRight;
+
+ if(!GetWindowRect(hwndDlg,&rcDlg)) break;
+ if(!GetWindowRect(hwndCtl,&rcCtl)) break;
+ if(!GetWindowRect(GetDlgItem(hwndDlg,IDC_TEXT),&rcEdit)) break;
+ rcNew.left=rcCtl.left+30;
+ rcNew.top=rcCtl.bottom+10;
+ rcNew.right=rcNew.left+(rr->rc.right-rr->rc.left)+(rcDlg.right-rcDlg.left)-(rcEdit.right-rcEdit.left)+(GetWindowLong(GetDlgItem(hwndDlg,IDC_TEXT),GWL_STYLE)&WS_VSCROLL?GetSystemMetrics(SM_CXVSCROLL):0);
+ if(GetWindowTextLength(GetDlgItem(hwndDlg,IDC_TEXT)))
+ rcNew.bottom=rcNew.top+min(GetSystemMetrics(SM_CYSCREEN)/5,(rr->rc.bottom-rr->rc.top)+(rcDlg.bottom-rcDlg.top)-(rcEdit.bottom-rcEdit.top));
+ else
+ rcNew.bottom=rcNew.top+min(GetSystemMetrics(SM_CYSCREEN)/5,(rcDlg.bottom-rcDlg.top)-(rcEdit.bottom-rcEdit.top));
+ if(GetSystemMetrics(SM_CXVIRTUALSCREEN)) {
+ ptScreenBottomRight.x=GetSystemMetrics(SM_CXVIRTUALSCREEN)+GetSystemMetrics(SM_XVIRTUALSCREEN);
+ ptScreenBottomRight.y=GetSystemMetrics(SM_CYVIRTUALSCREEN)+GetSystemMetrics(SM_YVIRTUALSCREEN);
+ }
+ else {
+ ptScreenBottomRight.x=GetSystemMetrics(SM_CXSCREEN);
+ ptScreenBottomRight.y=GetSystemMetrics(SM_CYSCREEN);
+ }
+ if(rcNew.right>=ptScreenBottomRight.x) OffsetRect(&rcNew,ptScreenBottomRight.x-rcNew.right,0);
+ if(rcNew.bottom>=ptScreenBottomRight.y) OffsetRect(&rcNew,0,ptScreenBottomRight.y-rcNew.bottom);
+ SetWindowPos(hwndDlg,0,rcNew.left,rcNew.top,rcNew.right-rcNew.left,rcNew.bottom-rcNew.top,SWP_NOZORDER);
+ ShowWindow(hwndDlg,SW_SHOWNORMAL);
+ break;
+ }
+#endif // defined EDITOR
+ }
+ }
+ break;
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDCANCEL: // WM_CLOSE
+ DestroyWindow(hwndDlg);
+ return TRUE;
+ }
+ break;
+ case WM_DESTROY:
+#ifndef EDITOR
+ FreeHyperlinkData();
+ if(IsWindow(hwndShadowDlg)) DestroyWindow(hwndShadowDlg);
+ if(hwndToolTip!=NULL) DestroyWindow(hwndToolTip);
+#endif
+ hwndHelpDlg=NULL;
+ break;
+ }
+ return FALSE;
+}
diff --git a/Help/helppack.c b/Help/helppack.c
new file mode 100644
index 0000000..4260bc6
--- /dev/null
+++ b/Help/helppack.c
@@ -0,0 +1,466 @@
+/*
+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 <tchar.h>
+#include <stdio.h>
+#define __RPCASYNC_H__ /* header shows warnings in VS6 */
+#include <windows.h>
+#include <win2k.h>
+#define MIRANDA_VER 0x0600
+#include <newpluginapi.h>
+#include <m_system.h>
+#include <m_utils.h>
+#include "help.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 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 '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 */
+#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)," 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("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,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];
+ 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(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);
+ }
+ }
+ }
+}
diff --git a/Help/main.c b/Help/main.c
new file mode 100644
index 0000000..781bd1f
--- /dev/null
+++ b/Help/main.c
@@ -0,0 +1,203 @@
+/*
+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 <tchar.h>
+#include <stdio.h>
+#define _WIN32_WINNT 0x0500
+#define __RPCASYNC_H__ /* header shows warnings in VS6 */
+#include <windows.h>
+#pragma warning(disable:4201) /* nonstandard extension used : nameless struct/union */
+#include <commctrl.h>
+#pragma warning(default:4201) /* nonstandard extension used : nameless struct/union */
+#define MIRANDA_VER 0x0600
+#include <newpluginapi.h>
+#include <win2k.h>
+#include <m_system.h>
+#include <m_database.h>
+#include <m_utils.h>
+#include <m_langpack.h>
+#include "m_help.h"
+#include "help.h"
+#include "version.h"
+
+HINSTANCE hInst;
+PLUGINLINK *pluginLink;
+struct MM_INTERFACE mmi;
+struct UTF8_INTERFACE utfi;
+extern HWND hwndHelpDlg;
+static HANDLE hHookModulesLoaded;
+
+static PLUGININFOEX pluginInfo={
+ sizeof(PLUGININFOEX),
+#ifdef EDITOR
+ "Help Editor",
+#else
+ "Help",
+#endif // defined EDITOR
+ PLUGIN_VERSION,
+#if defined(_DEBUG)
+ "Development build not intended for release. ("__DATE__")", /* auto-translated */
+#else
+ "Provides context sensitive help in the Miranda IM dialog boxes.", /* auto-translated */
+#endif
+ "Richard Hughes, H. Herkenrath",
+ PLUGIN_EMAIL, /* @ will be set later */
+ "© 2002 Richard Hughes, 2005-2007 H. Herkenrath",
+ PLUGIN_WEBSITE,
+ UNICODE_AWARE,
+ 0,
+#if defined(_UNICODE)
+ // {B16DF0B2-A08F-4bc6-8FA2-3D5FFFA2708D}
+ {0xb16df0b2,0xa08f,0x4bc6,{0x8f,0xa2,0x3d,0x5f,0xff,0xa2,0x70,0x8d}}
+#else
+ // {B9BC3771-F690-4bcd-ACE8-8887E7D2DF93}
+ {0xb9bc3771,0xf690,0x4bcd,{0xac,0xe8,0x88,0x87,0xe7,0xd2,0xdf,0x93}}
+#endif
+};
+static const MUUID interfaces[]={MIID_HELP,MIID_LAST};
+
+BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,void *pReserved)
+{
+ UNREFERENCED_PARAMETER(pReserved);
+ if(fdwReason==DLL_PROCESS_ATTACH)
+ DisableThreadLibraryCalls(hInst=hinstDLL);
+ return TRUE;
+}
+
+static void InstallFile(const TCHAR *pszFileName,const TCHAR *pszDestSubDir)
+{
+ TCHAR szFileFrom[MAX_PATH+1],szFileTo[MAX_PATH+1],*p;
+ HANDLE hFile;
+
+ if(!GetModuleFileName(hInst,szFileFrom,SIZEOF(szFileFrom)-lstrlen(pszFileName)))
+ return;
+ p=_tcsrchr(szFileFrom,_T('\\'));
+ if(p!=NULL) *(++p)=0;
+ lstrcat(szFileFrom,pszFileName); /* buffer safe */
+
+ hFile=CreateFile(szFileFrom,0,FILE_SHARE_READ,0,OPEN_EXISTING,0,0);
+ if(hFile==INVALID_HANDLE_VALUE) return;
+ CloseHandle(hFile);
+
+ if(!GetModuleFileName(NULL,szFileTo,SIZEOF(szFileTo)-lstrlen(pszDestSubDir)-lstrlen(pszFileName)))
+ return;
+ p=_tcsrchr(szFileTo,_T('\\'));
+ if(p!=NULL) *(++p)=0;
+ lstrcat(szFileTo,pszDestSubDir); /* buffer safe */
+ CreateDirectory(szFileTo,NULL);
+ lstrcat(szFileTo,pszFileName); /* buffer safe */
+
+ if(!MoveFile(szFileFrom,szFileTo) && GetLastError()==ERROR_ALREADY_EXISTS) {
+ DeleteFile(szFileTo);
+ MoveFile(szFileFrom,szFileTo);
+ }
+}
+
+static int HelpModulesLoaded(WPARAM wParam,LPARAM lParam)
+{
+ UNREFERENCED_PARAMETER(wParam);
+ UNREFERENCED_PARAMETER(lParam);
+ if(ServiceExists("DBEditorpp/RegisterSingleModule"))
+ CallService("DBEditorpp/RegisterSingleModule",(WPARAM)"HelpPlugin",0);
+ return 0;
+}
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+__declspec(dllexport) const PLUGININFO* MirandaPluginInfo(DWORD mirandaVersion)
+{
+ if(mirandaVersion<PLUGIN_MAKE_VERSION(0,1,0,1)) return NULL;
+ pluginInfo.cbSize=sizeof(PLUGININFO); /* needed as v0.6 does equality check */
+ /* email obfuscated, made .rdata writable */
+ pluginInfo.authorEmail[PLUGIN_EMAIL_ATT_POS-1]='@';
+ return (PLUGININFO*)&pluginInfo; /* header is the same */
+}
+
+__declspec(dllexport) const PLUGININFOEX* MirandaPluginInfoEx(DWORD mirandaVersion)
+{
+ UNREFERENCED_PARAMETER(mirandaVersion);
+ pluginInfo.cbSize=sizeof(PLUGININFOEX);
+ /* email obfuscated, made .rdata writable */
+ pluginInfo.authorEmail[PLUGIN_EMAIL_ATT_POS-1]='@';
+ return &pluginInfo;
+}
+
+__declspec(dllexport) const MUUID* MirandaPluginInterfaces(void)
+{
+ return interfaces;
+}
+
+__declspec(dllexport) int Load(PLUGINLINK *link)
+{
+ INITCOMMONCONTROLSEX icc;
+ pluginLink=link;
+
+ /* existance of MS_SYSTEM_GETVERSION and MS_LANGPACK_TRANSLATESTRING
+ * is checked in MirandaPluginInfo().
+ * Not placed in MirandaPluginInfo() to avoid MessageBoxes on plugin options.
+ * Using ANSI as LANG_UNICODE might not be supported. */
+ if(CallService(MS_SYSTEM_GETVERSION,0,0)<NEEDED_MIRANDA_VERSION) {
+ char szText[256];
+ mir_snprintf(szText,sizeof(szText),Translate("The Help Plugin can not be loaded. It requires Miranda IM %hs or later."),NEEDED_MIRANDA_VERSION_STR);
+ MessageBoxA(NULL,szText,Translate("Help Plugin"),MB_OK|MB_ICONINFORMATION|MB_SETFOREGROUND|MB_TOPMOST|MB_TASKMODAL);
+ return 1;
+ }
+
+ if(mir_getMMI(&mmi)) return 1;
+#if defined(_UNICODE)
+ if(mir_getUTFI(&utfi)) return 1;
+#endif
+ icc.dwSize=sizeof(icc);
+ icc.dwICC=ICC_UPDOWN_CLASS|ICC_TREEVIEW_CLASSES;
+ if(!InitCommonControlsEx(&icc)) return 1;
+
+ if(LoadLibraryA("RICHED20")==NULL) /* richedit v2.0 (Win98/NT4), v3.0 (WinXP/2000/Me+) */
+ if(IDYES!=MessageBoxEx(NULL,
+ TranslateT("The Help Plugin can not be loaded, riched20.dll is missing. If you are using Windows 95 or WINE please make sure you have riched20.dll installed.\n\nPress 'Yes' to continue loading Miranda IM."),
+ TranslateT("Help Plugin"),MB_YESNO|MB_ICONWARNING|MB_SETFOREGROUND|MB_TOPMOST|MB_TASKMODAL,LANGIDFROMLCID((LCID)CallService(MS_LANGPACK_GETLOCALE,0,0))))
+ return 1;
+
+ if(InstallDialogBoxHook()) return 1;
+ InitOptions();
+ InitDialogCache();
+ InitUpdate();
+ hHookModulesLoaded=HookEvent(ME_SYSTEM_MODULESLOADED,HelpModulesLoaded);
+
+ InstallFile(_T("Help-Readme.txt"),_T("Docs\\"));
+ InstallFile(_T("Help-License.txt"),_T("Docs\\"));
+ InstallFile(_T("Help-SDK.zip"),_T("Docs\\"));
+ return 0;
+}
+
+__declspec(dllexport) int Unload(void)
+{
+ UninitOptions();
+ UninitUpdate();
+ RemoveDialogBoxHook();
+ if(hwndHelpDlg!=NULL) DestroyWindow(hwndHelpDlg);
+ FreeDialogCache();
+ UnhookEvent(hHookModulesLoaded); /* does NULL check */
+ return 0;
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/Help/options.c b/Help/options.c
new file mode 100644
index 0000000..d540855
--- /dev/null
+++ b/Help/options.c
@@ -0,0 +1,804 @@
+/*
+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 <stdio.h>
+#include <tchar.h>
+#define _WIN32_WINNT 0x0500
+#define __RPCASYNC_H__ /* header shows warnings in VS6 */
+#include <windows.h>
+#pragma warning(disable:4201) /* nonstandard extension used : nameless struct/union */
+#include <commctrl.h>
+#pragma warning(default:4201) /* nonstandard extension used : nameless struct/union */
+#include <win2k.h>
+#define MIRANDA_VER 0x0600
+#include <newpluginapi.h>
+#include <m_system.h>
+#include <m_database.h>
+#include <m_langpack.h>
+#include <m_utils.h>
+#include <m_flags.h>
+#include "m_help.h"
+#include "help.h"
+
+#include <m_options.h>
+#include "resource.h"
+
+WORD settingAutoTipDelay; /* auto show help after those milliseconds, 0 if disabled */
+extern HINSTANCE hInst;
+static HANDLE hHookOptInit;
+static HWND hwndLangOpt;
+
+/**************************** LANGUAGE OPTS ***********************/
+
+/* these are only there for a short time to
+ * debug those radio buttons an Win9x */
+#define BOX(str) BOX2("%s (err:%i)",str,GetLastError())
+#define BOX2(fmt,p1,p2) { char str[256]; wsprintfA(str,fmt,p1,p2); MessageBoxA(NULL,str,"dbg",0); }
+
+// ImageList_Destroy() the return value
+// refresh on WM_THEMECHANGED
+static HIMAGELIST CreateRadioImages(COLORREF clrBk,COLORREF clrText)
+{
+ register HDC hdc,hdcScreen;
+ SIZE size;
+ RECT rc;
+ HBITMAP hbm,hbmPrev;
+ HIMAGELIST himl=NULL;
+
+ /* the WinXP+ themed way */
+ HMODULE hUxThemeDLL;
+ HTHEME (WINAPI *pfnOpenThemeData)(HWND,const WCHAR*);
+ HTHEME (WINAPI *pfnCloseThemeData)(HTHEME);
+ HRESULT (WINAPI *pfnDrawThemeBackground)(HTHEME,HDC,int,int,const RECT*,const RECT*);
+ hUxThemeDLL=LoadLibraryA("UXTHEME"); /* all ascii */
+
+ /* draw bitmap */
+ hdcScreen=GetDC(NULL);
+ if(hdcScreen!=NULL) {
+ hdc=CreateCompatibleDC(NULL); /* compatible to screen */
+ if(hdc!=NULL) {
+ size.cx=GetSystemMetrics(SM_CXSMICON);
+ size.cy=GetSystemMetrics(SM_CYSMICON);
+ SetRect(&rc,0,0,2*size.cx,size.cy);
+ hbm=CreateCompatibleBitmap(hdcScreen,rc.right,rc.bottom);
+ if(hbm!=NULL) {
+ hbmPrev=SelectObject(hdc,hbm);
+ if(hbmPrev!=NULL) { /* error on select? */
+ /* the WinXP+ themed way */
+ if(hUxThemeDLL!=NULL) {
+ *(PROC*)&pfnOpenThemeData=GetProcAddress(hUxThemeDLL,"OpenThemeData");
+ *(PROC*)&pfnCloseThemeData=GetProcAddress(hUxThemeDLL,"CloseThemeData");
+ *(PROC*)&pfnDrawThemeBackground=GetProcAddress(hUxThemeDLL,"DrawThemeBackground");
+ if(pfnOpenThemeData!=NULL && pfnCloseThemeData!=NULL && pfnDrawThemeBackground!=NULL) {
+ HTHEME hTheme;
+ hTheme=pfnOpenThemeData(NULL,L"Button");
+ if(hTheme!=NULL) {
+ SetRect(&rc,0,0,size.cx,size.cy);
+ /* unchecked */
+ if(!pfnDrawThemeBackground(hTheme,hdc,BP_RADIOBUTTON,RBS_UNCHECKEDNORMAL,&rc,NULL)) {
+ /* checked */
+ OffsetRect(&rc,size.cx,0);
+ if(!pfnDrawThemeBackground(hTheme,hdc,BP_RADIOBUTTON,RBS_CHECKEDNORMAL,&rc,NULL))
+ himl=ImageList_Create(size.cx,size.cy,ILC_COLOR32|ILC_MASK,3,0);
+ }
+ pfnCloseThemeData(hTheme);
+ }
+ }
+ }
+ /* the classic way */
+ if(himl==NULL) {
+ register HDC hdcMono;
+ HBITMAP hbmMono,hbmPrevMono;
+ RECT rcRadio;
+ COLORREF clrPrevText,clrPrevBk;
+ HBRUSH hbrBk;
+ hbrBk=CreateSolidBrush(clrBk);
+ if(hbrBk!=NULL) {
+ FillRect(hdc,&rc,hbrBk);
+ DeleteObject(hbrBk);
+ hdcMono=CreateCompatibleDC(hdc);
+ if(hdcMono!=NULL) {
+ hbmMono=CreateBitmap(rc.right,rc.bottom,1,1,NULL);
+ if(hbmMono!=NULL) {
+ hbmPrevMono=SelectObject(hdcMono,hbmMono);
+ if(hbmPrevMono!=NULL) { /* error on select? */
+ /* draws a black-and-white mask (see docs)
+ * we need to colorize it using BitBlt with text and background color */
+ clrPrevText=SetTextColor(hdc,clrText);
+ clrPrevBk=SetBkColor(hdc,clrBk);
+ /* check mark is slightly smaller than icon size */
+ SetRect(&rcRadio,0,0,GetSystemMetrics(SM_CXMENUCHECK),GetSystemMetrics(SM_CYMENUCHECK));
+ if(rcRadio.right>size.cx) rcRadio.right=size.cx;
+ if(rcRadio.bottom>size.cy) rcRadio.bottom=size.cy;
+ SetRect(&rc,((size.cx-rcRadio.right)/2)+1,((size.cy-rcRadio.bottom)/2)+1,rcRadio.right+1,rcRadio.bottom+1);
+ /* unchecked */
+ if(BitBlt(hdcMono,0,0,rcRadio.right,rcRadio.bottom,NULL,0,0,WHITENESS)) { /* white back */
+ if(DrawFrameControl(hdcMono,&rcRadio,DFC_BUTTON,DFCS_BUTTONRADIO|DFCS_FLAT)) {
+ if(BitBlt(hdc,rc.left,rc.top,rcRadio.right,rcRadio.bottom,hdcMono,0,0,SRCCOPY|NOMIRRORBITMAP)) {
+ /* checked */
+ OffsetRect(&rc,size.cx,0);
+ if(BitBlt(hdcMono,0,0,rcRadio.right,rcRadio.bottom,NULL,0,0,WHITENESS)) {/* white back */
+ if(DrawFrameControl(hdcMono,&rcRadio,DFC_BUTTON,DFCS_BUTTONRADIO|DFCS_FLAT|DFCS_CHECKED)) {
+ if(BitBlt(hdc,rc.left,rc.top,rcRadio.right,rcRadio.bottom,hdcMono,0,0,SRCCOPY|NOMIRRORBITMAP)) {
+ himl=ImageList_Create(size.cx,size.cy,ILC_COLOR|ILC_MASK,3,0);
+ if(himl==NULL) BOX("img list creation failed");
+ }
+ } else BOX("second DrawFrameControl() failed");
+ } else BOX("second BitBlt() failed");
+ } else BOX("intermediate BitBlt() failed");
+ } else BOX("DrawFrameControl() failed");
+ } else BOX("first BitBlt() failed");
+ /* restore */
+ SetBkColor(hdc,clrPrevBk);
+ SetTextColor(hdc,clrPrevText);
+ SelectObject(hdcMono,hbmPrevMono);
+ } else BOX("hbmPrevMono==NULL");
+ DeleteObject(hbmMono);
+ } else BOX("hbmMono==NULL");
+ DeleteDC(hdcMono);
+ } else BOX("hdcMono==NULL");
+ }
+ }
+ SelectObject(hdc,hbmPrev);
+ /* create imagelist */
+ if(himl!=NULL) {
+ if(ImageList_AddMasked(himl,hbm,clrBk)==-1) BOX("addmasked failed");
+ } else BOX("Win9x: drawing code not reached");
+ }
+ DeleteObject(hbm);
+ }
+ DeleteDC(hdc);
+ }
+ ReleaseDC(NULL,hdcScreen);
+ }
+
+ if(hUxThemeDLL!=NULL) FreeLibrary(hUxThemeDLL);
+ return himl;
+}
+
+static void CleanupPluginName(char *szShortName)
+{
+ char *p;
+ int len;
+ /* strip-off anything in brackets */
+ for(p=szShortName;*p!='\0';++p)
+ if(*p=='(' || *p=='[') {
+ *p='\0';
+ break;
+ }
+ /* remove trailing space */
+ len=lstrlenA(szShortName);
+ while(szShortName[0]!='\0' && szShortName[len-1]==' ')
+ szShortName[--len]=0;
+}
+
+static void DisplayNotIncludedPlugins(HWND hwndListBox,const HELPPACK_INFO *pack)
+{
+ WIN32_FIND_DATA wfd;
+ HANDLE hFind;
+ TCHAR szSearch[MAX_PATH],szDir[MAX_PATH],*p;
+ HMODULE hModule;
+ BOOL fNeedsFree;
+ char buf[128];
+ TCHAR buf2[128];
+ DWORD mirandaVersion;
+ PLUGININFO *pluginInfo;
+ PLUGININFO *(__cdecl *MirandaPluginInfo)(DWORD);
+
+ /* enum plugins */
+ if(GetModuleFileName(NULL,szDir,SIZEOF(szDir))) {
+ p=_tcsrchr(szDir,_T('\\'));
+ if(p!=NULL) *p=_T('\0');
+ mir_sntprintf(szSearch,SIZEOF(szSearch),_T("%s\\Plugins\\*.dll"),szDir);
+ hFind=FindFirstFile(szSearch, &wfd);
+ if(hFind!=INVALID_HANDLE_VALUE) {
+ mirandaVersion=CallService(MS_SYSTEM_GETVERSION,0,0);
+ SendMessage(hwndListBox,LB_SETLOCALE,CallService(MS_LANGPACK_GETLOCALE,0,0),0); /* for sort order */
+ SendMessage(hwndListBox,LB_INITSTORAGE,128,lstrlenA(pack->szPluginsIncluded)); /* speed up */
+ do {
+ if(wfd.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) continue;
+ if((lstrlen(wfd.cFileName)<4) || (wfd.cFileName[lstrlen(wfd.cFileName)-4]!=_T('.'))) continue;
+ /* file name */
+ lstrcpy(szSearch,wfd.cFileName); /* buffer safe */
+ p=_tcsrchr(szSearch,_T('.'));
+ if(p!=NULL) *p=_T('\0');
+#if defined(_UNICODE)
+ { char cFileNameA[MAX_PATH];
+ cFileNameA[0]='\0';
+ WideCharToMultiByte(CP_ACP,0,szSearch,-1,cFileNameA,sizeof(cFileNameA),NULL,NULL);
+ if(IsPluginIncluded(pack,cFileNameA)) continue;
+ }
+#else
+ if(IsPluginIncluded(pack,szSearch)) continue;
+#endif
+ /* friendly name of the plugin */
+ mir_sntprintf(szSearch,SIZEOF(szSearch),_T("%s\\Plugins\\%s"),szDir,wfd.cFileName);
+ hModule=GetModuleHandle(szSearch);
+ fNeedsFree=(hModule==NULL);
+ if(hModule==NULL) {
+ hModule=LoadLibrary(szSearch);
+ if(hModule==NULL) continue;
+ }
+ /* plugin info */
+ *(PROC*)&MirandaPluginInfo=GetProcAddress(hModule,"MirandaPluginInfo");
+ if(MirandaPluginInfo==NULL) /* v0.8 support */
+ *(PROC*)&MirandaPluginInfo=GetProcAddress(hModule,"MirandaPluginInfoEx");
+ if(MirandaPluginInfo!=NULL) { /* both structs have the same header */
+ pluginInfo=MirandaPluginInfo(mirandaVersion);
+ if(pluginInfo!=NULL && pluginInfo->cbSize>=sizeof(PLUGININFO) && pluginInfo->shortName!=NULL) {
+ lstrcpynA(buf,pluginInfo->shortName,sizeof(buf)); /* buffer safe */
+ CleanupPluginName(buf);
+ mir_sntprintf(buf2,SIZEOF(buf2),TranslateT("%hs (%s)"),buf,CharLower(wfd.cFileName));
+ SendMessage(hwndListBox,LB_ADDSTRING,0,(LPARAM)buf2);
+ }
+ }
+ if(fNeedsFree) FreeLibrary(hModule);
+ } while(FindNextFile(hFind,&wfd));
+ FindClose(hFind);
+ }
+ }
+ /* all are included? */
+ if(!SendMessage(hwndListBox,LB_GETCOUNT,0,0))
+ SendMessage(hwndListBox,LB_ADDSTRING,0,(LPARAM)TranslateT("All installed plugins are included."));
+}
+
+// pack is allowed to be NULL
+static void DisplayPackInfo(HWND hwndDlg,const HELPPACK_INFO *pack)
+{
+ /* show/hide controls */
+ if(IsWindowVisible(GetDlgItem(hwndDlg,IDC_NOPACK))==(pack!=NULL)) {
+ const int controls[]={IDC_LANGNOTINCLUDEDLABEL,IDC_LANGNOTINCLUDED,IDC_LANGDATELABEL,IDC_LANGDATE,
+ IDC_LANGLOCALELABEL,IDC_LANGLOCALE,IDC_LANGVERSIONLABEL,IDC_LANGVERSION,
+ IDC_LANGMODUSINGLABEL,IDC_LANGMODUSING,IDC_LANGAUTHORSLABEL,IDC_LANGAUTHORS,
+ IDC_LANGEMAILLABEL,IDC_LANGEMAIL};
+ int i;
+ for(i=0;i<SIZEOF(controls);i++)
+ ShowWindow(GetDlgItem(hwndDlg,controls[i]),(pack!=NULL)?SW_SHOW:SW_HIDE);
+ ShowWindow(GetDlgItem(hwndDlg,IDC_NOPACK),(pack!=NULL)?SW_HIDE:SW_SHOW);
+ SetDlgItemText(hwndDlg,IDC_LANGINFOFRAME,NULL);
+ }
+ if(pack==NULL) return;
+ /* compute not-included from included list */
+ SendDlgItemMessage(hwndDlg,IDC_LANGNOTINCLUDED,LB_RESETCONTENT,0,0);
+ DisplayNotIncludedPlugins(GetDlgItem(hwndDlg,IDC_LANGNOTINCLUDED),pack);
+ /* locale string */
+ if(!(pack->flags&HPF_NOLOCALE)) {
+ TCHAR szLocaleName[128];
+ szLocaleName[0]=_T('\0');
+ /* can't use LOCALE_SNAME as it is not present on pre WinVista */
+ if(!GetLocaleInfo(pack->Locale,LOCALE_SISO639LANGNAME,szLocaleName,SIZEOF(szLocaleName))) { /* Win98/NT4+ */
+ if(!GetLocaleInfo(pack->Locale,LOCALE_SLANGUAGE,szLocaleName,SIZEOF(szLocaleName))) /* not unique! */
+ szLocaleName[0]=_T('\0');
+ } else {
+ if(GetLocaleInfo(pack->Locale,LOCALE_SISO3166CTRYNAME,&szLocaleName[3],SIZEOF(szLocaleName)-3)) /* Win98/NT4+ */
+ szLocaleName[2]=_T('-');
+ }
+ /* add some note if its incompatible */
+ if(szLocaleName[0]) {
+ if(!IsValidLocale(pack->Locale,LCID_INSTALLED)) {
+ TCHAR *pszIncompat;
+ pszIncompat=TranslateT("(incompatible)");
+ szLocaleName[SIZEOF(szLocaleName)-lstrlen(pszIncompat)-1]=0;
+ lstrcat(lstrcat(szLocaleName,_T(" ")),pszIncompat); /* buffer safe */
+ }
+ SetDlgItemText(hwndDlg,IDC_LANGLOCALE,szLocaleName);
+ }
+ else SetDlgItemText(hwndDlg,IDC_LANGLOCALE,TranslateT("Unknown"));
+ }
+ else SetDlgItemText(hwndDlg,IDC_LANGLOCALE,TranslateT("Current"));
+ /* file date */
+ { SYSTEMTIME stFileDate;
+ TCHAR szDate[128];
+ szDate[0]=_T('\0');
+ if(FileTimeToSystemTime(&pack->ftFileDate,&stFileDate))
+ GetDateFormat((LCID)CallService(MS_LANGPACK_GETLOCALE,0,0),DATE_SHORTDATE,&stFileDate,NULL,szDate,SIZEOF(szDate));
+ SetDlgItemText(hwndDlg,IDC_LANGDATE,szDate);
+ }
+ /* version */
+ SetDlgItemTextA(hwndDlg,IDC_LANGVERSION,pack->szVersion);
+ if(pack->szVersion[0] && pack->szFLName[0]) {
+ if(!IsWindowVisible(GetDlgItem(hwndDlg,IDC_LANGVERSIONLABEL))) {
+ ShowWindow(GetDlgItem(hwndDlg,IDC_LANGVERSIONLABEL),SW_SHOW);
+ ShowWindow(GetDlgItem(hwndDlg,IDC_LANGVERSION),SW_SHOW);
+ }
+ } else {
+ ShowWindow(GetDlgItem(hwndDlg,IDC_LANGVERSIONLABEL),SW_HIDE);
+ ShowWindow(GetDlgItem(hwndDlg,IDC_LANGVERSION),SW_HIDE);
+ }
+ /* general */
+ SetDlgItemTextA(hwndDlg,IDC_LANGMODUSING,pack->szLastModifiedUsing);
+ SetDlgItemTextA(hwndDlg,IDC_LANGAUTHORS,pack->szAuthors);
+ SetDlgItemTextA(hwndDlg,IDC_LANGEMAIL,pack->szAuthorEmail);
+ SetDlgItemText(hwndDlg,IDC_LANGINFOFRAME,TranslateTS(pack->szLanguage));
+}
+
+#define M_RELOADLIST (WM_APP+1)
+#define M_SHOWFILECOL (WM_APP+2)
+
+static void DeletePackFile(HWND hwndDlg,HWND hwndList,int iItem,HELPPACK_INFO *pack)
+{
+ SHFILEOPSTRUCT sfo;
+ TCHAR szFileName[MAX_PATH];
+ ZeroMemory(&sfo,sizeof(sfo));
+ sfo.hwnd=hwndDlg;
+ sfo.wFunc=FO_DELETE;
+ sfo.fFlags=FOF_SIMPLEPROGRESS|FOF_SILENT; /* silent = no progress */
+ /* double zero terminated */
+ if(GetPackPath(szFileName,SIZEOF(szFileName)-1,pack->flags&HPF_ENABLED,pack->szFileName)) {
+ szFileName[lstrlen(szFileName)+1]=_T('\0');
+ sfo.pFrom=szFileName;
+ /* ask to delete file */
+ if(!SHFileOperation(&sfo) && !sfo.fAnyOperationsAborted) {
+ LVITEM lvi;
+ int nCount;
+ lvi.iItem=iItem;
+ lvi.iSubItem=0;
+ lvi.mask=LVIF_STATE;
+ lvi.stateMask=LVIS_STATEIMAGEMASK|LVIS_SELECTED|LVIS_FOCUSED;
+ if(ListView_GetItem(hwndList,&lvi)) {
+ ListView_DeleteItem(hwndList,iItem);
+ /* enable/select next item at same position */
+ nCount=ListView_GetItemCount(hwndList);
+ if(iItem<nCount) lvi.iItem=iItem;
+ else lvi.iItem=iItem-1;
+ if(lvi.iItem!=-1) {
+ ListView_SetItemState(hwndList,lvi.iItem,lvi.state,lvi.stateMask);
+ /* enable pack file */
+ lvi.mask=LVIF_PARAM;
+ lvi.iSubItem=0;
+ if(ListView_GetItem(hwndList,&lvi))
+ EnablePack((HELPPACK_INFO*)lvi.lParam,_T("helppack_*.txt"));
+ } else DisplayPackInfo(hwndDlg,NULL);
+ if(nCount==1) SendMessage(hwndDlg,M_SHOWFILECOL,0,FALSE);
+ }
+ }
+ }
+}
+
+static BOOL CALLBACK InsertPackItemEnumProc(HELPPACK_INFO *pack,WPARAM wParam,LPARAM lParam)
+{
+ LVITEM lvi;
+ HELPPACK_INFO *pack2;
+ UNREFERENCED_PARAMETER(lParam);
+
+ pack2=(HELPPACK_INFO*)mir_alloc(sizeof(HELPPACK_INFO));
+ if(pack2==NULL) return FALSE;
+ CopyMemory(pack2,pack,sizeof(HELPPACK_INFO));
+ /* country flag icon */
+ lvi.mask=LVIF_TEXT|LVIF_PARAM|LVIF_STATE;
+ if((HIMAGELIST)lParam!=NULL) {
+ HICON hIcon;
+ if(pack->flags&HPF_DEFAULT) /* not really needed, but to be consistent with LangMan */
+ hIcon=(HICON)CallService(MS_FLAGS_CREATEMERGEDFLAGICON,CTRY_UNITED_STATES,CTRY_UNITED_KINGDOM);
+ else {
+ int countryId=0xFFFF; /* Unknown */
+ TCHAR szBuf[6];
+ /* get country id from locale */
+ if(!(pack->flags&HPF_NOLOCALE))
+ if(GetLocaleInfo(pack->Locale,LOCALE_ICOUNTRY,szBuf,SIZEOF(szBuf)))
+ countryId=_ttoi(szBuf);
+ hIcon=(HICON)CallService(MS_FLAGS_LOADFLAGICON,countryId,0);
+ }
+ if(hIcon==NULL) lvi.iImage=-1;
+ else lvi.iImage=ImageList_AddIcon((HIMAGELIST)lParam,hIcon);
+ lvi.mask|=LVIF_IMAGE;
+ }
+ /* insert */
+ lvi.iItem=lvi.iSubItem=0;
+ lvi.stateMask=LVIS_STATEIMAGEMASK|LVIS_SELECTED;
+ lvi.state=INDEXTOSTATEIMAGEMASK((pack->flags&HPF_ENABLED)?2:1);
+ if(pack->flags&HPF_ENABLED) lvi.state|=LVIS_SELECTED|LVIS_FOCUSED;
+ lvi.pszText=TranslateTS(pack->szLanguage);
+ lvi.lParam=(LPARAM)pack2;
+ ListView_InsertItem((HWND)wParam,&lvi);
+
+ return TRUE;
+}
+
+static int CALLBACK CompareListItem(LPARAM lParam1,LPARAM lParam2,LPARAM lParamSort)
+{
+ int cmp;
+ cmp=CompareString((LCID)lParamSort,0,((HELPPACK_INFO*)lParam1)->szLanguage,-1,((HELPPACK_INFO*)lParam2)->szLanguage,-1);
+ if(cmp) cmp-=2;
+ if(!cmp) {
+ if(((HELPPACK_INFO*)lParam1)->flags&HPF_ENABLED) cmp=-1;
+ else if(((HELPPACK_INFO*)lParam2)->flags&HPF_ENABLED) cmp=1;
+ }
+ return cmp;
+}
+
+static BOOL CALLBACK LangOptDlgProc(HWND hwndDlg,UINT msg,WPARAM wParam,LPARAM lParam)
+{
+ switch(msg) {
+ case WM_INITDIALOG:
+ { HWND hwndList;
+ LVCOLUMN lvc;
+ hwndList=GetDlgItem(hwndDlg,IDC_LANGLIST);
+ hwndLangOpt=hwndDlg;
+ TranslateDialogDefault(hwndDlg);
+ ListView_SetExtendedListViewStyle(hwndList,LVS_EX_FULLROWSELECT|LVS_EX_LABELTIP);
+ ListView_SetImageList(hwndList,CreateRadioImages(ListView_GetBkColor(hwndList),ListView_GetTextColor(hwndList)),LVSIL_STATE); /* auto-destroyed */
+
+ lvc.mask=LVCF_TEXT;
+ lvc.pszText=TranslateT("Installed Languages");
+ ListView_InsertColumn(hwndList,0,&lvc);
+ if(ServiceExists(MS_FLAGS_LOADFLAGICON))
+ ListView_SetImageList(hwndList,ImageList_Create(GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),ILC_COLOR24,8,8),LVSIL_SMALL);
+ CorrectPacks(_T("helppack_*.txt"),_T("helppack_english.txt"),FALSE);
+ CheckDlgButton(hwndDlg,IDC_ENABLEHELPUPDATES,DBGetContactSettingByte(NULL,"HelpPlugin","EnableHelpUpdates",SETTING_ENABLEHELPUPDATES_DEFAULT)!=0);
+ SendMessage(hwndDlg,M_RELOADLIST,0,0);
+ SendMessage(hwndDlg,M_SHOWFILECOL,0,SendMessage(GetParent(hwndDlg),PSM_ISEXPERT,0,0));
+ return TRUE;
+ }
+ case M_RELOADLIST:
+ { HWND hwndList;
+ HIMAGELIST himl;
+ int iItem;
+ /* init list */
+ hwndList=GetDlgItem(hwndDlg,IDC_LANGLIST);
+ ListView_DeleteAllItems(hwndList);
+ ListView_DeleteColumn(hwndList,1); /* if present */
+ himl=ListView_GetImageList(hwndList,LVSIL_SMALL);
+ ImageList_RemoveAll(himl);
+ /* enum all packs */
+ EnumPacks(InsertPackItemEnumProc,_T("helppack_*.txt"),"Miranda Help Pack Version 1",(WPARAM)hwndList,(LPARAM)himl);
+ /* nothing installed */
+ if(!ListView_GetItemCount(hwndList)) DisplayPackInfo(hwndDlg,NULL);
+ /* make it use current langpack locale for sort */
+ ListView_SortItems(hwndList,CompareListItem,CallService(MS_LANGPACK_GETLOCALE,0,0));
+ CheckDlgButton(hwndDlg,IDC_ENABLEHELPUPDATES,DBGetContactSettingByte(NULL,"HelpPlugin","EnableHelpUpdates",SETTING_ENABLEHELPUPDATES_DEFAULT)!=0);
+ /* show selection */
+ iItem=ListView_GetNextItem(hwndList,-1,LVNI_SELECTED);
+ if(iItem!=-1) ListView_EnsureVisible(hwndList,iItem,FALSE);
+ return TRUE;
+ }
+ case M_SHOWFILECOL:
+ { HWND hwndList;
+ hwndList=GetDlgItem(hwndDlg,IDC_LANGLIST);
+ if((BOOL)lParam && ListView_GetItemCount(hwndList)>1) {
+ LVCOLUMN lvc;
+ LVITEM lvi;
+ HELPPACK_INFO *pack;
+ /* add column */
+ ListView_SetColumnWidth(hwndList,0,LVSCW_AUTOSIZE_USEHEADER);
+ lvc.mask=LVCF_TEXT|LVCF_WIDTH|LVCF_SUBITEM;
+ lvc.pszText=TranslateT("File");
+ lvc.cx=160;
+ ListView_InsertColumn(hwndList,lvc.iSubItem=1,&lvc);
+ ListView_SetColumnWidth(hwndList,0,ListView_GetColumnWidth(hwndList,0)-lvc.cx);
+ /* add text */
+ lvi.mask=LVIF_PARAM;
+ lvi.iSubItem=0;
+ for(lvi.iItem=0;ListView_GetItem(hwndList,&lvi);++lvi.iItem) {
+ pack=(HELPPACK_INFO*)lvi.lParam;
+ ListView_SetItemText(hwndList,lvi.iItem,1,pack->szFileName);
+ }
+ }
+ else {
+ ListView_DeleteColumn(hwndList,1);
+ ListView_SetColumnWidth(hwndList,0,LVSCW_AUTOSIZE_USEHEADER);
+ }
+ return TRUE;
+ }
+ case WM_THEMECHANGED:
+ case WM_SETTINGCHANGE:
+ { HIMAGELIST himl;
+ HWND hwndList;
+ hwndList=GetDlgItem(hwndDlg,IDC_LANGLIST);
+ himl=ListView_SetImageList(hwndList,CreateRadioImages(ListView_GetBkColor(hwndList),ListView_GetTextColor(hwndList)),LVSIL_STATE); /* auto-destroyed */
+ if(himl!=NULL) ImageList_Destroy(himl);
+ break;
+ }
+ case WM_CTLCOLORLISTBOX: /* mimic readonly edit */
+ return (BOOL)SendMessage(hwndDlg,WM_CTLCOLORSTATIC,wParam,lParam);
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDC_LANGEMAIL:
+ { char buf[512];
+ lstrcpyA(buf,"mailto:");
+ if(GetWindowTextA(GetDlgItem(hwndDlg,LOWORD(wParam)),&buf[7],sizeof(buf)-7))
+ CallService(MS_UTILS_OPENURL,FALSE,(LPARAM)buf);
+ return TRUE;
+ }
+ case IDC_MORELANG:
+ CallService(MS_UTILS_OPENURL,TRUE,(LPARAM)"http://addons.miranda-im.org/index.php?action=display&id=23");
+ return TRUE;
+ case IDC_ENABLEHELPUPDATES:
+ SendMessage(GetParent(hwndDlg),PSM_CHANGED,0,0); /* enable apply */
+ return TRUE;
+ case IDC_DOWNLOADLANG:
+ ServiceShowLangDialog(0,0);
+ return TRUE;
+ }
+ break;
+ case WM_CONTEXTMENU:
+ if(GetDlgCtrlID((HWND)wParam)==IDC_LANGLIST) {
+ LVHITTESTINFO hti;
+ HMENU hContextMenu;
+ RECT rc;
+ LVITEM lvi;
+ HELPPACK_INFO *pack;
+ /* get item */
+ POINTSTOPOINT(hti.pt,MAKEPOINTS(lParam));
+ if(hti.pt.x==-1 && hti.pt.y==-1) {
+ /* keyboard invoked */
+ hti.iItem=ListView_GetNextItem((HWND)wParam,-1,LVNI_SELECTED);
+ if(hti.iItem!=-1)
+ break;
+ if(!ListView_GetItemRect((HWND)wParam,hti.iItem,&rc,LVIR_SELECTBOUNDS))
+ break;
+ hti.pt.x=rc.left+(rc.right-rc.left)/2;
+ hti.pt.y=rc.top+(rc.bottom-rc.top)/2;
+ ClientToScreen((HWND)wParam,&hti.pt);
+ } else {
+ ScreenToClient((HWND)wParam,&hti.pt);
+ if(ListView_HitTest((HWND)wParam,&hti)==-1 || !(hti.flags&LVHT_ONITEM))
+ break;
+ POINTSTOPOINT(hti.pt,MAKEPOINTS(lParam));
+ }
+ /* param */
+ lvi.iItem=hti.iItem;
+ lvi.iSubItem=0;
+ lvi.mask=LVIF_PARAM;
+ if(!ListView_GetItem((HWND)wParam,&lvi)) break;
+ pack=(HELPPACK_INFO*)lvi.lParam;
+ /* context menu */
+ hContextMenu=CreatePopupMenu();
+ if(hContextMenu!=NULL) {
+ AppendMenu(hContextMenu,MF_STRING,2,TranslateT("&Remove..."));
+ if(TrackPopupMenuEx(hContextMenu,TPM_RETURNCMD|TPM_NONOTIFY|TPM_TOPALIGN|TPM_LEFTALIGN|TPM_RIGHTBUTTON|TPM_HORPOSANIMATION|TPM_VERPOSANIMATION,hti.pt.x,hti.pt.y,(HWND)wParam,NULL))
+ DeletePackFile(hwndDlg,(HWND)wParam,hti.iItem,pack);
+ DestroyMenu(hContextMenu);
+ }
+ return TRUE;
+ }
+ break;
+#if defined(_UNICODE)
+ case WM_NOTIFYFORMAT:
+ SetWindowLong(hwndDlg,DWL_MSGRESULT,NFR_UNICODE);
+ return TRUE;
+#endif
+ case WM_NOTIFY:
+ { NMHDR *nmhdr=(NMHDR*)lParam;
+ switch(nmhdr->idFrom) {
+ case IDC_LANGLIST:
+ switch(nmhdr->code) {
+ case LVN_DELETEITEM:
+ { LVITEM lvi;
+ lvi.iItem=((NMLISTVIEW*)lParam)->iItem; /* nmlv->lParam is invalid */
+ lvi.iSubItem=0;
+ lvi.mask=LVIF_PARAM;
+ if(ListView_GetItem(nmhdr->hwndFrom,&lvi))
+ mir_free((HELPPACK_INFO*)lvi.lParam);
+ break;
+ }
+ case LVN_ITEMCHANGED:
+ { NMLISTVIEW *nmlv=(NMLISTVIEW*)lParam;
+ if(!(nmlv->uChanged&LVIF_STATE)) break;
+ /* display info and check radio item */
+ if(nmlv->uNewState&LVIS_SELECTED && !(nmlv->uOldState&LVIS_SELECTED)) {
+ ListView_SetItemState(nmhdr->hwndFrom,nmlv->iItem,INDEXTOSTATEIMAGEMASK(2),LVIS_STATEIMAGEMASK);
+ DisplayPackInfo(hwndDlg,(HELPPACK_INFO*)nmlv->lParam);
+ }
+ /* disable all other radio items */
+ else if(nmlv->uNewState&INDEXTOSTATEIMAGEMASK(2)) {
+ int iItem;
+ for(iItem=ListView_GetItemCount(nmhdr->hwndFrom)-1;iItem!=-1;--iItem)
+ if(iItem!=nmlv->iItem)
+ ListView_SetItemState(nmhdr->hwndFrom,iItem,INDEXTOSTATEIMAGEMASK(1),LVIS_STATEIMAGEMASK);
+ /* enable apply */
+ if(nmlv->uOldState)
+ SendMessage(GetParent(hwndDlg),PSM_CHANGED,0,0);
+ }
+ break;
+ }
+ case LVN_KEYDOWN:
+ { int iItem;
+ iItem=ListView_GetNextItem(nmhdr->hwndFrom,-1,LVNI_SELECTED);
+ switch(((NMLVKEYDOWN*)lParam)->wVKey) {
+ case VK_SPACE:
+ ListView_SetItemState(nmhdr->hwndFrom,iItem,INDEXTOSTATEIMAGEMASK(2),LVIS_STATEIMAGEMASK);
+ break;
+ case VK_DELETE:
+ { LVITEM lvi;
+ lvi.iItem=iItem;
+ lvi.iSubItem=0;
+ lvi.mask=LVIF_PARAM;
+ if(ListView_GetItem(nmhdr->hwndFrom,&lvi))
+ DeletePackFile(hwndDlg,nmhdr->hwndFrom,iItem,(HELPPACK_INFO*)lvi.lParam);
+ break;
+ }
+ }
+ break;
+ }
+ case NM_CLICK:
+ { LVHITTESTINFO hti;
+ lParam=GetMessagePos();
+ POINTSTOPOINT(hti.pt,MAKEPOINTS(lParam));
+ ScreenToClient(nmhdr->hwndFrom,&hti.pt);
+ if(ListView_HitTest(nmhdr->hwndFrom,&hti)!=-1)
+ if(hti.flags&(LVHT_ONITEMSTATEICON|LVHT_ONITEMICON)) /* one of them */
+ ListView_SetItemState(nmhdr->hwndFrom,hti.iItem,LVIS_SELECTED,LVIS_SELECTED);
+ break;
+ }
+ } /* switch nmhdr->code */
+ break;
+ case 0:
+ switch(nmhdr->code) {
+ case PSN_APPLY:
+ { HWND hwndList;
+ LVITEM lvi;
+ HELPPACK_INFO *pack;
+ hwndList=GetDlgItem(hwndDlg,IDC_LANGLIST);
+ lvi.mask=LVIF_STATE|LVIF_PARAM;
+ lvi.stateMask=LVIS_STATEIMAGEMASK;
+ lvi.iSubItem=0;
+ for(lvi.iItem=0;ListView_GetItem(hwndList,&lvi);++lvi.iItem) {
+ pack=(HELPPACK_INFO*)lvi.lParam;
+ if(lvi.state&INDEXTOSTATEIMAGEMASK(2)) {
+ EnablePack(pack,_T("helppack_*.txt"));
+ pack->flags|=HPF_ENABLED;
+ } else pack->flags&=~HPF_ENABLED;
+ }
+ DBWriteContactSettingByte(NULL,"HelpPlugin","EnableAutoUpdates",(BYTE)(IsDlgButtonChecked(hwndDlg,IDC_ENABLEHELPUPDATES)!=0));
+ return TRUE;
+ }
+ case PSN_EXPERTCHANGED:
+ SendMessage(hwndDlg,M_SHOWFILECOL,0,((PSHNOTIFY*)lParam)->lParam);
+ return TRUE;
+ } /* switch nmhdr->code */
+ break;
+ } /* switch nmhdr->idFrom */
+ break;
+ }
+ }
+ return FALSE;
+}
+
+void ReloadLangOptList(void)
+{
+ if(hwndLangOpt!=NULL) {
+ SendMessage(hwndLangOpt,M_RELOADLIST,0,0);
+ SendMessage(hwndLangOpt,M_SHOWFILECOL,0,SendMessage(GetParent(hwndLangOpt),PSM_ISEXPERT,0,0));
+ }
+}
+
+/**************************** ADV OPTS ****************************/
+
+static BOOL CALLBACK AdvOptDlgProc(HWND hwndDlg,UINT msg,WPARAM wParam,LPARAM lParam)
+{
+ switch(msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ { WORD val=settingAutoTipDelay;
+ if(!val) val=DBGetContactSettingWord(NULL,"HelpPlugin","AutoTipDelay",SETTING_AUTOTIPDELAY_DEFAULT);
+ CheckDlgButton(hwndDlg,IDC_AUTOTIPSENABLED,settingAutoTipDelay!=0);
+ SendDlgItemMessage(hwndDlg,IDC_AUTOTIPDELAYSPIN,UDM_SETRANGE,0,MAKELPARAM(10000,500));
+ SendDlgItemMessage(hwndDlg,IDC_AUTOTIPDELAY,EM_SETLIMITTEXT,(WPARAM)5,0);
+ { UDACCEL uda={0,500};
+ SendDlgItemMessage(hwndDlg,IDC_AUTOTIPDELAYSPIN,UDM_SETACCEL,1,(LPARAM)&uda);
+ }
+ SetDlgItemInt(hwndDlg,IDC_AUTOTIPDELAY,val,FALSE);
+ SendDlgItemMessage(hwndDlg,IDC_AUTOTIPDELAYSPIN,UDM_SETPOS,0,MAKELPARAM(val,0));
+ EnableWindow(GetDlgItem(hwndDlg,IDC_AUTOTIPDELAYLABEL),settingAutoTipDelay!=0);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_AUTOTIPDELAY),settingAutoTipDelay!=0);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_AUTOTIPDELAYSPIN),settingAutoTipDelay!=0);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_AUTOTIPDELAYMS),settingAutoTipDelay!=0);
+ }
+ return TRUE;
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDC_AUTOTIPSENABLED:
+ { BOOL checked=IsDlgButtonChecked(hwndDlg,IDC_AUTOTIPSENABLED);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_AUTOTIPDELAYLABEL),checked);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_AUTOTIPDELAY),checked);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_AUTOTIPDELAYSPIN),checked);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_AUTOTIPDELAYMS),checked);
+ break;
+ }
+ case IDC_AUTOTIPDELAY:
+ if(HIWORD(wParam)==EN_KILLFOCUS) {
+ WORD minVal=HIWORD(SendDlgItemMessage(hwndDlg,IDC_AUTOTIPDELAYSPIN,UDM_GETRANGE,0,0));
+ if(GetDlgItemInt(hwndDlg,IDC_AUTOTIPDELAY,NULL,FALSE)<minVal) {
+ SetDlgItemInt(hwndDlg,IDC_AUTOTIPDELAY,minVal,FALSE);
+ SendDlgItemMessage(hwndDlg,IDC_AUTOTIPDELAYSPIN,UDM_SETPOS,0,MAKELPARAM(minVal,0));
+ }
+ }
+ if(HIWORD(wParam)!=EN_CHANGE || (HWND)lParam!=GetFocus()) return TRUE;
+ break;
+ }
+ PostMessage(GetParent(hwndDlg),PSM_CHANGED,0,0); // enable apply
+ break;
+#if defined(_UNICODE)
+ case WM_NOTIFYFORMAT:
+ SetWindowLong(hwndDlg,DWL_MSGRESULT,NFR_UNICODE);
+ return TRUE;
+#endif
+ case WM_NOTIFY:
+ switch(((LPNMHDR)lParam)->idFrom) {
+ case 0:
+ switch(((LPNMHDR)lParam)->code) {
+ case PSN_APPLY:
+ { WORD minVal;
+ minVal=HIWORD(SendDlgItemMessage(hwndDlg,IDC_AUTOTIPDELAYSPIN,UDM_GETRANGE,0,0));
+ if(GetDlgItemInt(hwndDlg,IDC_AUTOTIPDELAY,NULL,FALSE) < minVal) {
+ SetDlgItemInt(hwndDlg,IDC_AUTOTIPDELAY,minVal,FALSE);
+ SendDlgItemMessage(hwndDlg,IDC_AUTOTIPDELAYSPIN,UDM_SETPOS,0,MAKELPARAM(minVal,0));
+ }
+ settingAutoTipDelay=(WORD)GetDlgItemInt(hwndDlg,IDC_AUTOTIPDELAY,NULL,FALSE);
+ DBWriteContactSettingWord(NULL,"HelpPlugin","AutoTipDelay",settingAutoTipDelay);
+
+ if(!IsDlgButtonChecked(hwndDlg,IDC_AUTOTIPSENABLED)) settingAutoTipDelay=0;
+ DBWriteContactSettingByte(NULL,"HelpPlugin","AutoTipsEnabled",(BYTE)(settingAutoTipDelay!=0));
+ return TRUE;
+ }
+ }
+ break;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+/**************************** INIT ********************************/
+
+static int HelpOptInit(WPARAM wParam,LPARAM lParam)
+{
+ OPTIONSDIALOGPAGE odp;
+ UNREFERENCED_PARAMETER(lParam);
+ ZeroMemory(&odp,sizeof(odp));
+ odp.cbSize=sizeof(odp);
+ odp.position=1200000080; /* plugin opts=1300000000, lang opts=1200000090 */
+ odp.hInstance=hInst;
+ odp.ptszGroup=_T("Customize"); /* autotranslated */
+ odp.ptszTitle=_T("Help"); /* autotranslated */
+
+ odp.ptszTab=_T("Language"); /* autotranslated */
+ odp.flags=ODPF_TCHAR|ODPF_BOLDGROUPS;
+ odp.pszTemplate=MAKEINTRESOURCEA(IDD_OPT_LANG);
+ odp.pfnDlgProc=LangOptDlgProc;
+ CallService(MS_OPT_ADDPAGE,wParam,(LPARAM)&odp);
+
+#ifdef EDITOR
+ odp.ptszTab=_T("Help Editor"); /* autotranslated */
+#else
+ odp.ptszTab=_T("Advanced"); /* autotranslated */
+#endif
+ odp.flags|=ODPF_EXPERTONLY;
+ odp.pszTemplate=MAKEINTRESOURCEA(IDD_OPT_ADV);
+ odp.pfnDlgProc=AdvOptDlgProc;
+ CallService(MS_OPT_ADDPAGE,wParam,(LPARAM)&odp);
+ return 0;
+}
+
+void InitOptions(void)
+{
+ settingAutoTipDelay=0;
+ if(DBGetContactSettingByte(NULL,"HelpPlugin","AutoTipsEnabled",SETTING_AUTOTIPSENABLED_DEFAULT))
+ settingAutoTipDelay=DBGetContactSettingWord(NULL,"HelpPlugin","AutoTipDelay",SETTING_AUTOTIPDELAY_DEFAULT);
+
+ hwndLangOpt=NULL;
+ hHookOptInit=HookEvent(ME_OPT_INITIALISE,HelpOptInit);
+ CorrectPacks(_T("helppack_*.txt"),_T("helppack_english.txt"),FALSE);
+}
+
+void UninitOptions(void)
+{
+ UnhookEvent(hHookOptInit);
+} \ No newline at end of file
diff --git a/Help/resource.h b/Help/resource.h
new file mode 100644
index 0000000..e9f9b06
--- /dev/null
+++ b/Help/resource.h
@@ -0,0 +1,61 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by resource.rc
+//
+#define IDD_HELP 101
+#define IDD_SHADOW 102
+#define IDD_OPT_LANG 103
+#define IDD_OPT_ADV 104
+#define IDD_UPDATENOTIFY 105
+#define IDD_DOWNLOADLANG 106
+#define IDC_CTLTEXT 1001
+#define IDC_TEXT 1002
+#define IDC_CTLTYPE 1003
+#define IDC_CTLID 1004
+#define IDC_MODULE 1005
+#define IDC_DLGID 1006
+#define IDC_CARETSUCKER 1007
+#define IDC_LANGLIST 1008
+#define IDC_LANGINFOFRAME 1009
+#define IDC_LANGAUTHORSLABEL 1010
+#define IDC_LANGAUTHORS 1011
+#define IDC_LANGEMAILLABEL 1012
+#define IDC_LANGEMAIL 1013
+#define IDC_LANGMODUSINGLABEL 1014
+#define IDC_LANGMODUSING 1015
+#define IDC_LANGDATELABEL 1016
+#define IDC_LANGDATE 1017
+#define IDC_LANGVERSIONLABEL 1018
+#define IDC_LANGVERSION 1019
+#define IDC_LANGLOCALELABEL 1020
+#define IDC_LANGLOCALE 1021
+#define IDC_LANGNOTINCLUDEDLABEL 1022
+#define IDC_LANGNOTINCLUDED 1023
+#define IDC_MORELANG 1024
+#define IDC_NOPACK 1025
+#define IDC_ENABLEHELPUPDATES 1026
+#define IDC_DOWNLOADLANG 1027
+#define IDC_LANGCOMBO 1028
+#define IDC_DOWNLOADALL 1029
+#define IDC_LOADING 1030
+#define IDC_LANGUAGELABEL 1031
+#define IDC_LANGUAGE 1032
+#define IDC_CURRENTVERSION 1033
+#define IDC_NEWVERSION 1034
+#define IDC_NEWVERSIONLABEL 1035
+#define IDC_AUTOTIPSENABLED 1036
+#define IDC_AUTOTIPDELAY 1037
+#define IDC_AUTOTIPDELAYSPIN 1038
+#define IDC_AUTOTIPDELAYLABEL 1039
+#define IDC_AUTOTIPDELAYMS 1040
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 107
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1041
+#define _APS_NEXT_SYMED_VALUE 2001
+#endif
+#endif
diff --git a/Help/resource.rc b/Help/resource.rc
new file mode 100644
index 0000000..7deb6cc
--- /dev/null
+++ b/Help/resource.rc
@@ -0,0 +1,300 @@
+//Microsoft Developer Studio generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include <winres.h>
+#include <richedit.h>
+#include <m_utils.h>
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// Englisch (GB) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "#include <winres.h>\r\n"
+ "#include <richedit.h>\r\n"
+ "#include <m_utils.h>\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "#include ""version.rc""\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+#if defined(APSTUDIO_INVOKED) || !defined(EDITOR)
+IDD_HELP DIALOGEX 0, 0, 203, 75
+STYLE DS_SETFOREGROUND | DS_FIXEDSYS | DS_NOFAILCREATE | WS_POPUP |
+ WS_BORDER
+EXSTYLE WS_EX_TOPMOST | WS_EX_TOOLWINDOW | WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "",IDC_CARETSUCKER,227,47,50,14
+ EDITTEXT IDC_CTLTEXT,3,3,197,10,ES_MULTILINE | ES_AUTOHSCROLL |
+ ES_READONLY | NOT WS_BORDER
+ CONTROL "",IDC_TEXT,"RichEdit20A",WS_VSCROLL | WS_TABSTOP |
+ 0x1844,3,13,197,59
+END
+#endif
+
+IDD_SHADOW DIALOGEX 0, 0, 203, 75
+STYLE WS_POPUP
+EXSTYLE WS_EX_TOPMOST | WS_EX_TOOLWINDOW | WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+END
+
+IDD_OPT_ADV DIALOGEX 0, 0, 191, 48
+STYLE DS_FIXEDSYS | DS_NOFAILCREATE | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Context Help",IDC_STATIC,0,0,191,48
+ CONTROL "&Automatically show help when hovered",
+ IDC_AUTOTIPSENABLED,"Button",BS_AUTOCHECKBOX | BS_TOP |
+ WS_GROUP | WS_TABSTOP,10,13,174,9
+ CONTROL "&Delay:",IDC_AUTOTIPDELAYLABEL,"Static",
+ SS_LEFTNOWORDWRAP,24,28,60,8
+ EDITTEXT IDC_AUTOTIPDELAY,84,26,41,13,ES_AUTOHSCROLL | ES_NUMBER
+ CONTROL "",IDC_AUTOTIPDELAYSPIN,"msctls_updown32",
+ UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY |
+ UDS_ARROWKEYS | UDS_NOTHOUSANDS | WS_TABSTOP,124,26,11,
+ 14
+ CONTROL "milliseconds",IDC_AUTOTIPDELAYMS,"Static",
+ SS_LEFTNOWORDWRAP | SS_NOPREFIX,136,28,48,8
+END
+
+#if defined(APSTUDIO_INVOKED) || defined(EDITOR)
+#if defined(APSTUDIO_INVOKED)
+IDD_HELP$(EDITOR) DIALOGEX 0, 0, 326, 144
+#else
+IDD_HELP DIALOGEX 0, 0, 326, 144
+#endif
+STYLE DS_SETFOREGROUND | DS_FIXEDSYS | DS_NOFAILCREATE | DS_CENTER |
+ WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Help"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ CONTROL "Ctl ID: %d",IDC_CTLID,"Static",SS_LEFTNOWORDWRAP |
+ WS_GROUP,5,5,76,8
+ RTEXT "Dialog ID: %s",IDC_DLGID,82,5,239,8,SS_NOPREFIX
+ CONTROL "Type: %s",IDC_CTLTYPE,"Static",SS_LEFTNOWORDWRAP |
+ WS_GROUP,5,15,76,8
+ RTEXT "Module: %s",IDC_MODULE,82,15,239,8,SS_NOPREFIX
+ EDITTEXT IDC_CTLTEXT,5,26,316,12,ES_AUTOHSCROLL
+ CONTROL "",IDC_TEXT,"RichEdit20A",WS_VSCROLL | WS_TABSTOP |
+ 0x1044,5,40,316,99,WS_EX_CLIENTEDGE
+END
+#endif
+
+IDD_UPDATENOTIFY DIALOG DISCARDABLE 0, 0, 259, 115
+STYLE DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE |
+ WS_CAPTION | WS_SYSMENU
+CAPTION "Help Pack Update Now Available"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "A new version of a Help Pack is now available. Click the install button to download and install this new update.",
+ IDC_STATIC,8,7,243,21,SS_NOPREFIX
+ CONTROL "Language:",IDC_LANGUAGELABEL,"Static",SS_SIMPLE |
+ SS_NOPREFIX | WS_GROUP,8,29,65,8
+ EDITTEXT IDC_LANGUAGE,78,29,173,8,ES_AUTOHSCROLL | ES_READONLY |
+ NOT WS_BORDER
+ CONTROL "Current:",IDC_STATIC,"Static",SS_SIMPLE | SS_NOPREFIX |
+ WS_GROUP,8,43,65,8
+ EDITTEXT IDC_CURRENTVERSION,78,43,173,8,ES_AUTOHSCROLL |
+ ES_READONLY | NOT WS_BORDER
+ CONTROL "New:",IDC_NEWVERSIONLABEL,"Static",SS_SIMPLE |
+ SS_NOPREFIX | WS_GROUP,8,58,65,8
+ EDITTEXT IDC_NEWVERSION,78,58,173,8,ES_AUTOHSCROLL | ES_READONLY |
+ NOT WS_BORDER
+ PUSHBUTTON "&Install Now",IDOK,7,73,66,15,WS_GROUP
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,7,92,245,1
+ DEFPUSHBUTTON "Close",IDCANCEL,202,96,50,15
+END
+
+IDD_DOWNLOADLANG DIALOG DISCARDABLE 0, 0, 200, 126
+STYLE DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE |
+ WS_CAPTION | WS_SYSMENU
+CAPTION "Select your help language"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "Help is available in different languages.\nHere is a list of all available languages of the file listing, please select your native &language:",
+ IDC_STATIC,5,5,189,26
+ COMBOBOX IDC_LANGCOMBO,46,36,106,126,CBS_DROPDOWNLIST |
+ CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP
+ CONTROL "Download &all languages",IDC_DOWNLOADALL,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,46,53,148,10
+ LTEXT "Note: This will download and install the newest help pack available for the selected language. There might be help packs from other authors available on the file listing.",
+ IDC_STATIC,5,69,189,34,SS_NOPREFIX | WS_DISABLED
+ CTEXT "",IDC_LOADING,1,109,86,8,SS_NOPREFIX | SS_CENTERIMAGE |
+ NOT WS_VISIBLE
+ PUSHBUTTON "OK",IDOK,89,106,50,14,WS_DISABLED
+ DEFPUSHBUTTON "Cancel",IDCANCEL,144,106,50,15
+END
+
+IDD_OPT_LANG DIALOGEX 0, 0, 301, 227
+STYLE DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg"
+BEGIN
+ CONTROL "",IDC_LANGLIST,"SysListView32",LVS_REPORT |
+ LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_NOSORTHEADER |
+ WS_BORDER | WS_GROUP | WS_TABSTOP,2,3,299,61
+ GROUPBOX "",IDC_LANGINFOFRAME,2,68,298,119,WS_GROUP
+ CTEXT "No Help Pack installed!",IDC_NOPACK,5,75,289,108,
+ SS_NOPREFIX | SS_CENTERIMAGE | NOT WS_VISIBLE
+ RTEXT "Author(s):",IDC_LANGAUTHORSLABEL,5,78,66,9,SS_NOPREFIX
+ EDITTEXT IDC_LANGAUTHORS,74,78,220,18,ES_MULTILINE |
+ ES_AUTOVSCROLL | ES_READONLY | NOT WS_BORDER |
+ WS_VSCROLL
+ RTEXT "E-mail:",IDC_LANGEMAILLABEL,5,99,66,8,SS_NOPREFIX
+ CONTROL "",IDC_LANGEMAIL,"Hyperlink",WS_TABSTOP,76,99,207,10
+ RTEXT "Last modified using:",IDC_LANGMODUSINGLABEL,5,112,66,9,
+ SS_NOPREFIX
+ EDITTEXT IDC_LANGMODUSING,75,112,207,12,ES_AUTOHSCROLL |
+ ES_READONLY | NOT WS_BORDER
+ RTEXT "Date:",IDC_LANGDATELABEL,5,125,66,9,SS_NOPREFIX
+ EDITTEXT IDC_LANGDATE,75,125,66,12,ES_AUTOHSCROLL | ES_READONLY |
+ NOT WS_BORDER
+ RTEXT "Version:",IDC_LANGVERSIONLABEL,150,125,39,9,SS_NOPREFIX |
+ NOT WS_VISIBLE
+ EDITTEXT IDC_LANGVERSION,194,125,88,12,ES_AUTOHSCROLL |
+ ES_READONLY | NOT WS_VISIBLE | NOT WS_BORDER
+ RTEXT "Locale:",IDC_LANGLOCALELABEL,5,137,66,9,SS_NOPREFIX
+ EDITTEXT IDC_LANGLOCALE,75,137,207,12,ES_READONLY | NOT WS_BORDER
+ RTEXT "Not included:",IDC_LANGNOTINCLUDEDLABEL,5,150,66,10,
+ SS_NOPREFIX
+ LISTBOX IDC_LANGNOTINCLUDED,75,150,219,33,NOT LBS_NOTIFY |
+ LBS_SORT | LBS_HASSTRINGS | LBS_USETABSTOPS |
+ LBS_NOINTEGRALHEIGHT | LBS_DISABLENOSCROLL | NOT
+ WS_BORDER | WS_VSCROLL | WS_TABSTOP,WS_EX_TRANSPARENT
+ CONTROL "Download more Help Packs",IDC_MORELANG,"Hyperlink",
+ WS_GROUP | WS_TABSTOP | 0x1,2,191,299,10
+ CONTROL "Check for new &versions of Help Packs periodically",
+ IDC_ENABLEHELPUPDATES,"Button",BS_AUTOCHECKBOX |
+ WS_GROUP | WS_TABSTOP,2,214,209,10
+ PUSHBUTTON "&Download Language",IDC_DOWNLOADLANG,213,213,86,14,
+ WS_GROUP
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO DISCARDABLE
+BEGIN
+ IDD_HELP, DIALOG
+ BEGIN
+ LEFTMARGIN, 4
+ RIGHTMARGIN, 200
+ TOPMARGIN, 3
+ BOTTOMMARGIN, 72
+ END
+
+ IDD_SHADOW, DIALOG
+ BEGIN
+ RIGHTMARGIN, 201
+ BOTTOMMARGIN, 73
+ END
+
+ IDD_OPT_ADV, DIALOG
+ BEGIN
+ VERTGUIDE, 10
+ VERTGUIDE, 24
+ VERTGUIDE, 84
+ VERTGUIDE, 126
+ VERTGUIDE, 184
+ END
+
+ "IDD_HELP$(EDITOR)", DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 321
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 139
+ HORZGUIDE, 15
+ END
+
+ IDD_UPDATENOTIFY, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 252
+ VERTGUIDE, 74
+ TOPMARGIN, 7
+ END
+
+ IDD_DOWNLOADLANG, DIALOG
+ BEGIN
+ VERTGUIDE, 5
+ VERTGUIDE, 46
+ VERTGUIDE, 194
+ HORZGUIDE, 106
+ HORZGUIDE, 121
+ END
+
+ IDD_OPT_LANG, DIALOG
+ BEGIN
+ VERTGUIDE, 2
+ VERTGUIDE, 5
+ VERTGUIDE, 70
+ VERTGUIDE, 75
+ VERTGUIDE, 282
+ VERTGUIDE, 294
+ HORZGUIDE, 160
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+#endif // Englisch (GB) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+#include "version.rc"
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/Help/streaminout.c b/Help/streaminout.c
new file mode 100644
index 0000000..1f8f9b5
--- /dev/null
+++ b/Help/streaminout.c
@@ -0,0 +1,713 @@
+/*
+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 <tchar.h>
+#define __RPCASYNC_H__ /* header shows warnings in VS6 */
+#include <windows.h>
+#if !defined(VK_OEM_PLUS)
+#define _WIN32_WINNT 0x0500
+#include <win2k.h>
+#endif
+#define MIRANDA_VER 0x0600
+#include <newpluginapi.h>
+#include <m_system.h>
+#include "help.h"
+
+#include <richedit.h>
+
+struct EditStreamData {
+ PBYTE pbBuff;
+ int cbBuff;
+ int iCurrent;
+};
+
+#ifndef EDITOR
+struct HyperlinkData {
+ CHARRANGE range;
+ char *szLink;
+} static *hyperlink=NULL;
+static int hyperlinkCount=0;
+#endif
+
+static DWORD CALLBACK EditStreamInRtf(DWORD dwCookie,LPBYTE pbBuff,LONG cb,LONG *pcb)
+{
+ struct EditStreamData *esd=(struct EditStreamData*)dwCookie;
+ *pcb=min(esd->cbBuff-esd->iCurrent,cb);
+ CopyMemory(pbBuff,esd->pbBuff,*pcb);
+ esd->iCurrent+=*pcb;
+ return 0;
+}
+
+#ifdef EDITOR
+static DWORD CALLBACK EditStreamOutRtf(DWORD dwCookie,LPBYTE pbBuff,LONG cb,LONG *pcb)
+{
+ struct EditStreamData *esd=(struct EditStreamData*)dwCookie;
+ PBYTE buf=(PBYTE)mir_realloc(esd->pbBuff,esd->cbBuff+cb+1);
+ if(buf==NULL) return 0;
+ esd->pbBuff=buf;
+ esd->cbBuff+=cb;
+ CopyMemory(esd->pbBuff+esd->iCurrent,pbBuff,cb);
+ esd->iCurrent+=cb;
+ esd->pbBuff[esd->iCurrent]='\0';
+ *pcb=cb;
+ return 0;
+}
+#endif
+
+struct {
+ const char *szSym;
+ char ch;
+} static const htmlSymbolChars[]={
+ {"lt",'<'},
+ {"gt",'>'},
+ {"amp",'&'},
+ {"quot",'\"'},
+ {"nbsp",' '},
+};
+
+struct {
+ const char *szName;
+ const char *szClr;
+} static const htmlColourNames[]={
+ {"black","000000"},
+ {"maroon","800000"},
+ {"green","008000"},
+ {"olive","808000"},
+ {"navy","000080"},
+ {"purple","800080"},
+ {"teal","008080"},
+ {"silver","C0C0C0"},
+ {"gray","808080"},
+ {"red","FF0000"},
+ {"lime","00FF00"},
+ {"yellow","FFFF00"},
+ {"blue","0000FF"},
+ {"fuchsia","FF00FF"},
+ {"aqua","00FFFF"},
+ {"white","FFFFFF"},
+};
+
+// a quick test to see who's read their comp.lang.c FAQ:
+#define stringize2(n) #n
+#define stringize(n) stringize2(n)
+
+struct {
+ const char *szHtml;
+ const char *szRtf;
+} static const simpleHtmlRtfConversions[]={
+ {"i","i"},
+ {"/i","i0"},
+ {"b","b"},
+ {"/b","b0"},
+ {"u","ul"},
+ {"/u","ul0"},
+ {"big","fs" stringize(TEXTSIZE_BIG)},
+ {"/big","fs" stringize(TEXTSIZE_NORMAL)},
+ {"small","fs" stringize(TEXTSIZE_SMALL)},
+ {"/small","fs" stringize(TEXTSIZE_NORMAL)},
+ {"/font","cf0"}
+};
+
+// mir_free() the return value
+char *GetHtmlTagAttribute(const char *pszTag,const char *pszAttr)
+{
+ int iAttrName,iAttrNameEnd,iAttrEquals,iAttrValue,iAttrValueEnd,iAttrEnd;
+ int attrLen=lstrlenA(pszAttr);
+
+ for(iAttrName=0;!isspace(pszTag[iAttrName]) && pszTag[iAttrName]!='>';iAttrName++);
+ for(;;) {
+ for(;isspace(pszTag[iAttrName]);iAttrName++);
+ if(pszTag[iAttrName]=='>' || pszTag[iAttrName]=='\0') break;
+ for(iAttrNameEnd=iAttrName;isalnum(pszTag[iAttrNameEnd]);iAttrNameEnd++);
+ for(iAttrEquals=iAttrNameEnd;isspace(pszTag[iAttrEquals]);iAttrEquals++);
+ if(pszTag[iAttrEquals]!='=') {iAttrName=iAttrEquals; continue;}
+ for(iAttrValue=iAttrEquals+1;isspace(pszTag[iAttrValue]);iAttrValue++);
+ if(pszTag[iAttrValue]=='>' || pszTag[iAttrValue]=='\0') break;
+ if(pszTag[iAttrValue]=='"' || pszTag[iAttrValue]=='\'') {
+ for(iAttrValueEnd=iAttrValue+1;pszTag[iAttrValueEnd] && pszTag[iAttrValueEnd]!=pszTag[iAttrValue];iAttrValueEnd++);
+ iAttrValue++;
+ iAttrEnd=iAttrValueEnd+1;
+ }
+ else {
+ for(iAttrValueEnd=iAttrValue;pszTag[iAttrValueEnd] && pszTag[iAttrValueEnd]!='>' && !isspace(pszTag[iAttrValueEnd]);iAttrValueEnd++);
+ iAttrEnd=iAttrValueEnd;
+ }
+ if(pszTag[iAttrValueEnd]=='\0') break;
+ if(attrLen==iAttrNameEnd-iAttrName && !_strnicmp(pszAttr,pszTag+iAttrName,attrLen)) {
+ char *szValue;
+ szValue=(char*)mir_alloc(iAttrValueEnd-iAttrValue+1);
+ if(szValue!=NULL) {
+ CopyMemory(szValue,pszTag+iAttrValue,iAttrValueEnd-iAttrValue);
+ szValue[iAttrValueEnd-iAttrValue]='\0';
+ }
+ return szValue;
+ }
+ iAttrName=iAttrEnd;
+ }
+ return NULL;
+}
+
+void StreamInHtml(HWND hwndEdit,const char *szHtml,UINT codepage,COLORREF clrBkgrnd)
+{
+ EDITSTREAM stream;
+ struct EditStreamData esd;
+ struct ResizableCharBuffer header,body;
+ COLORREF *colourTbl=NULL;
+ int colourTblCount=0;
+ const char *pszHtml;
+ char *szThisTagHref=NULL;
+ int keywordAtBeginning=1,paragraphBefore=0,lineBreakBefore=1;
+ int charCount=0;
+
+ ZeroMemory(&stream,sizeof(stream));
+ ZeroMemory(&esd,sizeof(esd));
+ ZeroMemory(&header,sizeof(header));
+ ZeroMemory(&body,sizeof(body));
+
+#ifndef EDITOR
+ FreeHyperlinkData();
+#endif
+ AppendToCharBuffer(&header,"{\\rtf1\\ansi\\ansicpg%u\\deff0{\\fonttbl{\\f0 Tahoma;}}",codepage);
+ for(pszHtml=szHtml;*pszHtml!='\0';) {
+ if(*pszHtml=='<') {
+ const char *pszTagEnd;
+ int iNameEnd,i;
+ char szTagName[16];
+
+ pszTagEnd=strchr(pszHtml+1,'>');
+ if(pszTagEnd==NULL) break;
+ for(iNameEnd=1;pszHtml[iNameEnd]!='\0' && pszHtml[iNameEnd]!='>' && !isspace(pszHtml[iNameEnd]);iNameEnd++);
+ CopyMemory(szTagName,pszHtml+1,min(sizeof(szTagName),iNameEnd));
+ szTagName[min(sizeof(szTagName),iNameEnd)-1]='\0';
+
+ for(i=0;i<SIZEOF(simpleHtmlRtfConversions);i++) {
+ if(!lstrcmpiA(szTagName,simpleHtmlRtfConversions[i].szHtml)) {
+ AppendToCharBuffer(&body,"\\%s ",simpleHtmlRtfConversions[i].szRtf);
+ break;
+ }
+ }
+ if(i==SIZEOF(simpleHtmlRtfConversions)) {
+ if(!lstrcmpiA(szTagName,"br")) {
+ AppendToCharBuffer(&body,"\\par ");
+ charCount++; // linebreaks are characters
+ lineBreakBefore=1;
+ } else if(!lstrcmpiA(szTagName,"p") || !lstrcmpiA(szTagName,"/p")) {
+ if(charCount) paragraphBefore=1;
+ } else if(!lstrcmpiA(szTagName,"a")) {
+ mir_free(szThisTagHref); // does NULL check
+ szThisTagHref=GetHtmlTagAttribute(pszHtml,"href");
+#ifdef EDITOR
+ if(szThisTagHref!=NULL)
+ AppendToCharBuffer(&body,"\\strike ");
+#else
+ if(szThisTagHref!=NULL) {
+ struct HyperlinkData *buf=(struct HyperlinkData*)mir_realloc(hyperlink,sizeof(struct HyperlinkData)*(hyperlinkCount+1));
+ if(buf!=NULL) { // hyperlinkCount increased at </a>
+ hyperlink=buf;
+ hyperlink[hyperlinkCount].range.cpMin=paragraphBefore?(charCount+2):charCount;
+ hyperlink[hyperlinkCount].range.cpMax=-1;
+ hyperlink[hyperlinkCount].szLink=NULL;
+ } else {
+ mir_free(szThisTagHref);
+ szThisTagHref=NULL;
+ }
+ }
+#endif
+ }
+ else if(!lstrcmpiA(szTagName,"/a")) {
+ if(szThisTagHref) {
+#ifdef EDITOR
+ AppendToCharBuffer(&body,":%s\\strike0 ",szThisTagHref);
+ mir_free(szThisTagHref);
+#else
+#if defined(_UNICODE)
+ mir_utf8decodecp(szThisTagHref,CP_ACP,NULL);
+#endif
+ hyperlink[hyperlinkCount].range.cpMax=charCount;
+ hyperlink[hyperlinkCount].szLink=szThisTagHref;
+ hyperlinkCount++;
+#endif
+ szThisTagHref=NULL;
+ }
+ }
+ else if(!lstrcmpiA(szTagName,"font")) {
+ char *szColour=GetHtmlTagAttribute(pszHtml,"color");
+ if(szColour!=NULL) {
+ int i,freeColour=1;
+ if(szColour[0]!='#' || lstrlenA(szColour)!=7) {
+ for(i=0;i<SIZEOF(htmlColourNames);i++) {
+ if(!lstrcmpiA(szColour,htmlColourNames[i].szName)) {
+ mir_free(szColour);
+ szColour=(char*)htmlColourNames[i].szClr;
+ freeColour=0;
+ break;
+ }
+ }
+ } else szColour++;
+ if(szColour!=NULL) {
+ COLORREF colour;
+ char szRed[3],szGreen[3],szBlue[3];
+ szRed[0]=szColour[0]; szRed[1]=szColour[1]; szRed[2]='\0';
+ szGreen[0]=szColour[2]; szGreen[1]=szColour[3]; szGreen[2]='\0';
+ szBlue[0]=szColour[4]; szBlue[1]=szColour[5]; szBlue[2]='\0';
+ colour=RGB(strtol(szRed,NULL,16),strtol(szGreen,NULL,16),strtol(szBlue,NULL,16));
+ if(freeColour) mir_free(szColour);
+#ifndef EDITOR
+ if(colour!=clrBkgrnd) { // ensure color is visible
+#else
+ UNREFERENCED_PARAMETER(clrBkgrnd);
+#endif // !defined EDITOR
+ for(i=0;i<colourTblCount;i++)
+ if(colourTbl[i]==colour) break;
+ if(i==colourTblCount) {
+ COLORREF *buf=(COLORREF*)mir_realloc(colourTbl,(colourTblCount+1)*sizeof(COLORREF));
+ if(buf!=NULL) {
+ colourTbl=buf;
+ colourTblCount++;
+ colourTbl[i]=colour;
+ }
+ }
+ AppendToCharBuffer(&body,"\\cf%d ",i+2);
+#ifndef EDITOR
+ }
+#endif
+ }
+ }
+ } // endif font
+ }
+ pszHtml=pszTagEnd+1;
+ }
+ else if(*pszHtml=='&') {
+ const char *pszTagEnd;
+ char szTag[16];
+ int i;
+
+ pszTagEnd=strchr(pszHtml+1,';');
+ if(pszTagEnd==NULL) break;
+ CopyMemory(szTag,pszHtml+1,min(SIZEOF(szTag),pszTagEnd-pszHtml));
+ szTag[min(sizeof(szTag),pszTagEnd-pszHtml)-1]='\0';
+ if(szTag[0]=='#') {
+ int ch;
+ if(szTag[1]=='x' || szTag[1]=='X') ch=strtol(szTag+2,NULL,16);
+ else ch=strtol(szTag+1,NULL,10);
+ if(ch>=0x100) AppendToCharBuffer(&body,"\\u%d",ch);
+ else AppendToCharBuffer(&body,"\\'%02x ",ch);
+ }
+ else {
+ for(i=0;i<SIZEOF(htmlSymbolChars);i++) {
+ if(!lstrcmpiA(szTag,htmlSymbolChars[i].szSym)) {
+ AppendCharToCharBuffer(&body,htmlSymbolChars[i].ch);
+ charCount++;
+ break;
+ }
+ }
+ }
+ pszHtml=pszTagEnd+1;
+ }
+ else if(*pszHtml!=' ' || (!lineBreakBefore && !paragraphBefore)) {
+ lineBreakBefore=0;
+ if(paragraphBefore) {
+ AppendToCharBuffer(&body,"\\par\\par ");
+ charCount+=2; // linebreaks are characters
+ paragraphBefore=0;
+ }
+ if((BYTE)*pszHtml>=' ') charCount++;
+ if(*pszHtml=='\\' || *pszHtml=='{' || *pszHtml=='}')
+ AppendCharToCharBuffer(&body,'\\');
+ AppendCharToCharBuffer(&body,*pszHtml++);
+ }
+ else pszHtml++;
+ }
+ mir_free(szThisTagHref); // does NULL check
+
+ { int i;
+ COLORREF clr=GetSysColorBrush(COLOR_HOTLIGHT)?GetSysColor(COLOR_HOTLIGHT):RGB(0,0,255);
+ AppendToCharBuffer(&header,"{\\colortbl ;\\red%d\\green%d\\blue%d;",GetRValue(clr),GetGValue(clr),GetBValue(clr));
+ for(i=0;i<colourTblCount;i++)
+ AppendToCharBuffer(&header,"\\red%d\\green%d\\blue%d;",GetRValue(colourTbl[i]),GetGValue(colourTbl[i]),GetBValue(colourTbl[i]));
+ }
+ AppendToCharBuffer(&header,"}\\pard\\fs16\\uc0");
+ if(keywordAtBeginning) AppendCharToCharBuffer(&header,' ');
+ mir_free(colourTbl); // does NULL check
+
+ if(header.sz!=NULL) {
+ AppendToCharBuffer(&header,"%s}",body.sz?body.sz:"");
+ esd.pbBuff=(PBYTE)header.sz;
+ esd.cbBuff=header.iEnd;
+ stream.dwCookie=(DWORD)&esd;
+ stream.pfnCallback=EditStreamInRtf;
+ SendMessage(hwndEdit,EM_STREAMIN,SF_RTF,(LPARAM)&stream);
+ mir_free(header.sz);
+ }
+ mir_free(body.sz); // does NULL check
+
+#ifndef EDITOR
+ { int i;
+ CHARFORMAT cf;
+ ZeroMemory(&cf,sizeof(cf));
+ cf.cbSize=sizeof(cf);
+ cf.dwMask=CFM_UNDERLINE|CFM_COLOR; // CFE_LINK always uses RGB(0,0,255) instead of GetSysColor(COLOR_HOTLIGHT)
+ cf.dwEffects=CFE_UNDERLINE; // and ignores CFM_COLOR, so selfimplementing
+ cf.crTextColor=GetSysColorBrush(COLOR_HOTLIGHT)?GetSysColor(COLOR_HOTLIGHT):RGB(0,0,255);
+ for(i=0;i<hyperlinkCount;i++) {
+ SendMessage(hwndEdit,EM_EXSETSEL,0,(LPARAM)&hyperlink[i].range);
+ SendMessage(hwndEdit,EM_SETCHARFORMAT,SCF_SELECTION,(LPARAM)&cf);
+ }
+ SendMessage(hwndEdit,EM_SETSEL,0,0);
+ }
+#endif
+}
+
+#ifndef EDITOR
+void FreeHyperlinkData(void)
+{
+ int i;
+ for(i=0;i<hyperlinkCount;i++)
+ mir_free(hyperlink[i].szLink); // does NULL check
+ mir_free(hyperlink); // does NULL check
+ hyperlink=NULL;
+ hyperlinkCount=0;
+}
+
+int IsHyperlink(LONG cpPos,LONG *pcpMin,LONG *pcpMax,char **ppszLink)
+{
+ int i;
+ for(i=0;i<hyperlinkCount;i++)
+ if(cpPos>=hyperlink[i].range.cpMin && cpPos<=hyperlink[i].range.cpMax) {
+ if(pcpMin) *pcpMin=hyperlink[i].range.cpMin;
+ if(pcpMax) *pcpMax=hyperlink[i].range.cpMax;
+ if(ppszLink) *ppszLink=hyperlink[i].szLink;
+ return 1;
+ }
+ if(pcpMin) *pcpMin=-1;
+ if(pcpMax) *pcpMax=-1;
+ if(ppszLink) *ppszLink=NULL;
+ return 0;
+}
+
+#endif // !defined EDITOR
+
+#ifdef EDITOR
+struct RtfGroupStackData {
+ BYTE bold,italic,underline,strikeout;
+ BYTE isDestination,isColourTbl,isFontTbl;
+ int colour;
+ int fontSize;
+ int unicodeSkip;
+ int charset;
+};
+
+char *StreamOutHtml(HWND hwndEdit)
+{
+ EDITSTREAM stream;
+ struct EditStreamData esd;
+ struct ResizableCharBuffer htmlOut,hyperlink,*output;
+ COLORREF *colourTbl=NULL;
+ int colourTblCount=0;
+ struct RtfGroupStackData *groupStack;
+ int groupLevel;
+ int inFontTag=0,inAnchorTag=0,inBigTag=0,inSmallTag=0,lineBreakBefore=0;
+ char *pszRtf;
+ int *fontTblCharsets=NULL;
+ int fontTblCount=0;
+ int normalTextSize=0;
+ void *buf;
+
+ ZeroMemory(&stream,sizeof(stream));
+ ZeroMemory(&esd,sizeof(esd));
+ ZeroMemory(&htmlOut,sizeof(htmlOut));
+ ZeroMemory(&hyperlink,sizeof(hyperlink));
+ ZeroMemory(&output,sizeof(output));
+
+ stream.dwCookie=(DWORD)&esd;
+ stream.pfnCallback=EditStreamOutRtf;
+#if defined(_UNICODE)
+ SendMessage(hwndEdit,EM_STREAMOUT,(WPARAM)(CP_UTF8<<16)|SF_USECODEPAGE|SF_RTFNOOBJS|SFF_PLAINRTF,(LPARAM)&stream);
+#else
+ SendMessage(hwndEdit,EM_STREAMOUT,SF_RTFNOOBJS|SFF_PLAINRTF,(LPARAM)&stream);
+#endif
+ if(esd.pbBuff==NULL) return NULL;
+
+ output=&htmlOut;
+ groupStack=(struct RtfGroupStackData*)mir_calloc(sizeof(struct RtfGroupStackData));
+ if(groupStack!=NULL) {
+ groupLevel=0;
+ groupStack[0].unicodeSkip=1;
+ for(pszRtf=(char*)esd.pbBuff;*pszRtf!='\0';) {
+ if(*pszRtf=='{') {
+ buf=(struct RtfGroupStackData*)mir_realloc(groupStack,sizeof(struct RtfGroupStackData)*(groupLevel+2));
+ if(buf==NULL) break;
+ groupStack=(struct RtfGroupStackData*)buf;
+ groupStack[groupLevel]=groupStack[groupLevel];
+ groupLevel++;
+ pszRtf++;
+ }
+ else if(*pszRtf=='}') {
+ groupLevel--;
+ if(groupStack[groupLevel].bold!=groupStack[groupLevel+1].bold)
+ AppendToCharBuffer(output,groupStack[groupLevel].bold?"<b>":"</b>");
+ if(groupStack[groupLevel].italic!=groupStack[groupLevel+1].italic)
+ AppendToCharBuffer(output,groupStack[groupLevel].bold?"<i>":"</i>");
+ if(groupStack[groupLevel].underline!=groupStack[groupLevel+1].underline)
+ AppendToCharBuffer(output,groupStack[groupLevel].bold?"<u>":"</u>");
+ if(groupStack[groupLevel].strikeout!=groupStack[groupLevel+1].strikeout && groupStack[groupLevel+1].strikeout)
+ if(inAnchorTag) {AppendToCharBuffer(output,"</a>"); inAnchorTag=0;}
+ if(groupStack[groupLevel].colour!=groupStack[groupLevel+1].colour)
+ if(inFontTag) {AppendToCharBuffer(output,"</font>"); inFontTag=0;}
+ if(groupStack[groupLevel].fontSize!=groupStack[groupLevel+1].fontSize) {
+ if(inBigTag) {AppendToCharBuffer(output,"</big>"); inBigTag=0;}
+ if(inSmallTag) {AppendToCharBuffer(output,"</small>"); inSmallTag=0;}
+ if(groupStack[groupLevel].fontSize<normalTextSize)
+ {AppendToCharBuffer(output,"<small>"); inSmallTag=1;}
+ else if(groupStack[groupLevel].fontSize>normalTextSize)
+ {AppendToCharBuffer(output,"<big>"); inBigTag=1;}
+ }
+ if(groupLevel==0) break;
+ pszRtf++;
+ }
+ else if(*pszRtf=='\\' && pszRtf[1]=='*') {
+ groupStack[groupLevel].isDestination=1;
+ pszRtf+=2;
+ }
+ else if(*pszRtf=='\\' && pszRtf[1]=='\'') {
+ char szHex[3]="\0\0";
+ char szChar[2];
+ szHex[0]=pszRtf[2];
+ if(pszRtf[2]) szHex[1]=pszRtf[3];
+ else pszRtf--;
+ szChar[0]=(char)strtol(szHex,NULL,16); szChar[1]='\0';
+ if(groupStack[groupLevel].charset) {
+ WCHAR szwChar[2];
+ CHARSETINFO csi;
+ TranslateCharsetInfo((PDWORD)groupStack[groupLevel].charset,&csi,TCI_SRCCHARSET);
+ MultiByteToWideChar(csi.ciACP,0,szChar,1,szwChar,2);
+ AppendToCharBuffer(output,"&#%u;",(WORD)szwChar[0]);
+ }
+ else AppendToCharBuffer(output,"&#%u;",(BYTE)szChar[0]);
+ pszRtf+=4;
+ }
+ else if(*pszRtf=='\\' && isalpha(pszRtf[1])) {
+ char szControlWord[32];
+ int iWordEnd;
+ int hasParam=0;
+ int param=-1;
+
+ for(iWordEnd=1;isalpha(pszRtf[iWordEnd]);iWordEnd++);
+ CopyMemory(szControlWord,pszRtf+1,min(sizeof(szControlWord),iWordEnd));
+ szControlWord[min(sizeof(szControlWord),iWordEnd)-1]='\0';
+ if(isdigit(pszRtf[iWordEnd]) || pszRtf[iWordEnd]=='-') {
+ hasParam=1;
+ param=strtol(pszRtf+iWordEnd,&pszRtf,10);
+ }
+ else pszRtf=pszRtf+iWordEnd;
+ if(*pszRtf==' ') pszRtf++;
+ if(!lstrcmpiA(szControlWord,"colortbl")) {
+ groupStack[groupLevel].isColourTbl=1;
+ buf=(COLORREF*)mir_realloc(colourTbl,sizeof(COLORREF));
+ if(buf!=NULL) {
+ colourTbl=(COLORREF*)buf;
+ colourTblCount=1;
+ colourTbl[0]=0;
+ }
+ groupStack[groupLevel].isDestination=1;
+ }
+ else if(!lstrcmpiA(szControlWord,"fonttbl")) {
+ groupStack[groupLevel].isFontTbl=1;
+ groupStack[groupLevel].isDestination=1;
+ }
+ else if(!lstrcmpiA(szControlWord,"stylesheet")) {
+ groupStack[groupLevel].isDestination=1;
+ }
+ else if(!lstrcmpiA(szControlWord,"red")) {
+ if(!hasParam || !colourTblCount) break;
+ colourTbl[colourTblCount-1]&=~RGB(255,0,0);
+ colourTbl[colourTblCount-1]|=RGB(param,0,0);
+ }
+ else if(!lstrcmpiA(szControlWord,"green")) {
+ if(!hasParam || !colourTblCount) break;
+ colourTbl[colourTblCount-1]&=~RGB(0,255,0);
+ colourTbl[colourTblCount-1]|=RGB(0,param,0);
+ }
+ else if(!lstrcmpiA(szControlWord,"blue")) {
+ if(!hasParam || !colourTblCount) break;
+ colourTbl[colourTblCount-1]&=~RGB(0,0,255);
+ colourTbl[colourTblCount-1]|=RGB(0,0,param);
+ }
+ else if(!lstrcmpiA(szControlWord,"f")) {
+ if(groupStack[groupLevel].isFontTbl) {
+ buf=(int*)mir_realloc(fontTblCharsets,sizeof(int)*(fontTblCount+1));
+ if(buf!=NULL) {
+ fontTblCharsets=(int*)buf;
+ fontTblCharsets[fontTblCount]=0;
+ fontTblCount++;
+ }
+ }
+ else {
+ if(hasParam && param>=0 && param<fontTblCount)
+ groupStack[groupLevel].charset=fontTblCharsets[param];
+ }
+ }
+ else if(!lstrcmpiA(szControlWord,"fcharset")) {
+ if(groupStack[groupLevel].isFontTbl && fontTblCount && hasParam)
+ fontTblCharsets[fontTblCount-1]=param;
+ }
+ else if(!lstrcmpiA(szControlWord,"cf")) {
+ if(inFontTag) AppendToCharBuffer(output,"</font>");
+ if(hasParam && param) {
+ int i;
+ char szColour[7];
+ wsprintfA(szColour,"%02x%02x%02x",GetRValue(colourTbl[param]),GetGValue(colourTbl[param]),GetBValue(colourTbl[param]));
+ for(i=0;i<SIZEOF(htmlColourNames);i++) {
+ if(!lstrcmpiA(szColour,htmlColourNames[i].szClr)) {
+ AppendToCharBuffer(output,"<font color=\"%s\">",htmlColourNames[i].szName);
+ break;
+ }
+ }
+ if(i==SIZEOF(htmlColourNames))
+ AppendToCharBuffer(output,"<font color=\"#%s\">",szColour);
+ inFontTag=1;
+ groupStack[groupLevel].colour=param;
+ }
+ else groupStack[groupLevel].colour=0;
+ }
+ else if(!lstrcmpiA(szControlWord,"fs")) {
+ if(normalTextSize==0 && hasParam) {
+ normalTextSize=param;
+ groupStack[0].fontSize=normalTextSize;
+ }
+ if(inBigTag) {AppendToCharBuffer(output,"</big>"); inBigTag=0;}
+ if(inSmallTag) {AppendToCharBuffer(output,"</small>"); inSmallTag=0;}
+ if(hasParam) {
+ groupStack[groupLevel].fontSize=param;
+ if(groupStack[groupLevel].fontSize<normalTextSize)
+ {AppendToCharBuffer(output,"<small>"); inSmallTag=1;}
+ else if(groupStack[groupLevel].fontSize>normalTextSize)
+ {AppendToCharBuffer(output,"<big>"); inBigTag=1;}
+ }
+ }
+ else if(!lstrcmpiA(szControlWord,"uc")) {
+ if(hasParam) groupStack[groupLevel].unicodeSkip=param;
+ }
+ else if(!lstrcmpiA(szControlWord,"u")) {
+ if(hasParam) {
+ AppendToCharBuffer(output,"&#%u;",param);
+ pszRtf+=groupStack[groupLevel].unicodeSkip;
+ }
+ }
+ else if(!lstrcmpiA(szControlWord,"b")) {
+ if(!hasParam || param) {
+ groupStack[groupLevel].bold=1;
+ AppendToCharBuffer(output,"<b>");
+ }
+ else {
+ groupStack[groupLevel].bold=0;
+ AppendToCharBuffer(output,"</b>");
+ }
+ }
+ else if(!lstrcmpiA(szControlWord,"i")) {
+ if(!hasParam || param) {
+ groupStack[groupLevel].italic=1;
+ AppendToCharBuffer(output,"<i>");
+ }
+ else {
+ groupStack[groupLevel].italic=0;
+ AppendToCharBuffer(output,"</i>");
+ }
+ }
+ else if(!lstrcmpiA(szControlWord,"ul")) {
+ if(!hasParam || param) {
+ groupStack[groupLevel].underline=1;
+ AppendToCharBuffer(output,"<u>");
+ }
+ else {
+ groupStack[groupLevel].underline=0;
+ AppendToCharBuffer(output,"</u>");
+ }
+ }
+ else if(!lstrcmpiA(szControlWord,"ulnone")) {
+ groupStack[groupLevel].underline=0;
+ AppendToCharBuffer(output,"</u>");
+ }
+ else if(!lstrcmpiA(szControlWord,"strike")) {
+ if(!hasParam || param) {
+ groupStack[groupLevel].strikeout=1;
+ mir_free(hyperlink.sz); // does NULL check
+ hyperlink.iEnd=hyperlink.cbAlloced=0;
+ hyperlink.sz=NULL;
+ output=&hyperlink;
+ }
+ else {
+ groupStack[groupLevel].strikeout=0;
+ if(hyperlink.iEnd && hyperlink.sz!=NULL) {
+ char *pszColon;
+ output=&htmlOut;
+ pszColon=strchr(hyperlink.sz,':');
+ if(pszColon==NULL) pszColon="";
+ else *pszColon++='\0';
+ AppendToCharBuffer(output,"<a href=\"%s\">%s</a>",pszColon,hyperlink.sz);
+ mir_free(hyperlink.sz);
+ hyperlink.iEnd=hyperlink.cbAlloced=0;
+ hyperlink.sz=NULL;
+ }
+ }
+ }
+ else if(!lstrcmpiA(szControlWord,"par")) {
+ if(lineBreakBefore) AppendToCharBuffer(output,"<br>");
+ lineBreakBefore=1; // richedit puts a \par right at the end
+ }
+ }
+ else {
+ int i;
+ if(*pszRtf=='\\') pszRtf++;
+ if(!groupStack[groupLevel].isDestination) {
+ if(lineBreakBefore && (BYTE)*pszRtf>=' ') {AppendToCharBuffer(output,"<br>"); lineBreakBefore=0;}
+ if(*pszRtf==' ')
+ AppendCharToCharBuffer(output,*pszRtf);
+ else {
+ for(i=0;i<SIZEOF(htmlSymbolChars);i++) {
+ if(*pszRtf==htmlSymbolChars[i].ch) {
+ AppendToCharBuffer(output,"&%s;",htmlSymbolChars[i].szSym);
+ break;
+ }
+ }
+ if(i==SIZEOF(htmlSymbolChars))
+ AppendCharToCharBuffer(output,*pszRtf);
+ }
+ }
+ else if(groupStack[groupLevel].isColourTbl && *pszRtf==';') {
+ buf=(COLORREF*)mir_realloc(colourTbl,sizeof(COLORREF)*(colourTblCount+2));
+ if(buf!=NULL) {
+ colourTbl=(COLORREF*)buf;
+ colourTbl[colourTblCount]=0;
+ colourTblCount++;
+ }
+ }
+ pszRtf++;
+ }
+ }
+ mir_free(groupStack);
+ }
+ mir_free(colourTbl); // does NULL check
+ mir_free(fontTblCharsets); // does NULL check
+ mir_free(hyperlink.sz); // does NULL check
+
+ mir_free(esd.pbBuff);
+ return htmlOut.sz;
+}
+#endif // defined EDITOR
diff --git a/Help/unzip.c b/Help/unzip.c
new file mode 100644
index 0000000..9eed4dc
--- /dev/null
+++ b/Help/unzip.c
@@ -0,0 +1,3305 @@
+
+// THIS FILE is almost entirely based upon code by Jean-Loup Gailly
+// and Mark Adler. It has been modified by Lucian Wischik.
+// The modifications were: incorporate the bugfixes of 1.1.4, allow
+// unzipping to/from handles/pipes/files/memory, encryption, unicode,
+// a windowsish api, and putting everything into a single .cpp file.
+// The original code may be found at http://www.gzip.org/zlib/
+// The original copyright text follows.
+
+/* NOTE: This is a modification of the original unzip.cpp file. */
+
+// zlib -- interface of the 'zlib' general purpose compression library
+// version 1.1.3, July 9th, 1998
+//
+// Copyright (C) 1995-1998 Jean-Loup Gailly and Mark Adler
+//
+// This software is provided 'as-is', without any express or implied
+// warranty. In no event will the authors be held liable for any damages
+// arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it
+// freely, subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented; you must not
+// claim that you wrote the original software. If you use this software
+// in a product, an acknowledgment in the product documentation would be
+// appreciated but is not required.
+// 2. Altered source versions must be plainly marked as such, and must not be
+// misrepresented as being the original software.
+// 3. This notice may not be removed or altered from any source distribution.
+//
+// Jean-Loup Gailly Mark Adler
+// jloup@gzip.org madler@alumni.caltech.edu
+//
+// The data format used by the zlib library is described by RFCs (Request for
+// Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt
+// (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
+//
+// The 'zlib' compression library provides in-memory compression and
+// decompression functions, including integrity checks of the uncompressed
+// data. This version of the library supports only one compression method
+// (deflation) but other algorithms will be added later and will have the same
+// stream interface.
+//
+// Compression can be done in a single step if the buffers are large
+// enough (for example if an input file is mmap'ed), or can be done by
+// repeated calls of the compression function. In the latter case, the
+// application must provide more input and/or consume the output
+// (providing more output space) before each call.
+//
+// The library also supports reading and writing files in gzip (.gz) format
+// with an interface similar to that of stdio.
+//
+// The library does not install any signal handler. The decoder checks
+// the consistency of the compressed data, so the library should never
+// crash even in case of corrupted input.
+//
+// for more info about .ZIP format, see ftp://ftp.cdrom.com/pub/infozip/doc/appnote-970311-iz.zip
+// PkWare has also a specification at ftp://ftp.pkware.com/probdesc.zip
+
+#define __RPCASYNC_H__ /* header shows warnings in VS6 */
+#include <windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <tchar.h>
+#include "unzip.h"
+#define MIRANDA_VER 0x0600
+#include "newpluginapi.h"
+#include "m_system.h"
+
+typedef struct tm_unz_s {
+ unsigned int tm_sec; // seconds after the minute - [0,59]
+ unsigned int tm_min; // minutes after the hour - [0,59]
+ unsigned int tm_hour; // hours since midnight - [0,23]
+ unsigned int tm_mday; // day of the month - [1,31]
+ unsigned int tm_mon; // months since January - [0,11]
+ unsigned int tm_year; // years - [1980..2044]
+} tm_unz;
+
+// unz_global_info structure contain global data about the ZIPfile
+typedef struct unz_global_info_s {
+ unsigned long number_entry; // total number of entries in the central dir on this disk
+ unsigned long size_comment; // size of the global comment of the zipfile
+} unz_global_info;
+
+// unz_file_info contain information about a file in the zipfile
+typedef struct unz_file_info_s {
+ unsigned long version; // version made by 2 bytes
+ unsigned long version_needed; // version needed to extract 2 bytes
+ unsigned long flag; // general purpose bit flag 2 bytes
+ unsigned long compression_method; // compression method 2 bytes
+ unsigned long dosDate; // last mod file date in Dos fmt 4 bytes
+ unsigned long crc; // crc-32 4 bytes
+ unsigned long compressed_size; // compressed size 4 bytes
+ unsigned long uncompressed_size; // uncompressed size 4 bytes
+ unsigned long size_filename; // filename length 2 bytes
+ unsigned long size_file_extra; // extra field length 2 bytes
+ unsigned long size_file_comment; // file comment length 2 bytes
+ unsigned long disk_num_start; // disk number start 2 bytes
+ unsigned long internal_fa; // internal file attributes 2 bytes
+ unsigned long external_fa; // external file attributes 4 bytes
+ tm_unz tmu_date;
+} unz_file_info;
+
+#define UNZ_OK 0
+#define UNZ_END_OF_LIST_OF_FILE (-100)
+#define UNZ_ERRNO Z_ERRNO
+#define UNZ_EOF 0
+#define UNZ_PARAMERROR (-102)
+#define UNZ_BADZIPFILE (-103)
+#define UNZ_INTERNALERROR (-104)
+#define UNZ_CRCERROR (-105)
+#define UNZ_PASSWORD (-106)
+
+// Allowed flush values; see inflate() for details
+#define Z_SYNC_FLUSH 2
+#define Z_FINISH 4
+
+// The deflate compression method (the only one supported in this version)
+#define Z_DEFLATED 8
+
+// case sensitivity when searching for filenames
+#define CASE_SENSITIVE 1
+#define CASE_INSENSITIVE 2
+
+// Return codes for the compression/decompression functions. Negative
+// values are errors, positive values are used for special but normal events.
+#define Z_OK 0
+#define Z_STREAM_END 1
+#define Z_NEED_DICT 2
+#define Z_ERRNO (-1)
+#define Z_STREAM_ERROR (-2)
+#define Z_DATA_ERROR (-3)
+#define Z_MEM_ERROR (-4)
+#define Z_BUF_ERROR (-5)
+
+// Basic data types
+typedef long z_off_t;
+struct internal_state;
+
+typedef struct z_stream_s {
+ BYTE *next_in; // next input byte
+ UINT avail_in; // number of bytes available at next_in
+ ULONG total_in; // total nb of input bytes read so far
+
+ BYTE *next_out; // next output byte should be put there
+ UINT avail_out; // remaining free space at next_out
+ ULONG total_out; // total nb of bytes output so far
+
+ struct internal_state *state; // internal, not visible
+
+ int data_type; // best guess about the data type: ascii or binary
+ ULONG adler; // adler32 value of the uncompressed data
+ ULONG reserved; // reserved for future use
+} z_stream,*z_streamp;
+
+// The application must update next_in and avail_in when avail_in has
+// dropped to zero. It must update next_out and avail_out when avail_out
+// has dropped to zero. All other fields are set by the
+// compression library and must not be updated by the application.
+//
+// The fields total_in and total_out can be used for statistics or
+// progress reports. After compression, total_in holds the total size of
+// the uncompressed data and may be saved for use in the decompressor
+// (particularly if the decompressor wants to decompress everything in
+// a single step).
+
+
+// inflate decompresses as much data as possible, and stops when the input
+// buffer becomes empty or the output buffer becomes full. It may some
+// introduce some output latency (reading input without producing any output)
+// except when forced to flush.
+//
+// The detailed semantics are as follows. inflate performs one or both of the
+// following actions:
+//
+// - Decompress more input starting at next_in and update next_in and avail_in
+// accordingly. If not all input can be processed (because there is not
+// enough room in the output buffer), next_in is updated and processing
+// will resume at this point for the next call of inflate().
+//
+// - Provide more output starting at next_out and update next_out and avail_out
+// accordingly. inflate() provides as much output as possible, until there
+// is no more input data or no more space in the output buffer (see below
+// about the flush parameter).
+//
+// Before the call of inflate(), the application should ensure that at least
+// one of the actions is possible, by providing more input and/or consuming
+// more output, and updating the next_* and avail_* values accordingly.
+// The application can consume the uncompressed output when it wants, for
+// example when the output buffer is full (avail_out == 0), or after each
+// call of inflate(). If inflate returns Z_OK and with zero avail_out, it
+// must be called again after making room in the output buffer because there
+// might be more output pending.
+//
+// If the parameter flush is set to Z_SYNC_FLUSH, inflate flushes as much
+// output as possible to the output buffer. The flushing behavior of inflate is
+// not specified for values of the flush parameter other than Z_SYNC_FLUSH
+// and Z_FINISH, but the current implementation actually flushes as much output
+// as possible anyway.
+//
+// inflate() should normally be called until it returns Z_STREAM_END or an
+// error. However if all decompression is to be performed in a single step
+// (a single call of inflate), the parameter flush should be set to
+// Z_FINISH. In this case all pending input is processed and all pending
+// output is flushed; avail_out must be large enough to hold all the
+// uncompressed data. (The size of the uncompressed data may have been saved
+// by the compressor for this purpose.) The next operation on this stream must
+// be inflateEnd to deallocate the decompression state. The use of Z_FINISH
+// is never required, but can be used to inform inflate that a faster routine
+// may be used for the single inflate() call.
+//
+// If a preset dictionary is needed at this point, inflate sets strm-adler
+// to the adler32 checksum of the
+// dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise
+// it sets strm->adler to the adler32 checksum of all output produced
+// so far (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or
+// an error code as described below. At the end of the stream, inflate()
+// checks that its computed adler32 checksum is equal to that saved by the
+// compressor and returns Z_STREAM_END only if the checksum is correct.
+//
+// inflate() returns Z_OK if some progress has been made (more input processed
+// or more output produced), Z_STREAM_END if the end of the compressed data has
+// been reached and all uncompressed output has been produced, Z_NEED_DICT if a
+// preset dictionary is needed at this point, Z_DATA_ERROR if the input data was
+// corrupted (input stream not conforming to the zlib format or incorrect
+// adler32 checksum), Z_STREAM_ERROR if the stream structure was inconsistent
+// (for example if next_in or next_out was NULL), Z_MEM_ERROR if there was not
+// enough memory, Z_BUF_ERROR if no progress is possible or if there was not
+// enough room in the output buffer when Z_FINISH is used.
+static int inflate(z_streamp strm, int flush);
+
+// All dynamically allocated data structures for this stream are freed.
+// This function discards any unprocessed input and does not flush any
+// pending output.
+//
+// inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
+// was inconsistent.
+static int inflateEnd (z_streamp strm);
+
+// This function is equivalent to inflateEnd followed by inflateInit,
+// but does not free and reallocate all the internal decompression state.
+// The stream will keep attributes that may have been set by inflateInit2.
+//
+// inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+// stream state was inconsistent (such as zalloc or state being NULL).
+static int inflateReset (z_streamp strm);
+
+typedef unsigned char uch;
+typedef uch uchf;
+typedef unsigned short ush;
+typedef ush ushf;
+typedef unsigned long ulg;
+
+#define PRESET_DICT 0x20 // preset dictionary flag
+
+// Diagnostic functions
+#define LuTracev(x)
+#define LuTracevv(x)
+
+typedef ULONG (*check_func)(ULONG check,const BYTE *buf,UINT len);
+
+// Huffman code lookup table entry -- this entry is four bytes for machines
+// that have 16-bit pointers (e.g. PC's in the small or medium model).
+typedef struct inflate_huft_s inflate_huft;
+struct inflate_huft_s {
+ union {
+ struct {
+ BYTE Exop; // number of extra bits or operation
+ BYTE Bits; // number of bits in this code or subcode
+ } what;
+ UINT pad; // pad structure to a power of 2 (4 bytes for
+ } word; // 16-bit, 8 bytes for 32-bit int's)
+ UINT base; // literal, length base, distance base, or table offset
+};
+
+// Maximum size of dynamic tree. The maximum found in a long but non-
+// exhaustive search was 1004 huft structures (850 for length/literals
+// and 154 for distances, the latter actually the result of an
+// exhaustive search). The actual maximum is not known, but the
+// value below is more than safe.
+#define MANY 1440
+
+static int inflate_trees_bits (
+ UINT *, // 19 code lengths
+ UINT *, // bits tree desired/actual depth
+ inflate_huft * *, // bits tree result
+ inflate_huft *); // space for trees
+
+static int inflate_trees_dynamic (
+ UINT, // number of literal/length codes
+ UINT, // number of distance codes
+ UINT *, // that many (total) code lengths
+ UINT *, // literal desired/actual bit depth
+ UINT *, // distance desired/actual bit depth
+ inflate_huft * *, // literal/length tree result
+ inflate_huft * *, // distance tree result
+ inflate_huft *); // space for trees
+
+static int inflate_trees_fixed (
+ UINT *, // literal desired/actual bit depth
+ UINT *, // distance desired/actual bit depth
+ const inflate_huft * *, // literal/length tree result
+ const inflate_huft * *, // distance tree result
+ z_streamp); // for memory allocation
+
+struct inflate_blocks_state;
+typedef struct inflate_blocks_state inflate_blocks_statef;
+
+struct inflate_codes_state;
+typedef struct inflate_codes_state inflate_codes_statef;
+
+typedef enum {
+ IBM_TYPE, // get type bits (3, including end bit)
+ IBM_LENS, // get lengths for stored
+ IBM_STORED, // processing stored block
+ IBM_TABLE, // get table lengths
+ IBM_BTREE, // get bit lengths tree for a dynamic block
+ IBM_DTREE, // get length, distance trees for a dynamic block
+ IBM_CODES, // processing fixed or dynamic block
+ IBM_DRY, // output remaining window bytes
+ IBM_DONE, // finished last block, done
+ IBM_BAD} // got a data error--stuck here
+inflate_block_mode;
+
+// inflate blocks semi-private state
+struct inflate_blocks_state {
+ // mode
+ inflate_block_mode mode; // current inflate_block mode
+
+ // mode dependent information
+ union {
+ UINT left; // if STORED, bytes left to copy
+ struct {
+ UINT table; // table lengths (14 bits)
+ UINT index; // index into blens (or border)
+ UINT *blens; // bit lengths of codes
+ UINT bb; // bit length tree depth
+ inflate_huft *tb; // bit length decoding tree
+ } trees; // if DTREE, decoding info for trees
+ struct {
+ inflate_codes_statef
+ *codes;
+ } decode; // if CODES, current state
+ } sub; // submode
+ UINT last; // TRUE if this block is the last block
+
+ // mode independent information
+ UINT bitk; // bits in bit buffer
+ ULONG bitb; // bit buffer
+ inflate_huft *hufts; // single malloc for tree space
+ BYTE *window; // sliding window
+ BYTE *end; // one byte after sliding window
+ BYTE *read; // window read pointer
+ BYTE *write; // window write pointer
+ check_func checkfn; // check function
+ ULONG check; // check on output
+};
+
+// defines for inflate input/output
+// update pointers and return
+#define UPDBITS {s->bitb=b;s->bitk=k;}
+#define UPDIN {z->avail_in=n;z->total_in+=(ULONG)(p-z->next_in);z->next_in=p;}
+#define UPDOUT {s->write=q;}
+#define UPDATE {UPDBITS UPDIN UPDOUT}
+#define LEAVE {UPDATE return inflate_flush(s,z,r);}
+// get bytes and bits
+#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;}
+#define NEEDBYTE {if(n)r=Z_OK;else LEAVE}
+#define NEXTBYTE (n--,*p++)
+#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((ULONG)NEXTBYTE)<<k;k+=8;}}
+#define DUMPBITS(j) {b>>=(j);k-=(j);}
+// output bytes
+#define WAVAIL (UINT)(q<s->read?s->read-q-1:s->end-q)
+#define LOADOUT {q=s->write;m=(UINT)WAVAIL;m;}
+#define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(UINT)WAVAIL;}}
+#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT}
+#define NEEDOUT {if(m==0){WRAP if(m==0){FLUSH WRAP if(m==0) LEAVE}}r=Z_OK;}
+#define OUTBYTE(a) {*q++=(BYTE)(a);m--;}
+// load local pointers
+#define LOAD {LOADIN LOADOUT}
+
+// masks for lower bits (size given to avoid silly warnings with Visual C++)
+// And'ing with mask[n] masks the lower n bits
+const UINT inflate_mask[17] = {
+ 0x0000,
+ 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
+ 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
+};
+
+static int inflate_fast (UINT, UINT, const inflate_huft *, const inflate_huft *, inflate_blocks_statef *, z_streamp );
+
+const UINT fixed_bl = 9;
+const UINT fixed_bd = 5;
+const inflate_huft fixed_tl[] = {
+ {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115},
+ {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},192},
+ {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},160},
+ {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},224},
+ {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},144},
+ {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},208},
+ {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},176},
+ {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},240},
+ {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227},
+ {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},200},
+ {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},168},
+ {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},232},
+ {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},152},
+ {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},216},
+ {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},184},
+ {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},248},
+ {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163},
+ {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},196},
+ {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},164},
+ {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},228},
+ {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},148},
+ {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},212},
+ {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},180},
+ {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},244},
+ {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0},
+ {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},204},
+ {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},172},
+ {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},236},
+ {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},156},
+ {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},220},
+ {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},188},
+ {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},252},
+ {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131},
+ {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},194},
+ {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},162},
+ {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},226},
+ {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},146},
+ {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},210},
+ {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},178},
+ {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},242},
+ {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258},
+ {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},202},
+ {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},170},
+ {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},234},
+ {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},154},
+ {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},218},
+ {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},186},
+ {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},250},
+ {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195},
+ {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},198},
+ {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},166},
+ {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},230},
+ {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},150},
+ {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},214},
+ {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},182},
+ {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},246},
+ {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0},
+ {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},206},
+ {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},174},
+ {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},238},
+ {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},158},
+ {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},222},
+ {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},190},
+ {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},254},
+ {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115},
+ {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},193},
+ {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},161},
+ {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},225},
+ {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},145},
+ {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},209},
+ {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},177},
+ {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},241},
+ {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227},
+ {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},201},
+ {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},169},
+ {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},233},
+ {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},153},
+ {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},217},
+ {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},185},
+ {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},249},
+ {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163},
+ {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},197},
+ {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},165},
+ {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},229},
+ {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},149},
+ {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},213},
+ {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},181},
+ {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},245},
+ {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0},
+ {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},205},
+ {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},173},
+ {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},237},
+ {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},157},
+ {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},221},
+ {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},189},
+ {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},253},
+ {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131},
+ {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},195},
+ {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},163},
+ {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},227},
+ {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},147},
+ {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},211},
+ {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},179},
+ {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},243},
+ {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258},
+ {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},203},
+ {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},171},
+ {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},235},
+ {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},155},
+ {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},219},
+ {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},187},
+ {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},251},
+ {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195},
+ {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},199},
+ {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},167},
+ {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},231},
+ {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},151},
+ {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},215},
+ {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},183},
+ {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},247},
+ {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0},
+ {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},207},
+ {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},175},
+ {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},239},
+ {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},159},
+ {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},223},
+ {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},191},
+ {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},255}
+ };
+const inflate_huft fixed_td[] = {
+ {{{80,5}},1}, {{{87,5}},257}, {{{83,5}},17}, {{{91,5}},4097},
+ {{{81,5}},5}, {{{89,5}},1025}, {{{85,5}},65}, {{{93,5}},16385},
+ {{{80,5}},3}, {{{88,5}},513}, {{{84,5}},33}, {{{92,5}},8193},
+ {{{82,5}},9}, {{{90,5}},2049}, {{{86,5}},129}, {{{192,5}},24577},
+ {{{80,5}},2}, {{{87,5}},385}, {{{83,5}},25}, {{{91,5}},6145},
+ {{{81,5}},7}, {{{89,5}},1537}, {{{85,5}},97}, {{{93,5}},24577},
+ {{{80,5}},4}, {{{88,5}},769}, {{{84,5}},49}, {{{92,5}},12289},
+ {{{82,5}},13}, {{{90,5}},3073}, {{{86,5}},193}, {{{192,5}},24577}
+ };
+
+// copy as much as possible from the sliding window to the output area
+static int inflate_flush(inflate_blocks_statef *s,z_streamp z,int r)
+{
+ UINT n;
+ BYTE *p;
+ BYTE *q;
+
+ // local copies of source and destination pointers
+ p = z->next_out;
+ q = s->read;
+
+ // compute number of bytes to copy as far as end of window
+ n = (UINT)((q <= s->write ? s->write : s->end) - q);
+ if (n > z->avail_out) n = z->avail_out;
+ if (n && r == Z_BUF_ERROR) r = Z_OK;
+
+ // update counters
+ z->avail_out -= n;
+ z->total_out += n;
+
+ // update check information
+ if (s->checkfn != NULL)
+ z->adler = s->check = (*s->checkfn)(s->check, q, n);
+
+ // copy as far as end of window
+ if (n!=0) // check for n!=0 to avoid waking up CodeGuard
+ { CopyMemory(p, q, n);
+ p += n;
+ q += n;
+ }
+
+ // see if more to copy at beginning of window
+ if (q == s->end)
+ {
+ // wrap pointers
+ q = s->window;
+ if (s->write == s->end)
+ s->write = s->window;
+
+ // compute bytes to copy
+ n = (UINT)(s->write - q);
+ if (n > z->avail_out) n = z->avail_out;
+ if (n && r == Z_BUF_ERROR) r = Z_OK;
+
+ // update counters
+ z->avail_out -= n;
+ z->total_out += n;
+
+ // update check information
+ if (s->checkfn != NULL)
+ z->adler = s->check = (*s->checkfn)(s->check, q, n);
+
+ // copy
+ if (n!=0) { CopyMemory(p,q,n); p+=n; q+=n; }
+ }
+
+ // update pointers
+ z->next_out = p;
+ s->read = q;
+
+ // done
+ return r;
+}
+
+// simplify the use of the inflate_huft type with some defines
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+typedef enum { // waiting for "i:"=input, "o:"=output, "x:"=nothing
+ START, // x: set up for LEN
+ LEN, // i: get length/literal/eob next
+ LENEXT, // i: getting length extra (have base)
+ DIST, // i: get distance next
+ DISTEXT, // i: getting distance extra
+ COPY, // o: copying bytes in window, waiting for space
+ LIT, // o: got literal, waiting for output space
+ WASH, // o: got eob, possibly still output waiting
+ END, // x: got eob and all data flushed
+ BADCODE} // x: got error
+inflate_codes_mode;
+
+// inflate codes private state
+struct inflate_codes_state {
+ // mode
+ inflate_codes_mode mode; // current inflate_codes mode
+
+ // mode dependent information
+ UINT len;
+ union {
+ struct {
+ const inflate_huft *tree; // pointer into tree
+ UINT need; // bits needed
+ } code; // if LEN or DIST, where in tree
+ UINT lit; // if LIT, literal
+ struct {
+ UINT get; // bits to get for extra
+ UINT dist; // distance back to copy from
+ } copy; // if EXT or COPY, where and how much
+ } sub; // submode
+
+ // mode independent information
+ BYTE lbits; // ltree bits decoded per branch
+ BYTE dbits; // dtree bits decoder per branch
+ const inflate_huft *ltree; // literal/length/eob tree
+ const inflate_huft *dtree; // distance tree
+};
+
+static inflate_codes_statef *inflate_codes_new(
+UINT bl, UINT bd,
+const inflate_huft *tl,
+const inflate_huft *td) // need separate declaration for Borland C++
+{
+ inflate_codes_statef *c;
+
+ if ((c = (inflate_codes_statef *)
+ mir_calloc(sizeof(struct inflate_codes_state))) != NULL)
+ {
+ c->mode = START;
+ c->lbits = (BYTE)bl;
+ c->dbits = (BYTE)bd;
+ c->ltree = tl;
+ c->dtree = td;
+ LuTracev((stderr, "inflate: codes new\n"));
+ }
+ return c;
+}
+
+static int inflate_codes(inflate_blocks_statef *s, z_streamp z, int r)
+{
+ UINT j; // temporary storage
+ const inflate_huft *t; // temporary pointer
+ UINT e; // extra bits or operation
+ ULONG b; // bit buffer
+ UINT k; // bits in bit buffer
+ BYTE *p; // input data pointer
+ UINT n; // bytes available there
+ BYTE *q; // output window write pointer
+ UINT m; // bytes to end of window or read pointer
+ BYTE *f; // pointer to copy strings from
+ inflate_codes_statef *c = s->sub.decode.codes; // codes state
+
+ // copy input/output information to locals (UPDATE macro restores)
+ LOAD
+
+ // process input and output based on current state
+ for(;;) switch (c->mode)
+ { // waiting for "i:"=input, "o:"=output, "x:"=nothing
+ case START: // x: set up for LEN
+#ifndef SLOW
+ if (m >= 258 && n >= 10)
+ {
+ UPDATE
+ r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z);
+ LOAD
+ if (r != Z_OK)
+ {
+ c->mode = r == Z_STREAM_END ? WASH : BADCODE;
+ break;
+ }
+ }
+#endif // !SLOW
+ c->sub.code.need = c->lbits;
+ c->sub.code.tree = c->ltree;
+ c->mode = LEN;
+ case LEN: // i: get length/literal/eob next
+ j = c->sub.code.need;
+ NEEDBITS(j)
+ t = c->sub.code.tree + ((UINT)b & inflate_mask[j]);
+ DUMPBITS(t->bits)
+ e = (UINT)(t->exop);
+ if (e == 0) // literal
+ {
+ c->sub.lit = t->base;
+ LuTracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+ "inflate: literal '%c'\n" :
+ "inflate: literal 0x%02x\n", t->base));
+ c->mode = LIT;
+ break;
+ }
+ if (e & 16) // length
+ {
+ c->sub.copy.get = e & 15;
+ c->len = t->base;
+ c->mode = LENEXT;
+ break;
+ }
+ if ((e & 64) == 0) // next table
+ {
+ c->sub.code.need = e;
+ c->sub.code.tree = t + t->base;
+ break;
+ }
+ if (e & 32) // end of block
+ {
+ LuTracevv((stderr, "inflate: end of block\n"));
+ c->mode = WASH;
+ break;
+ }
+ c->mode = BADCODE; // invalid code
+ r = Z_DATA_ERROR;
+ LEAVE
+ case LENEXT: // i: getting length extra (have base)
+ j = c->sub.copy.get;
+ NEEDBITS(j)
+ c->len += (UINT)b & inflate_mask[j];
+ DUMPBITS(j)
+ c->sub.code.need = c->dbits;
+ c->sub.code.tree = c->dtree;
+ LuTracevv((stderr, "inflate: length %u\n", c->len));
+ c->mode = DIST;
+ case DIST: // i: get distance next
+ j = c->sub.code.need;
+ NEEDBITS(j)
+ t = c->sub.code.tree + ((UINT)b & inflate_mask[j]);
+ DUMPBITS(t->bits)
+ e = (UINT)(t->exop);
+ if (e & 16) // distance
+ {
+ c->sub.copy.get = e & 15;
+ c->sub.copy.dist = t->base;
+ c->mode = DISTEXT;
+ break;
+ }
+ if ((e & 64) == 0) // next table
+ {
+ c->sub.code.need = e;
+ c->sub.code.tree = t + t->base;
+ break;
+ }
+ c->mode = BADCODE; // invalid code
+ r = Z_DATA_ERROR;
+ LEAVE
+ case DISTEXT: // i: getting distance extra
+ j = c->sub.copy.get;
+ NEEDBITS(j)
+ c->sub.copy.dist += (UINT)b & inflate_mask[j];
+ DUMPBITS(j)
+ LuTracevv((stderr, "inflate: distance %u\n", c->sub.copy.dist));
+ c->mode = COPY;
+ case COPY: // o: copying bytes in window, waiting for space
+ f = q - c->sub.copy.dist;
+ while (f < s->window) // modulo window size-"while" instead
+ f += s->end - s->window; // of "if" handles invalid distances
+ while (c->len)
+ {
+ NEEDOUT
+ OUTBYTE(*f++)
+ if (f == s->end)
+ f = s->window;
+ c->len--;
+ }
+ c->mode = START;
+ break;
+ case LIT: // o: got literal, waiting for output space
+ NEEDOUT
+ OUTBYTE(c->sub.lit)
+ c->mode = START;
+ break;
+ case WASH: // o: got eob, possibly more output
+ if (k > 7) // return unused byte, if any
+ {
+ //Assert(k < 16, "inflate_codes grabbed too many bytes")
+ k -= 8;
+ n++;
+ p--; // can always return one
+ }
+ FLUSH
+ if (s->read != s->write)
+ LEAVE
+ c->mode = END;
+ case END:
+ r = Z_STREAM_END;
+ LEAVE
+ case BADCODE: // x: got error
+ r = Z_DATA_ERROR;
+ LEAVE
+ default:
+ r = Z_STREAM_ERROR;
+ LEAVE
+ }
+}
+
+// =============================================================
+
+// infblock -- interpret and process block types to last block
+// Copyright (C) 1995-1998 Mark Adler
+// For conditions of distribution and use, see copyright notice
+
+// Table for deflate from PKZIP's appnote.txt.
+const UINT border[] = { // Order of the bit length code lengths
+ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+// Notes beyond the 1.93a appnote.txt:
+// 1. Distance pointers never point before the beginning of the output stream.
+// 2. Distance pointers can point back across blocks, up to 32k away.
+// 3. There is an implied maximum of 7 bits for the bit length table and
+// 15 bits for the actual data.
+// 4. If only one code exists, then it is encoded using one bit. (Zero
+// would be more efficient, but perhaps a little confusing.) If two
+// codes exist, they are coded using one bit each (0 and 1).
+// 5. There is no way of sending zero distance codes--a dummy must be
+// sent if there are none. (History: a pre 2.0 version of PKZIP would
+// store blocks with no distance codes, but this was discovered to be
+// too harsh a criterion.) Valid only for 1.93a. 2.04c does allow
+// zero distance codes, which is sent as one code of zero bits in
+// length.
+// 6. There are up to 286 literal/length codes. Code 256 represents the
+// end-of-block. Note however that the static length tree defines
+// 288 codes just to fill out the Huffman codes. Codes 286 and 287
+// cannot be used though, since there is no length base or extra bits
+// defined for them. Similarily, there are up to 30 distance codes.
+// However, static trees define 32 codes (all 5 bits) to fill out the
+// Huffman codes, but the last two had better not show up in the data.
+// 7. Unzip can check dynamic Huffman blocks for complete code sets.
+// The exception is that a single code would not be complete (see #4).
+// 8. The five bits following the block type is really the number of
+// literal codes sent minus 257.
+// 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits
+// (1+6+6). Therefore, to output three times the length, you output
+// three codes (1+1+1), whereas to output four times the same length,
+// you only need two codes (1+3). Hmm.
+//10. In the tree reconstruction algorithm, Code = Code + Increment
+// only if BitLength(i) is not zero. (Pretty obvious.)
+//11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19)
+//12. Note: length code 284 can represent 227-258, but length code 285
+// really is 258. The last length deserves its own, short code
+// since it gets used a lot in very redundant files. The length
+// 258 is special since 258 - 3 (the min match length) is 255.
+//13. The literal/length and distance code bit lengths are read as a
+// single stream of lengths. It is possible (and advantageous) for
+// a repeat code (16, 17, or 18) to go across the boundary between
+// the two sets of lengths.
+
+static void inflate_blocks_reset(inflate_blocks_statef *s, z_streamp z, ULONG *c)
+{
+ if (c != NULL)
+ *c = s->check;
+ if (s->mode == IBM_BTREE || s->mode == IBM_DTREE)
+ mir_free(s->sub.trees.blens);
+ if (s->mode == IBM_CODES)
+ mir_free(s->sub.decode.codes);
+ s->mode = IBM_TYPE;
+ s->bitk = 0;
+ s->bitb = 0;
+ s->read = s->write = s->window;
+ if (s->checkfn != NULL)
+ z->adler = s->check = (*s->checkfn)(0L, (const BYTE *)NULL, 0);
+ LuTracev((stderr, "inflate: blocks reset\n"));
+}
+
+static inflate_blocks_statef *inflate_blocks_new(z_streamp z, check_func c, UINT w)
+{
+ inflate_blocks_statef *s;
+
+ if ((s = (inflate_blocks_statef *)mir_calloc
+ (sizeof(struct inflate_blocks_state))) == NULL)
+ return s;
+ if ((s->hufts =
+ (inflate_huft *)mir_calloc(sizeof(inflate_huft)*MANY)) == NULL)
+ {
+ mir_free(s);
+ return NULL;
+ }
+ if ((s->window = (BYTE *)mir_calloc(w)) == NULL)
+ {
+ mir_free(s->hufts);
+ mir_free(s);
+ return NULL;
+ }
+ s->end = s->window + w;
+ s->checkfn = c;
+ s->mode = IBM_TYPE;
+ LuTracev((stderr, "inflate: blocks allocated\n"));
+ inflate_blocks_reset(s, z, NULL);
+ return s;
+}
+
+static int inflate_blocks(inflate_blocks_statef *s, z_streamp z, int r)
+{
+ UINT t; // temporary storage
+ ULONG b; // bit buffer
+ UINT k; // bits in bit buffer
+ BYTE *p; // input data pointer
+ UINT n; // bytes available there
+ BYTE *q; // output window write pointer
+ UINT m; // bytes to end of window or read pointer
+
+ // copy input/output information to locals (UPDATE macro restores)
+ LOAD
+
+ // process input based on current state
+ for(;;) switch (s->mode)
+ {
+ case IBM_TYPE:
+ NEEDBITS(3)
+ t = (UINT)b & 7;
+ s->last = t & 1;
+ switch (t >> 1)
+ {
+ case 0: // stored
+ LuTracev((stderr, "inflate: stored block%s\n",
+ s->last ? " (last)" : ""));
+ DUMPBITS(3)
+ t = k & 7; // go to byte boundary
+ DUMPBITS(t)
+ s->mode = IBM_LENS; // get length of stored block
+ break;
+ case 1: // fixed
+ LuTracev((stderr, "inflate: fixed codes block%s\n",
+ s->last ? " (last)" : ""));
+ {
+ UINT bl, bd;
+ const inflate_huft *tl, *td;
+
+ inflate_trees_fixed(&bl, &bd, &tl, &td, z);
+ s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td);
+ if (s->sub.decode.codes == NULL)
+ {
+ r = Z_MEM_ERROR;
+ LEAVE
+ }
+ }
+ DUMPBITS(3)
+ s->mode = IBM_CODES;
+ break;
+ case 2: // dynamic
+ LuTracev((stderr, "inflate: dynamic codes block%s\n",
+ s->last ? " (last)" : ""));
+ DUMPBITS(3)
+ s->mode = IBM_TABLE;
+ break;
+ case 3: // illegal
+ DUMPBITS(3)
+ s->mode = IBM_BAD;
+ r = Z_DATA_ERROR;
+ LEAVE
+ }
+ break;
+ case IBM_LENS:
+ NEEDBITS(32)
+ if ((((~b) >> 16) & 0xffff) != (b & 0xffff))
+ {
+ s->mode = IBM_BAD;
+ r = Z_DATA_ERROR;
+ LEAVE
+ }
+ s->sub.left = (UINT)b & 0xffff;
+ b = k = 0; // dump bits
+ LuTracev((stderr, "inflate: stored length %u\n", s->sub.left));
+ s->mode = s->sub.left ? IBM_STORED : (s->last ? IBM_DRY : IBM_TYPE);
+ break;
+ case IBM_STORED:
+ if (n == 0)
+ LEAVE
+ NEEDOUT
+ t = s->sub.left;
+ if (t > n) t = n;
+ if (t > m) t = m;
+ CopyMemory(q, p, t);
+ p += t; n -= t;
+ q += t; m -= t;
+ if ((s->sub.left -= t) != 0)
+ break;
+ LuTracev((stderr, "inflate: stored end, %lu total out\n",
+ z->total_out + (q >= s->read ? q - s->read :
+ (s->end - s->read) + (q - s->window))));
+ s->mode = s->last ? IBM_DRY : IBM_TYPE;
+ break;
+ case IBM_TABLE:
+ NEEDBITS(14)
+ s->sub.trees.table = t = (UINT)b & 0x3fff;
+ // remove this section to workaround bug in pkzip
+ if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29)
+ {
+ s->mode = IBM_BAD;
+ r = Z_DATA_ERROR;
+ LEAVE
+ }
+ // end remove
+ t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f);
+ if ((s->sub.trees.blens = (UINT*)mir_calloc(t*sizeof(UINT))) == NULL)
+ {
+ r = Z_MEM_ERROR;
+ LEAVE
+ }
+ DUMPBITS(14)
+ s->sub.trees.index = 0;
+ LuTracev((stderr, "inflate: table sizes ok\n"));
+ s->mode = IBM_BTREE;
+ case IBM_BTREE:
+ while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10))
+ {
+ NEEDBITS(3)
+ s->sub.trees.blens[border[s->sub.trees.index++]] = (UINT)b & 7;
+ DUMPBITS(3)
+ }
+ while (s->sub.trees.index < 19)
+ s->sub.trees.blens[border[s->sub.trees.index++]] = 0;
+ s->sub.trees.bb = 7;
+ t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb,
+ &s->sub.trees.tb, s->hufts);
+ if (t != Z_OK)
+ {
+ r = t;
+ if (r == Z_DATA_ERROR)
+ {
+ mir_free(s->sub.trees.blens);
+ s->mode = IBM_BAD;
+ }
+ LEAVE
+ }
+ s->sub.trees.index = 0;
+ LuTracev((stderr, "inflate: bits tree ok\n"));
+ s->mode = IBM_DTREE;
+ case IBM_DTREE:
+ while (t = s->sub.trees.table,
+ s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f))
+ {
+ inflate_huft *h;
+ UINT i, j, c;
+
+ t = s->sub.trees.bb;
+ NEEDBITS(t)
+ h = s->sub.trees.tb + ((UINT)b & inflate_mask[t]);
+ t = h->bits;
+ c = h->base;
+ if (c < 16)
+ {
+ DUMPBITS(t)
+ s->sub.trees.blens[s->sub.trees.index++] = c;
+ }
+ else // c == 16..18
+ {
+ i = c == 18 ? 7 : c - 14;
+ j = c == 18 ? 11 : 3;
+ NEEDBITS(t + i)
+ DUMPBITS(t)
+ j += (UINT)b & inflate_mask[i];
+ DUMPBITS(i)
+ i = s->sub.trees.index;
+ t = s->sub.trees.table;
+ if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) ||
+ (c == 16 && i < 1))
+ {
+ mir_free(s->sub.trees.blens);
+ s->mode = IBM_BAD;
+ r = Z_DATA_ERROR;
+ LEAVE
+ }
+ c = c == 16 ? s->sub.trees.blens[i - 1] : 0;
+ do {
+ s->sub.trees.blens[i++] = c;
+ } while (--j);
+ s->sub.trees.index = i;
+ }
+ }
+ s->sub.trees.tb = NULL;
+ {
+ UINT bl, bd;
+ inflate_huft *tl, *td;
+ inflate_codes_statef *c;
+
+ bl = 9; // must be <= 9 for lookahead assumptions
+ bd = 6; // must be <= 9 for lookahead assumptions
+ t = s->sub.trees.table;
+ t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f),
+ s->sub.trees.blens, &bl, &bd, &tl, &td,
+ s->hufts);
+ if (t != Z_OK)
+ {
+ if (t == (UINT)Z_DATA_ERROR)
+ {
+ mir_free(s->sub.trees.blens);
+ s->mode = IBM_BAD;
+ }
+ r = t;
+ LEAVE
+ }
+ LuTracev((stderr, "inflate: trees ok\n"));
+ if ((c = inflate_codes_new(bl, bd, tl, td)) == NULL)
+ {
+ r = Z_MEM_ERROR;
+ LEAVE
+ }
+ s->sub.decode.codes = c;
+ }
+ mir_free(s->sub.trees.blens);
+ s->mode = IBM_CODES;
+ case IBM_CODES:
+ UPDATE
+ if ((r = inflate_codes(s, z, r)) != Z_STREAM_END)
+ return inflate_flush(s, z, r);
+ r = Z_OK;
+ mir_free(s->sub.decode.codes);
+ LOAD
+ LuTracev((stderr, "inflate: codes end, %lu total out\n",
+ z->total_out + (q >= s->read ? q - s->read :
+ (s->end - s->read) + (q - s->window))));
+ if (!s->last)
+ {
+ s->mode = IBM_TYPE;
+ break;
+ }
+ s->mode = IBM_DRY;
+ case IBM_DRY:
+ FLUSH
+ if (s->read != s->write)
+ LEAVE
+ s->mode = IBM_DONE;
+ case IBM_DONE:
+ r = Z_STREAM_END;
+ LEAVE
+ case IBM_BAD:
+ r = Z_DATA_ERROR;
+ LEAVE
+ default:
+ r = Z_STREAM_ERROR;
+ LEAVE
+ }
+}
+
+static int inflate_blocks_free(inflate_blocks_statef *s, z_streamp z)
+{
+ inflate_blocks_reset(s, z, NULL);
+ mir_free(s->window);
+ mir_free(s->hufts);
+ mir_free(s);
+ LuTracev((stderr, "inflate: blocks freed\n"));
+ return Z_OK;
+}
+
+// =============================================================
+
+// inftrees -- generate Huffman trees for efficient decoding
+// Copyright (C) 1995-1998 Mark Adler
+// For conditions of distribution and use, see copyright notice
+
+// Tables for deflate from PKZIP's appnote.txt.
+const UINT cplens[31] = { // Copy lengths for literal codes 257..285
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+ 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
+ // see note #13 above about 258
+const UINT cplext[31] = { // Extra bits for literal codes 257..285
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
+ 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112}; // 112==invalid
+const UINT cpdist[30] = { // Copy offsets for distance codes 0..29
+ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+ 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+ 8193, 12289, 16385, 24577};
+const UINT cpdext[30] = { // Extra bits for distance codes
+ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
+ 7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
+ 12, 12, 13, 13};
+
+// Huffman code decoding is performed using a multi-level table lookup.
+// The fastest way to decode is to simply build a lookup table whose
+// size is determined by the longest code. However, the time it takes
+// to build this table can also be a factor if the data being decoded
+// is not very long. The most common codes are necessarily the
+// shortest codes, so those codes dominate the decoding time, and hence
+// the speed. The idea is you can have a shorter table that decodes the
+// shorter, more probable codes, and then point to subsidiary tables for
+// the longer codes. The time it costs to decode the longer codes is
+// then traded against the time it takes to make longer tables.
+//
+// This results of this trade are in the variables lbits and dbits
+// below. lbits is the number of bits the first level table for literal/
+// length codes can decode in one step, and dbits is the same thing for
+// the distance codes. Subsequent tables are also less than or equal to
+// those sizes. These values may be adjusted either when all of the
+// codes are shorter than that, in which case the longest code length in
+// bits is used, or when the shortest code is *longer* than the requested
+// table size, in which case the length of the shortest code in bits is
+// used.
+//
+// There are two different values for the two tables, since they code a
+// different number of possibilities each. The literal/length table
+// codes 286 possible values, or in a flat code, a little over eight
+// bits. The distance table codes 30 possible values, or a little less
+// than five bits, flat. The optimum values for speed end up being
+// about one bit more than those, so lbits is 8+1 and dbits is 5+1.
+// The optimum values may differ though from machine to machine, and
+// possibly even between compilers. Your mileage may vary.
+
+// If BMAX needs to be larger than 16, then h and x[] should be ULONG.
+#define BMAX 15 // maximum bit length of any code
+
+static int huft_build(
+UINT *b, // code lengths in bits (all assumed <= BMAX)
+UINT n, // number of codes (assumed <= 288)
+UINT s, // number of simple-valued codes (0..s-1)
+const UINT *d, // list of base values for non-simple codes
+const UINT *e, // list of extra bits for non-simple codes
+inflate_huft * *t, // result: starting table
+UINT *m, // maximum lookup bits, returns actual
+inflate_huft *hp, // space for trees
+UINT *hn, // hufts used in space
+UINT *v) // working area: values in order of bit length
+// Given a list of code lengths and a maximum table size, make a set of
+// tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR
+// if the given code set is incomplete (the tables are still built in this
+// case), or Z_DATA_ERROR if the input is invalid.
+{
+
+ UINT a; // counter for codes of length k
+ UINT c[BMAX+1]; // bit length count table
+ UINT f; // i repeats in table every f entries
+ int g; // maximum code length
+ int h; // table level
+ register UINT i; // counter, current code
+ register UINT j; // counter
+ register int k; // number of bits in current code
+ int l; // bits per table (returned in m)
+ UINT mask; // (1 << w) - 1, to avoid cc -O bug on HP
+ register UINT *p; // pointer into c[], b[], or v[]
+ inflate_huft *q; // points to current table
+ struct inflate_huft_s r; // table entry for structure assignment
+ inflate_huft *u[BMAX]; // table stack
+ register int w; // bits before this table == (l * h)
+ UINT x[BMAX+1]; // bit offsets, then code stack
+ UINT *xp; // pointer into x
+ int y; // number of dummy codes added
+ UINT z; // number of entries in current table
+
+ // Generate counts for each bit length
+ p = c;
+#define C0 *p++ = 0;
+#define C2 C0 C0 C0 C0
+#define C4 C2 C2 C2 C2
+ C4; p; // clear c[]--assume BMAX+1 is 16
+ p = b; i = n;
+ do {
+ c[*p++]++; // assume all entries <= BMAX
+ } while (--i);
+ if (c[0] == n) // null input--all zero length codes
+ {
+ *t = (inflate_huft *)NULL;
+ *m = 0;
+ return Z_OK;
+ }
+
+ // Find minimum and maximum length, bound *m by those
+ l = *m;
+ for (j = 1; j <= BMAX; j++)
+ if (c[j])
+ break;
+ k = j; // minimum code length
+ if ((UINT)l < j)
+ l = j;
+ for (i = BMAX; i; i--)
+ if (c[i])
+ break;
+ g = i; // maximum code length
+ if ((UINT)l > i)
+ l = i;
+ *m = l;
+
+ // Adjust last length count to fill out codes, if needed
+ for (y = 1 << j; j < i; j++, y <<= 1)
+ if ((y -= c[j]) < 0)
+ return Z_DATA_ERROR;
+ if ((y -= c[i]) < 0)
+ return Z_DATA_ERROR;
+ c[i] += y;
+
+ // Generate starting offsets into the value table for each length
+ x[1] = j = 0;
+ p = c + 1; xp = x + 2;
+ while (--i) { // note that i == g from above
+ *xp++ = (j += *p++);
+ }
+
+ // Make a table of values in order of bit lengths
+ p = b; i = 0;
+ do {
+ if ((j = *p++) != 0)
+ v[x[j]++] = i;
+ } while (++i < n);
+ n = x[g]; // set n to length of v
+
+ // Generate the Huffman codes and for each, make the table entries
+ x[0] = i = 0; // first Huffman code is zero
+ p = v; // grab values in bit order
+ h = -1; // no tables yet--level -1
+ w = -l; // bits decoded == (l * h)
+ u[0] = (inflate_huft *)NULL; // just to keep compilers happy
+ q = (inflate_huft *)NULL; // ditto
+ z = 0; // ditto
+
+ // go through the bit lengths (k already is bits in shortest code)
+ for (; k <= g; k++)
+ {
+ a = c[k];
+ while (a--)
+ {
+ // here i is the Huffman code of length k bits for value *p
+ // make tables up to required level
+ while (k > w + l)
+ {
+ h++;
+ w += l; // previous table always l bits
+
+ // compute minimum size table less than or equal to l bits
+ z = g - w;
+ z = z > (UINT)l ? l : z; // table size upper limit
+ if ((f = 1 << (j = k - w)) > a + 1) // try a k-w bit table
+ { // too few codes for k-w bit table
+ f -= a + 1; // deduct codes from patterns left
+ xp = c + k;
+ if (j < z)
+ while (++j < z) // try smaller tables up to z bits
+ {
+ if ((f <<= 1) <= *++xp)
+ break; // enough codes to use up j bits
+ f -= *xp; // else deduct codes from patterns
+ }
+ }
+ z = 1 << j; // table entries for j-bit table
+
+ // allocate new table
+ if (*hn + z > MANY) // (note: doesn't matter for fixed)
+ return Z_DATA_ERROR; // overflow of MANY
+ u[h] = q = hp + *hn;
+ *hn += z;
+
+ // connect to last table, if there is one
+ if (h)
+ {
+ x[h] = i; // save pattern for backing up
+ r.bits = (BYTE)l; // bits to dump before this table
+ r.exop = (BYTE)j; // bits in this table
+ j = i >> (w - l);
+ r.base = (UINT)(q - u[h-1] - j); // offset to this table
+ u[h-1][j] = r; // connect to last table
+ }
+ else
+ *t = q; // first table is returned result
+ }
+
+ // set up table entry in r
+ r.bits = (BYTE)(k - w);
+ if (p >= v + n)
+ r.exop = 128 + 64; // out of values--invalid code
+ else if (*p < s)
+ {
+ r.exop = (BYTE)(*p < 256 ? 0 : 32 + 64); // 256 is end-of-block
+ r.base = *p++; // simple code is just the value
+ }
+ else
+ {
+ r.exop = (BYTE)(e[*p - s] + 16 + 64);// non-simple--look up in lists
+ r.base = d[*p++ - s];
+ }
+
+ // fill code-like entries with r
+ f = 1 << (k - w);
+ for (j = i >> w; j < z; j += f)
+ q[j] = r;
+
+ // backwards increment the k-bit code i
+ for (j = 1 << (k - 1); i & j; j >>= 1)
+ i ^= j;
+ i ^= j;
+
+ // backup over finished tables
+ mask = (1 << w) - 1; // needed on HP, cc -O bug
+ while ((i & mask) != x[h])
+ {
+ h--; // don't need to update q
+ w -= l;
+ mask = (1 << w) - 1;
+ }
+ }
+ }
+ // Return Z_BUF_ERROR if we were given an incomplete table
+ return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK;
+}
+
+static int inflate_trees_bits(
+UINT *c, // 19 code lengths
+UINT *bb, // bits tree desired/actual depth
+inflate_huft * *tb, // bits tree result
+inflate_huft *hp) // space for trees
+{
+ int r;
+ UINT hn = 0; // hufts used in space
+ UINT *v; // work area for huft_build
+
+ if ((v = (UINT*)mir_calloc(19*sizeof(UINT))) == NULL)
+ return Z_MEM_ERROR;
+ r = huft_build(c, 19, 19, (UINT*)NULL, (UINT*)NULL,
+ tb, bb, hp, &hn, v);
+ if (r == Z_BUF_ERROR || *bb == 0)
+ r = Z_DATA_ERROR;
+ mir_free(v);
+ return r;
+}
+
+static int inflate_trees_dynamic(
+UINT nl, // number of literal/length codes
+UINT nd, // number of distance codes
+UINT *c, // that many (total) code lengths
+UINT *bl, // literal desired/actual bit depth
+UINT *bd, // distance desired/actual bit depth
+inflate_huft * *tl, // literal/length tree result
+inflate_huft * *td, // distance tree result
+inflate_huft *hp) // space for trees
+{
+ int r;
+ UINT hn = 0; // hufts used in space
+ UINT *v; // work area for huft_build
+
+ // allocate work area
+ if ((v = (UINT*)mir_calloc(288*sizeof(UINT))) == NULL)
+ return Z_MEM_ERROR;
+
+ // build literal/length tree
+ r = huft_build(c, nl, 257, cplens, cplext, tl, bl, hp, &hn, v);
+ if (r != Z_OK || *bl == 0)
+ {
+ if (r != Z_DATA_ERROR && r != Z_MEM_ERROR)
+ r = Z_DATA_ERROR;
+ mir_free(v);
+ return r;
+ }
+
+ // build distance tree
+ r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, hp, &hn, v);
+ if (r != Z_OK || (*bd == 0 && nl > 257))
+ {
+ if (r == Z_BUF_ERROR || (r != Z_DATA_ERROR && r != Z_MEM_ERROR))
+ r = Z_DATA_ERROR;
+ mir_free(v);
+ return r;
+ }
+
+ // done
+ mir_free(v);
+ return Z_OK;
+}
+
+static int inflate_trees_fixed(
+UINT *bl, // literal desired/actual bit depth
+UINT *bd, // distance desired/actual bit depth
+const inflate_huft **tl, // literal/length tree result
+const inflate_huft **td, // distance tree result
+z_streamp strm) // for memory allocation
+{
+ *bl = fixed_bl;
+ *bd = fixed_bd;
+ *tl = fixed_tl;
+ *td = fixed_td;
+ strm;
+ return Z_OK;
+}
+
+// =============================================================
+
+// inffast -- process literals and length/distance pairs fast
+// Copyright (C) 1995-1998 Mark Adler
+// For conditions of distribution and use, see copyright notice
+
+// macros for bit input with no checking and for returning unused bytes
+#define GRABBITS(j) {while(k<(j)){b|=((ULONG)NEXTBYTE)<<k;k+=8;}}
+#define UNGRAB {c=z->avail_in-n;c=(k>>3)<c?k>>3:c;n+=c;p-=c;k-=c<<3;}
+
+// Called with number of bytes left to write in window at least 258
+// (the maximum string length) and number of input bytes available
+// at least ten. The ten bytes are six bytes for the longest length/
+// distance pair plus four bytes for overloading the bit buffer.
+
+static int inflate_fast(
+UINT bl, UINT bd,
+const inflate_huft *tl,
+const inflate_huft *td, // need separate declaration for Borland C++
+inflate_blocks_statef *s,
+z_streamp z)
+{
+ const inflate_huft *t; // temporary pointer
+ UINT e; // extra bits or operation
+ ULONG b; // bit buffer
+ UINT k; // bits in bit buffer
+ BYTE *p; // input data pointer
+ UINT n; // bytes available there
+ BYTE *q; // output window write pointer
+ UINT m; // bytes to end of window or read pointer
+ UINT ml; // mask for literal/length tree
+ UINT md; // mask for distance tree
+ UINT c; // bytes to copy
+ UINT d; // distance back to copy from
+ BYTE *r; // copy source pointer
+
+ // load input, output, bit values
+ LOAD
+
+ // initialize masks
+ ml = inflate_mask[bl];
+ md = inflate_mask[bd];
+
+ // do until not enough input or output space for fast loop
+ do { // assume called with m >= 258 && n >= 10
+ // get literal/length code
+ GRABBITS(20) // max bits for literal/length code
+ if ((e = (t = tl + ((UINT)b & ml))->exop) == 0)
+ {
+ DUMPBITS(t->bits)
+ LuTracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+ "inflate: * literal '%c'\n" :
+ "inflate: * literal 0x%02x\n", t->base));
+ *q++ = (BYTE)t->base;
+ m--;
+ continue;
+ }
+ for (;;) {
+ DUMPBITS(t->bits)
+ if (e & 16)
+ {
+ // get extra bits for length
+ e &= 15;
+ c = t->base + ((UINT)b & inflate_mask[e]);
+ DUMPBITS(e)
+ LuTracevv((stderr, "inflate: * length %u\n", c));
+
+ // decode distance base of block to copy
+ GRABBITS(15); // max bits for distance code
+ e = (t = td + ((UINT)b & md))->exop;
+ for (;;) {
+ DUMPBITS(t->bits)
+ if (e & 16)
+ {
+ // get extra bits to add to distance base
+ e &= 15;
+ GRABBITS(e) // get extra bits (up to 13)
+ d = t->base + ((UINT)b & inflate_mask[e]);
+ DUMPBITS(e)
+ LuTracevv((stderr, "inflate: * distance %u\n", d));
+
+ // do the copy
+ m -= c;
+ r = q - d;
+ if (r < s->window) // wrap if needed
+ {
+ do {
+ r += s->end - s->window; // force pointer in window
+ } while (r < s->window); // covers invalid distances
+ e = (UINT) (s->end - r);
+ if (c > e)
+ {
+ c -= e; // wrapped copy
+ do {
+ *q++ = *r++;
+ } while (--e);
+ r = s->window;
+ do {
+ *q++ = *r++;
+ } while (--c);
+ }
+ else // normal copy
+ {
+ *q++ = *r++; c--;
+ *q++ = *r++; c--;
+ do {
+ *q++ = *r++;
+ } while (--c);
+ }
+ }
+ else // normal copy
+ {
+ *q++ = *r++; c--;
+ *q++ = *r++; c--;
+ do {
+ *q++ = *r++;
+ } while (--c);
+ }
+ break;
+ }
+ else if ((e & 64) == 0)
+ {
+ t += t->base;
+ e = (t += ((UINT)b & inflate_mask[e]))->exop;
+ }
+ else
+ {
+ UNGRAB
+ UPDATE
+ return Z_DATA_ERROR;
+ }
+ };
+ break;
+ }
+ if ((e & 64) == 0)
+ {
+ t += t->base;
+ if ((e = (t += ((UINT)b & inflate_mask[e]))->exop) == 0)
+ {
+ DUMPBITS(t->bits)
+ LuTracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+ "inflate: * literal '%c'\n" :
+ "inflate: * literal 0x%02x\n", t->base));
+ *q++ = (BYTE)t->base;
+ m--;
+ break;
+ }
+ }
+ else if (e & 32)
+ {
+ LuTracevv((stderr, "inflate: * end of block\n"));
+ UNGRAB
+ UPDATE
+ return Z_STREAM_END;
+ }
+ else
+ {
+ UNGRAB
+ UPDATE
+ return Z_DATA_ERROR;
+ }
+ };
+ } while (m >= 258 && n >= 10);
+
+ // not enough input or output--restore pointers and return
+ UNGRAB
+ UPDATE
+ return Z_OK;
+}
+
+// =============================================================
+
+// crc32 -- compute the CRC-32 of a data stream
+// Copyright (C) 1995-1998 Mark Adler
+// For conditions of distribution and use, see copyright notice
+
+// Table of CRC-32's of all single-byte values (made by make_crc_table)
+const ULONG crc_table[256] = {
+ 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
+ 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
+ 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
+ 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
+ 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
+ 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
+ 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
+ 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
+ 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
+ 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
+ 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
+ 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
+ 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
+ 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
+ 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
+ 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
+ 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
+ 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
+ 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
+ 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
+ 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
+ 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
+ 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
+ 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
+ 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
+ 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
+ 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
+ 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
+ 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
+ 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
+ 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
+ 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
+ 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
+ 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
+ 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
+ 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
+ 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
+ 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
+ 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
+ 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
+ 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
+ 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
+ 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
+ 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
+ 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
+ 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
+ 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
+ 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
+ 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
+ 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
+ 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
+ 0x2d02ef8dL
+};
+
+#define CRC_DO1(buf) crc = crc_table[((int)crc^(*buf++))&0xff]^(crc>>8);
+#define CRC_DO2(buf) CRC_DO1(buf); CRC_DO1(buf);
+#define CRC_DO4(buf) CRC_DO2(buf); CRC_DO2(buf);
+#define CRC_DO8(buf) CRC_DO4(buf); CRC_DO4(buf);
+
+// Update a running crc with the bytes buf[0..len-1] and return the updated
+// crc. If buf is NULL, this function returns the required initial value
+// for the crc. Pre- and post-conditioning (one's complement) is performed
+// within this function so it shouldn't be done by the application.
+static ULONG ucrc32(ULONG crc,const BYTE *buf,UINT len)
+{
+ if(buf==NULL) return 0L;
+ crc=crc^0xffffffffL;
+ while (len>=8) { CRC_DO8(buf); len-=8; }
+ if(len) do { CRC_DO1(buf); } while(--len);
+ return crc^0xffffffffL;
+}
+
+// =============================================================
+
+// some decryption routines
+
+#define CRC32(c, b) (crc_table[((int)(c)^(b))&0xff]^((c)>>8))
+void Uupdate_keys(unsigned long *keys,char c)
+{
+ keys[0]=CRC32(keys[0],c);
+ keys[1]+=keys[0]&0xFF;
+ keys[1]=keys[1]*134775813L+1;
+ keys[2]=CRC32(keys[2],keys[1]>>24);
+}
+
+static char Udecrypt_byte(unsigned long *keys)
+{
+ unsigned temp=((unsigned)keys[2]&0xffff)|2;
+ return (char)(((temp * (temp^1))>>8)&0xff);
+}
+
+static char zdecode(unsigned long *keys,char c)
+{
+ c^=Udecrypt_byte(keys);
+ Uupdate_keys(keys,c);
+ return c;
+}
+
+// =============================================================
+
+// adler32 -- compute the Adler-32 checksum of a data stream
+// Copyright (C) 1995-1998 Mark Adler
+// For conditions of distribution and use, see copyright notice
+
+#define BASE 65521L // largest prime smaller than 65536
+#define NMAX 5552 // largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1
+
+#define AD_DO1(buf,i) {s1+=buf[i]; s2+=s1;}
+#define AD_DO2(buf,i) AD_DO1(buf,i); AD_DO1(buf,i+1);
+#define AD_DO4(buf,i) AD_DO2(buf,i); AD_DO2(buf,i+2);
+#define AD_DO8(buf,i) AD_DO4(buf,i); AD_DO4(buf,i+4);
+#define AD_DO16(buf) AD_DO8(buf,0); AD_DO8(buf,8);
+
+// Update a running Adler-32 checksum with the bytes buf[0..len-1] and
+// return the updated checksum. If buf is NULL, this function returns
+// the required initial value for the checksum.
+// An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
+// much faster.
+static ULONG adler32(ULONG adler,const BYTE *buf,UINT len)
+{
+ unsigned long s1=adler&0xffff;
+ unsigned long s2=(adler>>16)&0xffff;
+ int k;
+ if(buf==NULL) return 1L;
+ while(len > 0) {
+ k=len<NMAX?len:NMAX;
+ len-=k;
+ while(k>=16) {
+ AD_DO16(buf);
+ buf += 16;
+ k-=16;
+ }
+ if(k!=0) do {
+ s1+=*buf++;
+ s2+=s1;
+ } while(--k);
+ s1%=BASE;
+ s2%=BASE;
+ }
+ return (s2<<16)|s1;
+}
+
+// =============================================================
+
+// inflate -- zlib interface to inflate modules
+// Copyright (C) 1995-1998 Mark Adler
+// For conditions of distribution and use, see copyright notice
+
+typedef enum {
+ IM_METHOD, // waiting for method byte
+ IM_FLAG, // waiting for flag byte
+ IM_DICT4, // four dictionary check bytes to go
+ IM_DICT3, // three dictionary check bytes to go
+ IM_DICT2, // two dictionary check bytes to go
+ IM_DICT1, // one dictionary check byte to go
+ IM_DICT0, // waiting for dictionary
+ IM_BLOCKS, // decompressing blocks
+ IM_CHECK4, // four check bytes to go
+ IM_CHECK3, // three check bytes to go
+ IM_CHECK2, // two check bytes to go
+ IM_CHECK1, // one check byte to go
+ IM_DONE, // finished check, done
+ IM_BAD} // got an error--stay here
+inflate_mode;
+
+// inflate private state
+struct internal_state {
+ // mode
+ inflate_mode mode; // current inflate mode
+ // mode dependent information
+ union {
+ UINT method; // if IM_FLAGS, method byte
+ struct {
+ ULONG was; // computed check value
+ ULONG need; // stream check value
+ } check; // if CHECK, check values to compare
+ UINT marker; // if IM_BAD, inflateSync's marker bytes count
+ } sub; // submode
+ // mode independent information
+ int nowrap; // flag for no wrapper
+ UINT wbits; // log2(window size) (8..15, defaults to 15)
+ inflate_blocks_statef *blocks; // current inflate_blocks state
+};
+
+static int inflateReset(z_streamp z)
+{
+ if(z==NULL || z->state==NULL)
+ return Z_STREAM_ERROR;
+ z->total_in=z->total_out=0;
+ z->state->mode=z->state->nowrap?IM_BLOCKS:IM_METHOD;
+ inflate_blocks_reset(z->state->blocks, z, NULL);
+ LuTracev((stderr,"inflate: reset\n"));
+ return Z_OK;
+}
+
+static int inflateEnd(z_streamp z)
+{
+ if(z==NULL || z->state==NULL)
+ return Z_STREAM_ERROR;
+ if(z->state->blocks != NULL)
+ inflate_blocks_free(z->state->blocks, z);
+ mir_free(z->state);
+ z->state = NULL;
+ LuTracev((stderr,"inflate: end\n"));
+ return Z_OK;
+}
+
+static int inflateInit2(z_streamp z)
+{
+ int w=-15; // MAX_WBITS: 32K LZ77 window.
+
+ // Warning: reducing MAX_WBITS makes this code unable to extract
+ // .gz files created by gzip.
+ //
+ // The memory requirements for deflate are (in bytes):
+ // (1 << (windowBits+2)) + (1 << (memLevel+9))
+ // that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values)
+ // plus a few kilobytes for small objects. For example, if you want to reduce
+ // the default memory requirements from 256K to 128K, compile with
+ // make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
+ // Of course this will generally degrade compression (there's no free lunch).
+ //
+ // The memory requirements for inflate are (in bytes) 1 << windowBits
+ // that is, 32K for windowBits=15 (default value) plus a few kilobytes
+ // for small objects.
+
+ // initialize state
+ if(z == NULL) return Z_STREAM_ERROR;
+ if((z->state=(struct internal_state *)mir_calloc(sizeof(struct internal_state)))==NULL)
+ return Z_MEM_ERROR;
+ z->state->blocks=NULL;
+ // handle undocumented nowrap option (no zlib header or check)
+ z->state->nowrap=0;
+ if(w < 0) {
+ w=-w;
+ z->state->nowrap=1;
+ }
+ // set window size
+ if(w < 8 || w > 15) {
+ inflateEnd(z);
+ return Z_STREAM_ERROR;
+ }
+ z->state->wbits=(UINT)w;
+ // create inflate_blocks state
+ if((z->state->blocks=inflate_blocks_new(z,z->state->nowrap?NULL:adler32,(UINT)1<<w))== NULL) {
+ inflateEnd(z);
+ return Z_MEM_ERROR;
+ }
+ LuTracev((stderr,"inflate: allocated\n"));
+ // reset state
+ inflateReset(z);
+ return Z_OK;
+}
+
+#define IM_NEEDBYTE { if(z->avail_in==0) return r;r=f;}
+#define IM_NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++)
+int inflate(z_streamp z,int f)
+{
+ int r;
+ UINT b;
+ if(z==NULL || z->state==NULL || z->next_in==NULL)
+ return Z_STREAM_ERROR;
+ f=(f==Z_FINISH)?Z_BUF_ERROR:Z_OK;
+ r=Z_BUF_ERROR;
+ for(;;)
+ switch(z->state->mode) {
+ case IM_METHOD:
+ IM_NEEDBYTE
+ if(((z->state->sub.method = IM_NEXTBYTE) & 0xf) != Z_DEFLATED) {
+ z->state->mode=IM_BAD;
+ z->state->sub.marker=5; // can't try inflateSync
+ break;
+ }
+ if((z->state->sub.method>>4)+8 > z->state->wbits) {
+ z->state->mode=IM_BAD;
+ z->state->sub.marker=5; // can't try inflateSync
+ break;
+ }
+ z->state->mode = IM_FLAG;
+ case IM_FLAG:
+ IM_NEEDBYTE
+ b = IM_NEXTBYTE;
+ if(((z->state->sub.method << 8) + b) % 31) {
+ z->state->mode=IM_BAD;
+ z->state->sub.marker = 5; // can't try inflateSync
+ break;
+ }
+ LuTracev((stderr,"inflate: zlib header ok\n"));
+ if(!(b & PRESET_DICT)) {
+ z->state->mode = IM_BLOCKS;
+ break;
+ }
+ z->state->mode=IM_DICT4;
+ case IM_DICT4:
+ IM_NEEDBYTE
+ z->state->sub.check.need=(ULONG)IM_NEXTBYTE<<24;
+ z->state->mode=IM_DICT3;
+ case IM_DICT3:
+ IM_NEEDBYTE
+ z->state->sub.check.need+=(ULONG)IM_NEXTBYTE<<16;
+ z->state->mode=IM_DICT2;
+ case IM_DICT2:
+ IM_NEEDBYTE
+ z->state->sub.check.need+=(ULONG)IM_NEXTBYTE<<8;
+ z->state->mode=IM_DICT1;
+ case IM_DICT1:
+ IM_NEEDBYTE; r;
+ z->state->sub.check.need+=(ULONG)IM_NEXTBYTE;
+ z->adler=z->state->sub.check.need;
+ z->state->mode=IM_DICT0;
+ return Z_NEED_DICT;
+ case IM_DICT0:
+ z->state->mode=IM_BAD;
+ z->state->sub.marker=0; // can try inflateSync
+ return Z_STREAM_ERROR;
+ case IM_BLOCKS:
+ r=inflate_blocks(z->state->blocks,z,r);
+ if(r==Z_DATA_ERROR) {
+ z->state->mode=IM_BAD;
+ z->state->sub.marker=0; // can try inflateSync
+ break;
+ }
+ if(r==Z_OK) r=f;
+ if(r!=Z_STREAM_END) return r;
+ r=f;
+ inflate_blocks_reset(z->state->blocks,z,&z->state->sub.check.was);
+ if(z->state->nowrap) {
+ z->state->mode=IM_DONE;
+ break;
+ }
+ z->state->mode=IM_CHECK4;
+ case IM_CHECK4:
+ IM_NEEDBYTE
+ z->state->sub.check.need=(ULONG)IM_NEXTBYTE<<24;
+ z->state->mode=IM_CHECK3;
+ case IM_CHECK3:
+ IM_NEEDBYTE
+ z->state->sub.check.need+=(ULONG)IM_NEXTBYTE<<16;
+ z->state->mode = IM_CHECK2;
+ case IM_CHECK2:
+ IM_NEEDBYTE
+ z->state->sub.check.need+=(ULONG)IM_NEXTBYTE<<8;
+ z->state->mode=IM_CHECK1;
+ case IM_CHECK1:
+ IM_NEEDBYTE
+ z->state->sub.check.need+=(ULONG)IM_NEXTBYTE;
+ if(z->state->sub.check.was!=z->state->sub.check.need) {
+ z->state->mode=IM_BAD;
+ z->state->sub.marker=5; // can't try inflateSync
+ break;
+ }
+ LuTracev((stderr,"inflate: zlib check ok\n"));
+ z->state->mode=IM_DONE;
+ case IM_DONE:
+ return Z_STREAM_END;
+ case IM_BAD:
+ return Z_DATA_ERROR;
+ default:
+ return Z_STREAM_ERROR;
+ }
+}
+
+// =============================================================
+
+// IO on .zip files using zlib
+// Version 0.15 beta, Mar 19th, 1998,
+// Read unzip.h for more info
+// unzip 0.15 Copyright 1998 Gilles Vollant
+
+#define UNZ_BUFSIZE (16384)
+#define UNZ_MAXFILENAMEINZIP (256)
+#define SIZECENTRALDIRITEM (0x2e)
+#define SIZEZIPLOCALHEADER (0x1e)
+
+// unz_file_info_interntal contain internal info about a file in zipfile
+typedef struct unz_file_info_internal_s {
+ ULONG offset_curfile; // relative offset of local header 4 bytes
+} unz_file_info_internal;
+
+typedef struct {
+ BOOL is_handle; // either a handle or memory
+ BOOL canseek;
+ // for handles:
+ HANDLE h;
+ BOOL herr;
+ unsigned long initial_offset;
+ BOOL mustclosehandle;
+ // for memory:
+ void *buf;
+ unsigned int len,pos; // if it's a memory block
+} LUFILE;
+
+static LUFILE *lufopen(void *z,unsigned int len,DWORD flags,ZRESULT *err)
+{
+ HANDLE h=NULL;
+ BOOL canseek=FALSE,mustclosehandle=FALSE;
+ LUFILE *lf;
+ *err=ZR_OK;
+ if(flags!=ZIP_HANDLE && flags!=ZIP_FILENAME && flags!=ZIP_MEMORY) { *err=ZR_ARGS; return NULL; }
+ if(flags==ZIP_HANDLE || flags==ZIP_FILENAME) {
+ if(flags==ZIP_HANDLE) {
+ HANDLE hf = z;
+ h=hf;
+ mustclosehandle=FALSE;
+#ifdef DuplicateHandle
+ if(!DuplicateHandle(GetCurrentProcess(),hf,GetCurrentProcess(),&h,0,FALSE,DUPLICATE_SAME_ACCESS))
+ mustclosehandle=TRUE;
+#endif
+ }
+ else {
+ h=CreateFile((const TCHAR*)z,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
+ if(h==INVALID_HANDLE_VALUE) { *err=ZR_NOFILE; return NULL; }
+ mustclosehandle=TRUE;
+ }
+ // test if we can seek on it. We can't use GetFileType(h)==FILE_TYPE_DISK since it's not on CE.
+ canseek=(SetFilePointer(h,0,0,FILE_CURRENT)!=0xFFFFFFFF);
+ }
+ lf=mir_alloc(sizeof(LUFILE));
+ if(lf==NULL) { if(mustclosehandle) CloseHandle(h); return NULL; }
+ if(flags==ZIP_HANDLE || flags==ZIP_FILENAME) {
+ lf->is_handle=TRUE; lf->mustclosehandle=mustclosehandle;
+ lf->canseek=canseek;
+ lf->h=h; lf->herr=FALSE;
+ lf->initial_offset=0;
+ if(canseek) lf->initial_offset=SetFilePointer(h,0,NULL,FILE_CURRENT);
+ }
+ else {
+ lf->is_handle=FALSE;
+ lf->canseek=TRUE;
+ lf->mustclosehandle=FALSE;
+ lf->buf=z; lf->len=len; lf->pos=0; lf->initial_offset=0;
+ }
+ *err=ZR_OK;
+ return lf;
+}
+
+static int lufclose(LUFILE *stream) {
+ if(stream==NULL) return EOF;
+ if(stream->mustclosehandle) CloseHandle(stream->h);
+ mir_free(stream);
+ return 0;
+}
+
+static int luferror(LUFILE *stream) {
+ if(stream->is_handle && stream->herr) return 1;
+ return 0;
+}
+
+static long int luftell(LUFILE *stream)
+{
+ if(stream->is_handle && stream->canseek)
+ return SetFilePointer(stream->h,0,NULL,FILE_CURRENT)-stream->initial_offset;
+ if(stream->is_handle) return 0;
+ return stream->pos;
+}
+
+static int lufseek(LUFILE *stream,long offset,int whence)
+{
+ if(stream->is_handle && stream->canseek) {
+ if(whence==SEEK_SET) SetFilePointer(stream->h,stream->initial_offset+offset,0,FILE_BEGIN);
+ else if(whence==SEEK_CUR) SetFilePointer(stream->h,offset,NULL,FILE_CURRENT);
+ else if(whence==SEEK_END) SetFilePointer(stream->h,offset,NULL,FILE_END);
+ else return 19; // EINVAL
+ return 0;
+ }
+ if(stream->is_handle) return 29; // ESPIPE
+ if(whence==SEEK_SET) stream->pos=offset;
+ else if(whence==SEEK_CUR) stream->pos+=offset;
+ else if(whence==SEEK_END) stream->pos=stream->len+offset;
+ return 0;
+}
+
+static size_t lufread(void *ptr,size_t size,size_t n,LUFILE *stream)
+{
+ unsigned int toread;
+ toread=(unsigned int)(size*n);
+ if(stream->is_handle) {
+ DWORD red; BOOL res;
+ res=ReadFile(stream->h,ptr,toread,&red,NULL);
+ if(!res) stream->herr=TRUE;
+ return red/size;
+ }
+ if(stream->pos+toread > stream->len) toread=stream->len-stream->pos;
+ CopyMemory(ptr,(char*)stream->buf + stream->pos,toread);
+ stream->pos+=toread;
+ return toread/size;
+}
+
+// file_in_zip_read_info_s contain internal information about a file in zipfile,
+// when reading and decompress it
+typedef struct {
+ char *read_buffer; // internal buffer for compressed data
+ z_stream stream; // zLib stream structure for inflate
+
+ ULONG pos_in_zipfile; // position in byte on the zipfile, for fseek
+ ULONG stream_initialised; // flag set if stream structure is initialised
+
+ ULONG offset_local_extrafield; // offset of the local extra field
+ UINT size_local_extrafield; // size of the local extra field
+ ULONG pos_local_extrafield; // position in the local extra field in read
+
+ ULONG crc32; // crc32 of all data uncompressed
+ ULONG crc32_wait; // crc32 we must obtain after decompress all
+ ULONG rest_read_compressed; // number of byte to be decompressed
+ ULONG rest_read_uncompressed; //number of byte to be obtained after decomp
+ LUFILE* file; // io structore of the zipfile
+ ULONG compression_method; // compression method (0==store)
+ ULONG byte_before_the_zipfile; // byte before the zipfile, (>0 for sfx)
+
+ BOOL encrypted; // is it encrypted?
+ unsigned long keys[3]; // decryption keys, initialized by unzOpenCurrentFile
+ int encheadleft; // the first call(s) to unzReadCurrentFile will read this many encryption-header bytes first
+ char crcenctest; // if encrypted, we'll check the encryption buffer against this
+} file_in_zip_read_info_s;
+
+// unz_s contains internal information about the zipfile
+typedef struct
+{
+ LUFILE* file; // io structore of the zipfile
+ unz_global_info gi; // public global information
+ ULONG byte_before_the_zipfile; // byte before the zipfile, (>0 for sfx)
+ ULONG num_file; // number of the current file in the zipfile
+ ULONG pos_in_central_dir; // pos of the current file in the central dir
+ ULONG current_file_ok; // flag about the usability of the current file
+ ULONG central_pos; // position of the beginning of the central dir
+
+ ULONG size_central_dir; // size of the central directory
+ ULONG offset_central_dir; // offset of start of central directory with respect to the starting disk number
+
+ unz_file_info cur_file_info; // public info about the current file in zip
+ unz_file_info_internal cur_file_info_internal; // private info about it
+ file_in_zip_read_info_s* pfile_in_zip_read; // structure about the current file if we are decompressing it
+} unz_s, *unzFile;
+
+// Read a byte from a gz_stream; update next_in and avail_in. Return EOF
+// for end of file.
+// IN assertion: the stream s has been sucessfully opened for reading.
+static int unzlocal_getByte(LUFILE *fin,int *pi)
+{
+ unsigned char c;
+ int err=(int)lufread(&c,1,1,fin);
+ if(err==1) {
+ *pi=(int)c;
+ return UNZ_OK;
+ } else {
+ if(luferror(fin)) return UNZ_ERRNO;
+ return UNZ_EOF;
+ }
+}
+
+// Reads a long in LSB order from the given gz_stream. Sets
+static int unzlocal_getShort(LUFILE *fin,ULONG *pX)
+{
+ ULONG x ;
+ int i,err;
+ err=unzlocal_getByte(fin,&i);
+ x=(ULONG)i;
+ if(err==UNZ_OK) err=unzlocal_getByte(fin,&i);
+ x+=((ULONG)i)<<8;
+ if(err==UNZ_OK) *pX = x;
+ else *pX = 0;
+ return err;
+}
+
+static int unzlocal_getLong(LUFILE *fin,ULONG *pX)
+{
+ ULONG x ;
+ int i,err;
+ err=unzlocal_getByte(fin,&i);
+ x=(ULONG)i;
+ if(err==UNZ_OK) err=unzlocal_getByte(fin,&i);
+ x+=((ULONG)i)<<8;
+ if(err==UNZ_OK) err=unzlocal_getByte(fin,&i);
+ x+=((ULONG)i)<<16;
+ if(err==UNZ_OK) err=unzlocal_getByte(fin,&i);
+ x+=((ULONG)i)<<24;
+ if(err==UNZ_OK) *pX=x;
+ else *pX = 0;
+ return err;
+}
+
+// Compare two filename (s,w).
+// If iCaseSenisivity = 1, comparision is case sensitiv (like lstrcmp)
+// If iCaseSenisivity = 2, comparision is not case sensitive (like lstrcmpi)
+// allows wildcards in w, wildcmp implementation
+static BOOL unzStringFileNameMatch(const char *s,const char *w,int iCaseSensitivity)
+{
+ int i,l;
+ for(;;++w,++s)
+ switch(*w) {
+ case '*':
+ if(w[1]=='\0') return TRUE; /* optimize */
+ l=lstrlenA(s);
+ for(i=0;i<=l;++i)
+ if(unzStringFileNameMatch(w+1,s+i,iCaseSensitivity))
+ return TRUE;
+ return FALSE;
+ case '?':
+ if(*s=='\0') return FALSE;
+ break;
+ default:
+ if((iCaseSensitivity==1)?(*w!=*s):(_tolower(*w)!=_tolower(*s)))
+ return FALSE;
+ if(*w=='\0') return TRUE;
+ break;
+ }
+}
+
+#define BUFREADCOMMENT (0x400)
+
+// Locate the Central directory of a zipfile (at the end, just before
+// the global comment). Lu bugfix 2005.07.26 - returns 0xFFFFFFFF if not found,
+// rather than 0, since 0 is a valid central-dir-location for an empty zipfile.
+static ULONG unzlocal_SearchCentralDir(LUFILE *fin)
+{ ULONG uSizeFile,uMaxBack,uPosFound,uBackRead;
+ unsigned char *buf;
+ ULONG uReadSize,uReadPos ;
+ int i;
+
+ if(lufseek(fin,0,SEEK_END)) return 0xFFFFFFFF;
+ uSizeFile=luftell(fin);
+ uMaxBack=0xffff; // maximum size of global comment
+ if(uMaxBack>uSizeFile) uMaxBack=uSizeFile;
+ buf=(unsigned char*)mir_alloc(BUFREADCOMMENT+4);
+ if(buf==NULL) return 0xFFFFFFFF;
+ uPosFound=0xFFFFFFFF;
+
+ uBackRead=4;
+ while(uBackRead<uMaxBack) {
+ if(uBackRead+BUFREADCOMMENT>uMaxBack) uBackRead=uMaxBack;
+ else uBackRead+=BUFREADCOMMENT;
+ uReadPos=uSizeFile-uBackRead ;
+ uReadSize=((BUFREADCOMMENT+4)<(uSizeFile-uReadPos)) ? (BUFREADCOMMENT+4) : (uSizeFile-uReadPos);
+ if(lufseek(fin,uReadPos,SEEK_SET)!=0) break;
+ if(lufread(buf,(UINT)uReadSize,1,fin)!=1) break;
+ for(i=(int)uReadSize-3; (i--)>=0;) {
+ if(((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) {
+ uPosFound=uReadPos+i;
+ break;
+ }
+ }
+ if(uPosFound!=0) break;
+ }
+ if(buf!=NULL) mir_free(buf);
+ return uPosFound;
+}
+
+static int unzGoToFirstFile(unzFile file);
+static int unzCloseCurrentFile(unzFile file);
+
+// Open a Zip file.
+// If the zipfile cannot be opened (file don't exist or in not valid), return NULL.
+// Otherwise, the return value is a unzFile Handle, usable with other unzip functions
+unzFile unzOpenInternal(LUFILE *fin)
+{
+ int err=UNZ_OK;
+ unz_s us,*s;
+ ULONG central_pos,uL;
+ ULONG number_disk; // number of the current dist, used for spanning ZIP, unsupported, always 0
+ ULONG number_disk_with_CD; // number the the disk with central dir, used for spaning ZIP, unsupported, always 0
+ ULONG number_entry_CD; // total number of entries in the central dir (same than number_entry on nospan)
+
+ if(fin==NULL) return NULL;
+ central_pos=unzlocal_SearchCentralDir(fin);
+ if(central_pos==0xFFFFFFFF) err=UNZ_ERRNO;
+ if(lufseek(fin,central_pos,SEEK_SET)!=0) err=UNZ_ERRNO;
+ // the signature, already checked
+ if(unzlocal_getLong(fin,&uL)!=UNZ_OK) err=UNZ_ERRNO;
+ // number of this disk
+ if(unzlocal_getShort(fin,&number_disk)!=UNZ_OK) err=UNZ_ERRNO;
+ // number of the disk with the start of the central directory
+ if(unzlocal_getShort(fin,&number_disk_with_CD)!=UNZ_OK) err=UNZ_ERRNO;
+ // total number of entries in the central dir on this disk
+ if(unzlocal_getShort(fin,&us.gi.number_entry)!=UNZ_OK) err=UNZ_ERRNO;
+ // total number of entries in the central dir
+ if(unzlocal_getShort(fin,&number_entry_CD)!=UNZ_OK) err=UNZ_ERRNO;
+ if(number_entry_CD!=us.gi.number_entry || number_disk_with_CD!=0 || number_disk!=0) err=UNZ_BADZIPFILE;
+ // size of the central directory
+ if(unzlocal_getLong(fin,&us.size_central_dir)!=UNZ_OK) err=UNZ_ERRNO;
+ // offset of start of central directory with respect to the starting disk number
+ if(unzlocal_getLong(fin,&us.offset_central_dir)!=UNZ_OK) err=UNZ_ERRNO;
+ // zipfile comment length
+ if(unzlocal_getShort(fin,&us.gi.size_comment)!=UNZ_OK) err=UNZ_ERRNO;
+ if((central_pos+fin->initial_offset<us.offset_central_dir+us.size_central_dir) && err==UNZ_OK) err=UNZ_BADZIPFILE;
+ if(err!=UNZ_OK) { lufclose(fin); return NULL; }
+
+ us.file=fin;
+ us.byte_before_the_zipfile=central_pos+fin->initial_offset-(us.offset_central_dir+us.size_central_dir);
+ us.central_pos=central_pos;
+ us.pfile_in_zip_read=NULL;
+ fin->initial_offset=0; // since the zipfile itself is expected to handle this
+
+ s=(unz_s*)mir_alloc(sizeof(unz_s));
+ if(s==NULL) { lufclose(fin); return NULL; }
+ *s=us;
+ unzGoToFirstFile((unzFile)s);
+ return (unzFile)s;
+}
+
+// Close a ZipFile opened with unzipOpen.
+// If there is files inside the .Zip opened with unzipOpenCurrentFile (see later),
+// these files MUST be closed with unzipCloseCurrentFile before call unzipClose.
+// return UNZ_OK if there is no problem.
+static int unzClose(unzFile file)
+{
+ unz_s *s;
+ if(file==NULL) return UNZ_PARAMERROR;
+ s=(unz_s*)file;
+ if(s->pfile_in_zip_read!=NULL)
+ unzCloseCurrentFile(file);
+ lufclose(s->file);
+ mir_free(s); // does NULL check, unused s=0;
+ return UNZ_OK;
+}
+
+// Translate date/time from Dos format to tm_unz (readable more easily)
+static void unzlocal_DosDateToTmuDate (ULONG ulDosDate,tm_unz* ptm)
+{
+ ULONG uDate;
+ uDate=(ULONG)(ulDosDate>>16);
+ ptm->tm_mday=(UINT)(uDate&0x1f) ;
+ ptm->tm_mon=(UINT)((((uDate)&0x1E0)/0x20)-1) ;
+ ptm->tm_year=(UINT)(((uDate&0x0FE00)/0x0200)+1980) ;
+ ptm->tm_hour=(UINT)((ulDosDate &0xF800)/0x800);
+ ptm->tm_min=(UINT)((ulDosDate&0x7E0)/0x20) ;
+ ptm->tm_sec=(UINT)(2*(ulDosDate&0x1f)) ;
+}
+
+// Get Info about the current file in the zipfile, with internal only info
+static int unzlocal_GetCurrentFileInfoInternal(unzFile file, unz_file_info *pfile_info,
+ unz_file_info_internal *pfile_info_internal, char *szFileName,
+ ULONG fileNameBufferSize, void *extraField, ULONG extraFieldBufferSize,
+ char *szComment, ULONG commentBufferSize)
+{
+ unz_s *s;
+ unz_file_info file_info;
+ unz_file_info_internal file_info_internal;
+ int err=UNZ_OK;
+ ULONG uMagic;
+ long lSeek=0;
+
+ if(file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz_s*)file;
+ if(lufseek(s->file,s->pos_in_central_dir+s->byte_before_the_zipfile,SEEK_SET)!=0)
+ err=UNZ_ERRNO;
+ // we check the magic
+ if(err==UNZ_OK)
+ if(unzlocal_getLong(s->file,&uMagic)!=UNZ_OK)
+ err=UNZ_ERRNO;
+ else if(uMagic!=0x02014b50)
+ err=UNZ_BADZIPFILE;
+ if(unzlocal_getShort(s->file,&file_info.version) != UNZ_OK)
+ err=UNZ_ERRNO;
+ if(unzlocal_getShort(s->file,&file_info.version_needed) != UNZ_OK)
+ err=UNZ_ERRNO;
+ if(unzlocal_getShort(s->file,&file_info.flag) != UNZ_OK)
+ err=UNZ_ERRNO;
+ if(unzlocal_getShort(s->file,&file_info.compression_method) != UNZ_OK)
+ err=UNZ_ERRNO;
+ if(unzlocal_getLong(s->file,&file_info.dosDate) != UNZ_OK)
+ err=UNZ_ERRNO;
+ unzlocal_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date);
+ if(unzlocal_getLong(s->file,&file_info.crc)!=UNZ_OK)
+ err=UNZ_ERRNO;
+ if(unzlocal_getLong(s->file,&file_info.compressed_size)!=UNZ_OK)
+ err=UNZ_ERRNO;
+ if(unzlocal_getLong(s->file,&file_info.uncompressed_size)!=UNZ_OK)
+ err=UNZ_ERRNO;
+ if(unzlocal_getShort(s->file,&file_info.size_filename)!=UNZ_OK)
+ err=UNZ_ERRNO;
+ if(unzlocal_getShort(s->file,&file_info.size_file_extra)!=UNZ_OK)
+ err=UNZ_ERRNO;
+ if(unzlocal_getShort(s->file,&file_info.size_file_comment)!=UNZ_OK)
+ err=UNZ_ERRNO;
+ if(unzlocal_getShort(s->file,&file_info.disk_num_start)!=UNZ_OK)
+ err=UNZ_ERRNO;
+ if(unzlocal_getShort(s->file,&file_info.internal_fa)!=UNZ_OK)
+ err=UNZ_ERRNO;
+ if(unzlocal_getLong(s->file,&file_info.external_fa)!=UNZ_OK)
+ err=UNZ_ERRNO;
+ if(unzlocal_getLong(s->file,&file_info_internal.offset_curfile)!=UNZ_OK)
+ err=UNZ_ERRNO;
+
+ lSeek+=file_info.size_filename;
+ if((err==UNZ_OK) && (szFileName!=NULL)) {
+ ULONG uSizeRead ;
+ if (file_info.size_filename<fileNameBufferSize) {
+ *(szFileName+file_info.size_filename)='\0';
+ uSizeRead=file_info.size_filename;
+ }
+ else uSizeRead=fileNameBufferSize;
+
+ if((file_info.size_filename>0) && (fileNameBufferSize>0))
+ if(lufread(szFileName,(UINT)uSizeRead,1,s->file)!=1)
+ err=UNZ_ERRNO;
+ lSeek-=uSizeRead;
+ }
+
+ if((err==UNZ_OK) && (extraField!=NULL)) {
+ ULONG uSizeRead ;
+ if (file_info.size_file_extra<extraFieldBufferSize)
+ uSizeRead=file_info.size_file_extra;
+ else
+ uSizeRead=extraFieldBufferSize;
+ if(lSeek!=0)
+ if(lufseek(s->file,lSeek,SEEK_CUR)==0)
+ lSeek=0;
+ else
+ err=UNZ_ERRNO;
+ if((file_info.size_file_extra>0) && (extraFieldBufferSize>0))
+ if(lufread(extraField,(UINT)uSizeRead,1,s->file)!=1)
+ err=UNZ_ERRNO;
+ lSeek+=file_info.size_file_extra - uSizeRead;
+ }
+ else lSeek+=file_info.size_file_extra;
+
+ if((err==UNZ_OK) && (szComment!=NULL)) {
+ ULONG uSizeRead ;
+ if(file_info.size_file_comment<commentBufferSize) {
+ *(szComment+file_info.size_file_comment)='\0';
+ uSizeRead = file_info.size_file_comment;
+ }
+ else uSizeRead = commentBufferSize;
+
+ if(lSeek!=0)
+ if(lufseek(s->file,lSeek,SEEK_CUR)!=0)
+ err=UNZ_ERRNO;
+ if((file_info.size_file_comment>0) && (commentBufferSize>0))
+ if(lufread(szComment,(UINT)uSizeRead,1,s->file)!=1)
+ err=UNZ_ERRNO;
+ }
+ if((err==UNZ_OK) && (pfile_info!=NULL))
+ *pfile_info=file_info;
+ if((err==UNZ_OK) && (pfile_info_internal!=NULL))
+ *pfile_info_internal=file_info_internal;
+ return err;
+}
+
+// Write info about the ZipFile in the *pglobal_info structure.
+// No preparation of the structure is needed
+// return UNZ_OK if there is no problem.
+#define unzGetCurrentFileInfo(file,pfile_info,szFileName,fileNameBufferSize,extraField,extraFieldBufferSize,szComment,commentBufferSize) \
+ unzlocal_GetCurrentFileInfoInternal(file,pfile_info,NULL,szFileName,fileNameBufferSize,extraField,extraFieldBufferSize,szComment,commentBufferSize)
+
+// Set the current file of the zipfile to the first file.
+// return UNZ_OK if there is no problem
+static int unzGoToFirstFile(unzFile file)
+{
+ int err;
+ unz_s *s;
+ if(file==NULL) return UNZ_PARAMERROR;
+ s=(unz_s*)file;
+ s->pos_in_central_dir=s->offset_central_dir;
+ s->num_file=0;
+ err=unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info,&s->cur_file_info_internal,
+ NULL,0,NULL,0,NULL,0);
+ s->current_file_ok=(err==UNZ_OK);
+ return err;
+}
+
+// Set the current file of the zipfile to the next file.
+// return UNZ_OK if there is no problem
+// return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest.
+static int unzGoToNextFile(unzFile file)
+{
+ unz_s* s;
+ int err;
+
+ if(file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz_s*)file;
+ if(!s->current_file_ok)
+ return UNZ_END_OF_LIST_OF_FILE;
+ if(s->num_file+1==s->gi.number_entry)
+ return UNZ_END_OF_LIST_OF_FILE;
+
+ s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename +
+ s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ;
+ s->num_file++;
+ err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info,&s->cur_file_info_internal,
+ NULL,0,NULL,0,NULL,0);
+ s->current_file_ok=(err==UNZ_OK);
+ return err;
+}
+
+// Try locate the file szWildFileName in the zipfile, wildcards allowed.
+// For the iCaseSensitivity signification, see unzStringFileNameMatch
+// return value:
+// UNZ_OK if the file is found. It becomes the current file.
+// UNZ_END_OF_LIST_OF_FILE if the file is not found
+static int unzLocateFile(unzFile file,int startIndex,const char *szWildFileName,int iCaseSensitivity)
+{
+ unz_s *s;
+ int err;
+ ULONG num_fileSaved;
+ ULONG pos_in_central_dirSaved;
+ char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1];
+
+ if(file==NULL)
+ return UNZ_PARAMERROR;
+ if(strlen(szWildFileName)>=UNZ_MAXFILENAMEINZIP)
+ return UNZ_PARAMERROR;
+ s=(unz_s*)file;
+ if(!s->current_file_ok)
+ return UNZ_END_OF_LIST_OF_FILE;
+ num_fileSaved=s->num_file;
+ pos_in_central_dirSaved=s->pos_in_central_dir;
+ err=unzGoToFirstFile(file);
+ while(err==UNZ_OK) {
+ unzGetCurrentFileInfo(file,NULL,szCurrentFileName,sizeof(szCurrentFileName)-1,NULL,0,NULL,0);
+ if((int)file->num_file>=startIndex)
+ if(unzStringFileNameMatch(szCurrentFileName,szWildFileName,iCaseSensitivity))
+ return UNZ_OK;
+ err=unzGoToNextFile(file);
+ }
+ s->num_file=num_fileSaved ;
+ s->pos_in_central_dir=pos_in_central_dirSaved ;
+ return err;
+}
+
+// Read the local header of the current zipfile
+// Check the coherency of the local header and info in the end of central
+// directory about this file
+// store in *piSizeVar the size of extra info in local header
+// (filename and size of extra field data)
+static int unzlocal_CheckCurrentFileCoherencyHeader(unz_s *s,UINT *piSizeVar,
+ ULONG *poffset_local_extrafield, UINT *psize_local_extrafield)
+{
+ ULONG uMagic,uData,uFlags;
+ ULONG size_filename;
+ ULONG size_extra_field;
+ int err=UNZ_OK;
+ *piSizeVar=0;
+ *poffset_local_extrafield=0;
+ *psize_local_extrafield=0;
+
+ if(lufseek(s->file,s->cur_file_info_internal.offset_curfile + s->byte_before_the_zipfile,SEEK_SET)!=0)
+ return UNZ_ERRNO;
+ if(err==UNZ_OK) {
+ if(unzlocal_getLong(s->file,&uMagic)!=UNZ_OK)
+ err=UNZ_ERRNO;
+ else if(uMagic!=0x04034b50)
+ err=UNZ_BADZIPFILE;
+ }
+ if(unzlocal_getShort(s->file,&uData)!=UNZ_OK)
+ err=UNZ_ERRNO;
+ //else if((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion))
+ // err=UNZ_BADZIPFILE;
+ if(unzlocal_getShort(s->file,&uFlags)!=UNZ_OK)
+ err=UNZ_ERRNO;
+ if(unzlocal_getShort(s->file,&uData)!=UNZ_OK)
+ err=UNZ_ERRNO;
+ else if((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method))
+ err=UNZ_BADZIPFILE;
+ if((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) && (s->cur_file_info.compression_method!=Z_DEFLATED))
+ err=UNZ_BADZIPFILE;
+ if(unzlocal_getLong(s->file,&uData) != UNZ_OK) // date/time
+ err=UNZ_ERRNO;
+ if(unzlocal_getLong(s->file,&uData) != UNZ_OK) // crc
+ err=UNZ_ERRNO;
+ else if((err==UNZ_OK) && (uData!=s->cur_file_info.crc) && ((uFlags & 8)==0))
+ err=UNZ_BADZIPFILE;
+ if(unzlocal_getLong(s->file,&uData)!=UNZ_OK) // size compr
+ err=UNZ_ERRNO;
+ else if((err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) && ((uFlags&8)==0))
+ err=UNZ_BADZIPFILE;
+ if(unzlocal_getLong(s->file,&uData) != UNZ_OK) // size uncompr
+ err=UNZ_ERRNO;
+ else if((err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && ((uFlags&8)==0))
+ err=UNZ_BADZIPFILE;
+ if(unzlocal_getShort(s->file,&size_filename)!=UNZ_OK)
+ err=UNZ_ERRNO;
+ else if((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename))
+ err=UNZ_BADZIPFILE;
+ *piSizeVar+=(UINT)size_filename;
+ if(unzlocal_getShort(s->file,&size_extra_field)!=UNZ_OK)
+ err=UNZ_ERRNO;
+ *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile+SIZEZIPLOCALHEADER + size_filename;
+ *psize_local_extrafield=(UINT)size_extra_field;
+ *piSizeVar+=(UINT)size_extra_field;
+ return err;
+}
+
+// Open for reading data the current file in the zipfile.
+// If there is no error and the file is opened, the return value is UNZ_OK.
+static int unzOpenCurrentFile(unzFile file,const char *password)
+{
+ int err;
+ int Store;
+ UINT iSizeVar;
+ unz_s* s;
+ file_in_zip_read_info_s *pfile_in_zip_read_info;
+ ULONG offset_local_extrafield; // offset of the local extra field
+ UINT size_local_extrafield; // size of the local extra field
+ BOOL extlochead;
+ const char *cp;
+
+ if(file==NULL) return UNZ_PARAMERROR;
+ s=(unz_s*)file;
+ if(!s->current_file_ok) return UNZ_PARAMERROR;
+ if(s->pfile_in_zip_read != NULL) unzCloseCurrentFile(file);
+ if(unzlocal_CheckCurrentFileCoherencyHeader(s,&iSizeVar,&offset_local_extrafield,&size_local_extrafield)!=UNZ_OK)
+ return UNZ_BADZIPFILE;
+ pfile_in_zip_read_info=(file_in_zip_read_info_s*)mir_alloc(sizeof(file_in_zip_read_info_s));
+ if(pfile_in_zip_read_info==NULL)
+ return UNZ_INTERNALERROR;
+ pfile_in_zip_read_info->read_buffer=(char*)mir_alloc(UNZ_BUFSIZE);
+ if(pfile_in_zip_read_info->read_buffer==NULL) {
+ mir_free(pfile_in_zip_read_info->read_buffer);
+ return UNZ_INTERNALERROR;
+ }
+ pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield;
+ pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield;
+ pfile_in_zip_read_info->pos_local_extrafield=0;
+ if(pfile_in_zip_read_info->read_buffer==NULL) {
+ mir_free(pfile_in_zip_read_info); // does NULL check, unused pfile_in_zip_read_info=0;
+ return UNZ_INTERNALERROR;
+ }
+ pfile_in_zip_read_info->stream_initialised=0;
+ //if(s->cur_file_info.compression_method!=0 && s->cur_file_info.compression_method!=Z_DEFLATED)
+ // err=UNZ_BADZIPFILE;
+ Store=s->cur_file_info.compression_method==0;
+ pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc;
+ pfile_in_zip_read_info->crc32=0;
+ pfile_in_zip_read_info->compression_method = s->cur_file_info.compression_method;
+ pfile_in_zip_read_info->file=s->file;
+ pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile;
+ pfile_in_zip_read_info->stream.total_out=0;
+ if(!Store) {
+ err=inflateInit2(&pfile_in_zip_read_info->stream);
+ if(err==Z_OK) pfile_in_zip_read_info->stream_initialised=1;
+ // windowBits is passed < 0 to tell that there is no zlib header.
+ // Note that in this case inflate *requires* an extra "dummy" byte
+ // after the compressed stream in order to complete decompression and
+ // return Z_STREAM_END.
+ // In unzip, I don't wait absolutely Z_STREAM_END because I known the
+ // size of both compressed and uncompressed data
+ }
+ pfile_in_zip_read_info->rest_read_compressed = s->cur_file_info.compressed_size ;
+ pfile_in_zip_read_info->rest_read_uncompressed = s->cur_file_info.uncompressed_size ;
+ pfile_in_zip_read_info->encrypted = (s->cur_file_info.flag&1)!=0;
+ extlochead=(s->cur_file_info.flag&8)!=0;
+ if(extlochead) pfile_in_zip_read_info->crcenctest=(char)((s->cur_file_info.dosDate>>8)&0xff);
+ else pfile_in_zip_read_info->crcenctest=(char)(s->cur_file_info.crc>>24);
+ pfile_in_zip_read_info->encheadleft=(pfile_in_zip_read_info->encrypted?12:0);
+ pfile_in_zip_read_info->keys[0]=305419896L;
+ pfile_in_zip_read_info->keys[1]=591751049L;
+ pfile_in_zip_read_info->keys[2]=878082192L;
+ for(cp=password; cp!=0 && *cp!=0; cp++)
+ Uupdate_keys(pfile_in_zip_read_info->keys,*cp);
+ pfile_in_zip_read_info->pos_in_zipfile=s->cur_file_info_internal.offset_curfile+SIZEZIPLOCALHEADER +iSizeVar;
+ pfile_in_zip_read_info->stream.avail_in=(UINT)0;
+ s->pfile_in_zip_read=pfile_in_zip_read_info;
+ return UNZ_OK;
+}
+
+// Read bytes from the current file.
+// buf contain buffer where data must be copied
+// len the size of buf.
+// return the number of byte copied if somes bytes are copied (and also sets *reached_eof)
+// return 0 if the end of file was reached. (and also sets *reached_eof).
+// return <0 with error code if there is an error. (in which case *reached_eof is meaningless)
+// (UNZ_ERRNO for IO error, or zLib error for uncompress error)
+static int unzReadCurrentFile(unzFile file, void *buf, unsigned len, BOOL *reached_eof)
+{
+ int err=UNZ_OK;
+ UINT iRead=0;
+ unz_s *s;
+ file_in_zip_read_info_s* pfile_in_zip_read_info;
+ unsigned int uDoEncHead;
+
+ if(reached_eof!=0) *reached_eof=FALSE;
+ s=(unz_s*)file;
+ if(s==NULL) return UNZ_PARAMERROR;
+
+ pfile_in_zip_read_info=s->pfile_in_zip_read;
+ if(pfile_in_zip_read_info==NULL) return UNZ_PARAMERROR;
+ if((pfile_in_zip_read_info->read_buffer == NULL)) return UNZ_END_OF_LIST_OF_FILE;
+ if(len==0) return 0;
+
+ pfile_in_zip_read_info->stream.next_out = (BYTE*)buf;
+ pfile_in_zip_read_info->stream.avail_out = (UINT)len;
+
+ if(len>pfile_in_zip_read_info->rest_read_uncompressed)
+ pfile_in_zip_read_info->stream.avail_out=(UINT)pfile_in_zip_read_info->rest_read_uncompressed;
+
+ while (pfile_in_zip_read_info->stream.avail_out>0) {
+ if((pfile_in_zip_read_info->stream.avail_in==0) && (pfile_in_zip_read_info->rest_read_compressed>0)) {
+ UINT uReadThis=UNZ_BUFSIZE;
+ unsigned int i;
+ char *buf;
+
+ if(pfile_in_zip_read_info->rest_read_compressed<uReadThis) uReadThis=(UINT)pfile_in_zip_read_info->rest_read_compressed;
+ if(uReadThis==0) { if(reached_eof!=0) *reached_eof=TRUE; return UNZ_EOF;}
+ if(lufseek(pfile_in_zip_read_info->file,pfile_in_zip_read_info->pos_in_zipfile+pfile_in_zip_read_info->byte_before_the_zipfile,SEEK_SET)!=0) return UNZ_ERRNO;
+ if(lufread(pfile_in_zip_read_info->read_buffer,uReadThis,1,pfile_in_zip_read_info->file)!=1) return UNZ_ERRNO;
+ pfile_in_zip_read_info->pos_in_zipfile += uReadThis;
+ pfile_in_zip_read_info->rest_read_compressed-=uReadThis;
+ pfile_in_zip_read_info->stream.next_in = (BYTE*)pfile_in_zip_read_info->read_buffer;
+ pfile_in_zip_read_info->stream.avail_in = (UINT)uReadThis;
+
+ if(pfile_in_zip_read_info->encrypted) {
+ buf=(char*)pfile_in_zip_read_info->stream.next_in;
+ for(i=0;i<uReadThis;i++)
+ buf[i]=zdecode(pfile_in_zip_read_info->keys,buf[i]);
+ }
+ }
+ uDoEncHead=pfile_in_zip_read_info->encheadleft;
+ if(uDoEncHead>pfile_in_zip_read_info->stream.avail_in)
+ uDoEncHead=pfile_in_zip_read_info->stream.avail_in;
+ if(uDoEncHead>0) {
+ char bufcrc=pfile_in_zip_read_info->stream.next_in[uDoEncHead-1];
+ pfile_in_zip_read_info->rest_read_uncompressed-=uDoEncHead;
+ pfile_in_zip_read_info->stream.avail_in -= uDoEncHead;
+ pfile_in_zip_read_info->stream.next_in += uDoEncHead;
+ pfile_in_zip_read_info->encheadleft -= uDoEncHead;
+ if(pfile_in_zip_read_info->encheadleft==0)
+ if(bufcrc!=pfile_in_zip_read_info->crcenctest) return UNZ_PASSWORD;
+ }
+
+ if(pfile_in_zip_read_info->compression_method==0) {
+ UINT uDoCopy,i ;
+ if(pfile_in_zip_read_info->stream.avail_out < pfile_in_zip_read_info->stream.avail_in)
+ uDoCopy=pfile_in_zip_read_info->stream.avail_out ;
+ else
+ uDoCopy=pfile_in_zip_read_info->stream.avail_in ;
+ for(i=0;i<uDoCopy;i++)
+ *(pfile_in_zip_read_info->stream.next_out+i)=*(pfile_in_zip_read_info->stream.next_in+i);
+ pfile_in_zip_read_info->crc32=ucrc32(pfile_in_zip_read_info->crc32,pfile_in_zip_read_info->stream.next_out,uDoCopy);
+ pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy;
+ pfile_in_zip_read_info->stream.avail_in-=uDoCopy;
+ pfile_in_zip_read_info->stream.avail_out-=uDoCopy;
+ pfile_in_zip_read_info->stream.next_out+=uDoCopy;
+ pfile_in_zip_read_info->stream.next_in+=uDoCopy;
+ pfile_in_zip_read_info->stream.total_out+=uDoCopy;
+ iRead+=uDoCopy;
+ if(pfile_in_zip_read_info->rest_read_uncompressed==0)
+ if(reached_eof!=0) *reached_eof=TRUE;
+ }
+ else {
+ ULONG uTotalOutBefore,uTotalOutAfter;
+ const BYTE *bufBefore;
+ ULONG uOutThis;
+ int flush=Z_SYNC_FLUSH;
+ uTotalOutBefore = pfile_in_zip_read_info->stream.total_out;
+ bufBefore = pfile_in_zip_read_info->stream.next_out;
+ err=inflate(&pfile_in_zip_read_info->stream,flush);
+
+ uTotalOutAfter=pfile_in_zip_read_info->stream.total_out;
+ uOutThis=uTotalOutAfter-uTotalOutBefore;
+ pfile_in_zip_read_info->crc32=ucrc32(pfile_in_zip_read_info->crc32,bufBefore,(UINT)(uOutThis));
+ pfile_in_zip_read_info->rest_read_uncompressed-=uOutThis;
+ iRead+=(UINT)(uTotalOutAfter-uTotalOutBefore);
+ if(err==Z_STREAM_END || pfile_in_zip_read_info->rest_read_uncompressed==0) {
+ if(reached_eof!=0) *reached_eof=TRUE;
+ return iRead;
+ }
+ if(err!=Z_OK) break;
+ }
+ }
+ if(err==Z_OK) return iRead;
+ return err;
+}
+
+// Close the file in zip opened with unzipOpenCurrentFile
+// Return UNZ_CRCERROR if all the file was read but the CRC is not good
+static int unzCloseCurrentFile(unzFile file)
+{
+ int err=UNZ_OK;
+ unz_s* s;
+ file_in_zip_read_info_s* pfile_in_zip_read_info;
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz_s*)file;
+ pfile_in_zip_read_info=s->pfile_in_zip_read;
+
+ if(pfile_in_zip_read_info==NULL)
+ return UNZ_PARAMERROR;
+ if(pfile_in_zip_read_info->rest_read_uncompressed == 0)
+ if(pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait)
+ err=UNZ_CRCERROR;
+ if(pfile_in_zip_read_info->read_buffer!=0) {
+ void *buf=pfile_in_zip_read_info->read_buffer;
+ mir_free(buf);
+ pfile_in_zip_read_info->read_buffer=0;
+ }
+ pfile_in_zip_read_info->read_buffer=NULL;
+ if(pfile_in_zip_read_info->stream_initialised)
+ inflateEnd(&pfile_in_zip_read_info->stream);
+
+ pfile_in_zip_read_info->stream_initialised=0;
+ if(pfile_in_zip_read_info!=0) mir_free(pfile_in_zip_read_info); // unused pfile_in_zip_read_info=0;
+ s->pfile_in_zip_read=NULL;
+ return err;
+}
+
+typedef unsigned __int32 lutime_t; // define it ourselves since we don't include time.h
+
+static FILETIME timet2filetime(const lutime_t t)
+{
+ LONGLONG i=Int32x32To64(t,10000000)+116444736000000000;
+ FILETIME ft;
+ ft.dwLowDateTime=(DWORD)i;
+ ft.dwHighDateTime=(DWORD)(i>>32);
+ return ft;
+}
+
+static FILETIME dosdatetime2filetime(WORD dosdate,WORD dostime)
+{
+ // date: bits 0-4 are day of month 1-31. Bits 5-8 are month 1..12. Bits 9-15 are year-1980
+ // time: bits 0-4 are seconds/2, bits 5-10 are minute 0..59. Bits 11-15 are hour 0..23
+ SYSTEMTIME st;
+ FILETIME ft;
+ st.wYear=(WORD)(((dosdate>>9)&0x7f)+1980);
+ st.wMonth=(WORD)((dosdate>>5)&0xf);
+ st.wDay=(WORD)(dosdate&0x1f);
+ st.wHour=(WORD)((dostime>>11)&0x1f);
+ st.wMinute=(WORD)((dostime>>5)&0x3f);
+ st.wSecond=(WORD)((dostime&0x1f)*2);
+ st.wMilliseconds=0;
+ SystemTimeToFileTime(&st,&ft);
+ return ft;
+}
+
+typedef struct {
+ unzFile uf; int currentfile; ZIPENTRY cze; int czei;
+ char *password;
+ char *unzbuf; // lazily created and destroyed, used by Unzip
+ TCHAR rootdir[MAX_PATH]; // includes a trailing slash
+} UnzipData;
+
+static UnzipData *UnzipData_Create(const char *pwd)
+{
+ UnzipData *unz;
+ unz=(UnzipData*)mir_alloc(sizeof(UnzipData));
+ if(unz==NULL) return NULL;
+ unz->uf=0;
+ unz->unzbuf=NULL;
+ unz->currentfile=-1;
+ unz->czei=-1;
+ unz->password=mir_strdup(pwd); // does NULL check
+ return unz;
+}
+
+static void UnzipData_Destroy(UnzipData *unz)
+{
+ mir_free(unz->password); // does NULL check
+ mir_free(unz->unzbuf); // does NULL check
+ mir_free(unz);
+}
+
+static ZRESULT UnzipData_Open(UnzipData *unz,void *z,unsigned int len,DWORD flags)
+{
+ TCHAR lastchar;
+ ZRESULT e;
+ LUFILE *f;
+
+ if(unz->uf!=0 || unz->currentfile!=-1) return ZR_NOTINITED;
+#ifdef GetCurrentDirectory
+ GetCurrentDirectory(MAX_PATH,unz->rootdir);
+#else
+ lstrcpy(unz->rootdir,_T("\\"));
+#endif
+ lastchar=unz->rootdir[_tcslen(unz->rootdir)-1];
+ if(lastchar!='\\' && lastchar!='/') lstrcat(unz->rootdir,_T("\\"));
+ if(flags==ZIP_HANDLE)
+ // test if we can seek on it. We can't use GetFileType(h)==FILE_TYPE_DISK since it's not on CE.
+ if(SetFilePointer(z,0,0,FILE_CURRENT)==0xFFFFFFFF) return ZR_SEEK;
+ f=lufopen(z,len,flags,&e);
+ if(f==NULL) return e;
+ unz->uf=unzOpenInternal(f);
+ if(unz->uf==0) return ZR_NOFILE;
+ return ZR_OK;
+}
+
+static ZRESULT UnzipData_SetUnzipBaseDir(UnzipData *unz,const TCHAR *dir)
+{
+ TCHAR lastchar;
+ lstrcpy(unz->rootdir,dir);
+ lastchar=unz->rootdir[_tcslen(unz->rootdir)-1];
+ if(lastchar!='\\' && lastchar!='/') lstrcat(unz->rootdir,_T("\\"));
+ return ZR_OK;
+}
+
+static ZRESULT UnzipData_Get(UnzipData *unz,int index,ZIPENTRY *ze)
+{
+ unsigned int extralen,iSizeVar;
+ unsigned long offset;
+ int res;
+ unsigned char *extra;
+ TCHAR tfn[MAX_PATH];
+ const TCHAR *c,*sfn=tfn;
+ unz_file_info ufi; char fn[MAX_PATH];
+
+ if(index<-1 || index>=(int)unz->uf->gi.number_entry) return ZR_ARGS;
+ if(unz->currentfile!=-1) unzCloseCurrentFile(unz->uf);
+ unz->currentfile=-1;
+ if(index==unz->czei && index!=-1) {
+ CopyMemory(ze,&unz->cze,sizeof(ZIPENTRY));
+ return ZR_OK;
+ }
+ if(index==-1) {
+ ze->index=unz->uf->gi.number_entry;
+ ze->name[0]=0;
+ ze->attr=0;
+ ze->atime.dwLowDateTime=0; ze->atime.dwHighDateTime=0;
+ ze->ctime.dwLowDateTime=0; ze->ctime.dwHighDateTime=0;
+ ze->mtime.dwLowDateTime=0; ze->mtime.dwHighDateTime=0;
+ ze->comp_size=0;
+ ze->unc_size=0;
+ return ZR_OK;
+ }
+ if(index<(int)unz->uf->num_file) unzGoToFirstFile(unz->uf);
+ while((int)unz->uf->num_file<index) unzGoToNextFile(unz->uf);
+ unzGetCurrentFileInfo(unz->uf,&ufi,fn,MAX_PATH,NULL,0,NULL,0);
+
+ // now get the extra header. We do this ourselves, instead of
+ // calling unzOpenCurrentFile &c., to avoid allocating more than necessary.
+ res=unzlocal_CheckCurrentFileCoherencyHeader(unz->uf,&iSizeVar,&offset,&extralen);
+ if(res!=UNZ_OK) return ZR_CORRUPT;
+ if(lufseek(unz->uf->file,offset,SEEK_SET)!=0) return ZR_READ;
+ extra=(unsigned char*)mir_alloc(extralen);
+ if(lufread(extra,1,(UINT)extralen,unz->uf->file)!=extralen) { mir_free(extra); return ZR_READ;}
+ ze->index=unz->uf->num_file;
+#ifdef _UNICODE
+ MultiByteToWideChar(CP_UTF8,0,fn,-1,tfn,MAX_PATH);
+#else
+ lstrcpyA(tfn,fn);
+#endif
+
+ // As a safety feature: if the zip filename had sneaky stuff
+ // like "c:\windows\file.txt" or "\windows\file.txt" or "fred\..\..\..\windows\file.txt"
+ // then we get rid of them all. That way, when the programmer does UnzipItem(hz,i,ze.name),
+ // it won't be a problem. (If the programmer really did want to get the full evil information,
+ // then they can edit out this security feature from here).
+ // In particular, we chop off any prefixes that are "c:\" or "\" or "/" or "[stuff]\.." or "[stuff]/.."
+ for(;;) {
+ if(sfn[0]!=0 && sfn[1]==':') { sfn+=2; continue; }
+ if(sfn[0]=='\\') { sfn++; continue; }
+ if(sfn[0]=='/') { sfn++; continue; }
+ c=_tcsstr(sfn,_T("\\..\\")); if(c!=0) { sfn=c+4; continue; }
+ c=_tcsstr(sfn,_T("\\../")); if(c!=0) { sfn=c+4; continue; }
+ c=_tcsstr(sfn,_T("/../")); if(c!=0) { sfn=c+4; continue; }
+ c=_tcsstr(sfn,_T("/..\\")); if(c!=0) { sfn=c+4; continue; }
+ break;
+ }
+ lstrcpy(ze->name,sfn);
+
+ // zip has an 'attribute' 32bit value. Its lower half is windows stuff
+ // its upper half is standard unix stat.st_mode. We'll start trying
+ // to read it in unix mode
+ { unsigned long a=ufi.external_fa;
+ BOOL isdir=(a&0x40000000)!=0,readonly=(a&0x00800000)==0;
+ BOOL hidden=FALSE,system=FALSE,archive=TRUE;
+ int host;
+ // but in normal hostmodes these are overridden by the lower half...
+ host=ufi.version>>8;
+ if(host==0 || host==7 || host==11 || host==14) {
+ readonly=(a&0x00000001)!=0;
+ hidden=(a&0x00000002)!=0;
+ system=(a&0x00000004)!=0;
+ isdir=(a&0x00000010)!=0;
+ archive=(a&0x00000020)!=0;
+ }
+ ze->attr=0;
+ if(isdir) ze->attr|=FILE_ATTRIBUTE_DIRECTORY;
+ if(archive) ze->attr|=FILE_ATTRIBUTE_ARCHIVE;
+ if(hidden) ze->attr|=FILE_ATTRIBUTE_HIDDEN;
+ if(readonly) ze->attr|=FILE_ATTRIBUTE_READONLY;
+ if(system) ze->attr|=FILE_ATTRIBUTE_SYSTEM;
+ ze->comp_size=ufi.compressed_size;
+ ze->unc_size=ufi.uncompressed_size;
+ }
+ { WORD dostime,dosdate;
+ FILETIME ftd,ft;
+ unsigned int epos=0;
+ char etype[3];
+ int size,flags;
+ BOOL hasmtime,hasatime,hasctime;
+
+ dostime=(WORD)(ufi.dosDate&0xFFFF);
+ dosdate=(WORD)((ufi.dosDate>>16)&0xFFFF);
+ ftd=dosdatetime2filetime(dosdate,dostime);
+ LocalFileTimeToFileTime(&ftd,&ft);
+ ze->atime=ft; ze->ctime=ft; ze->mtime=ft;
+
+ // the zip will always have at least that dostime. But if it also has
+ // an extra header, then we'll instead get the info from that.
+ while(epos+4<extralen) {
+ etype[0]=extra[epos+0]; etype[1]=extra[epos+1]; etype[2]=0;
+ size=extra[epos+2];
+ if(strcmp(etype,"UT")!=0) { epos+=4+size; continue; }
+ flags=extra[epos+4];
+ hasmtime=(flags&1)!=0;
+ hasatime=(flags&2)!=0;
+ hasctime=(flags&4)!=0;
+ epos+=5;
+ if(hasmtime) {
+ lutime_t mtime=((extra[epos+0])<<0) | ((extra[epos+1])<<8) |((extra[epos+2])<<16) | ((extra[epos+3])<<24);
+ epos+=4;
+ ze->mtime=timet2filetime(mtime);
+ }
+ if(hasatime) {
+ lutime_t atime=((extra[epos+0])<<0) | ((extra[epos+1])<<8) |((extra[epos+2])<<16) | ((extra[epos+3])<<24);
+ epos+=4;
+ ze->atime=timet2filetime(atime);
+ }
+ if(hasctime) {
+ lutime_t ctime=((extra[epos+0])<<0) | ((extra[epos+1])<<8) |((extra[epos+2])<<16) | ((extra[epos+3])<<24);
+ epos+=4;
+ ze->ctime=timet2filetime(ctime);
+ }
+ break;
+ }
+ }
+
+ if(extra!=0) mir_free(extra);
+ CopyMemory(&unz->cze,ze,sizeof(ZIPENTRY));
+ unz->czei=index;
+ return ZR_OK;
+}
+
+// tname is allowed to contain wildcards
+static ZRESULT UnzipData_Find(UnzipData *unz,const TCHAR *tname,BOOL ic,int *index,ZIPENTRY *ze)
+{
+ char name[MAX_PATH];
+ int res,i;
+ ZRESULT zres;
+ if(index!=NULL && *index==-1) return ZR_NOTFOUND;
+#ifdef _UNICODE
+ WideCharToMultiByte(CP_UTF8,0,tname,-1,name,MAX_PATH,0,0);
+#else
+ lstrcpyA(name,tname);
+#endif
+ res=unzLocateFile(unz->uf,(index!=NULL)?*index:0,name,ic?CASE_INSENSITIVE:CASE_SENSITIVE);
+ if(res!=UNZ_OK) {
+ if(index!=NULL) *index=-1;
+ if(ze!=NULL) { ZeroMemory(ze,sizeof(ZIPENTRY)); ze->index=-1; }
+ return ZR_NOTFOUND;
+ }
+ if(unz->currentfile!=-1) unzCloseCurrentFile(unz->uf);
+ unz->currentfile=-1;
+ i=(int)unz->uf->num_file;
+ if(index!=NULL) *index=i;
+ if(ze!=NULL) {
+ zres=UnzipData_Get(unz,i,ze);
+ if(zres!=ZR_OK) return zres;
+ }
+ return ZR_OK;
+}
+
+static void EnsureDirectory(const TCHAR *rootdir, const TCHAR *dir)
+{
+ TCHAR *lastslash,*name,*c;
+ TCHAR cd[MAX_PATH];
+ if(rootdir!=0 && GetFileAttributes(rootdir)==0xFFFFFFFF)
+ CreateDirectory(rootdir,0);
+ if(*dir==0) return;
+ lastslash=(TCHAR*)dir;
+ c=lastslash;
+ while(*c!=0) { if(*c=='/' || *c=='\\') lastslash=c; c++; }
+ name=lastslash;
+ if(lastslash!=dir) {
+ TCHAR tmp[MAX_PATH];
+ CopyMemory(tmp,dir,sizeof(TCHAR)*(lastslash-dir));
+ tmp[lastslash-dir]=0;
+ EnsureDirectory(rootdir,tmp);
+ name++;
+ }
+ *cd=0; if(rootdir!=0) lstrcpy(cd,rootdir); lstrcat(cd,dir);
+ if(GetFileAttributes(cd)==0xFFFFFFFF) CreateDirectory(cd,NULL);
+}
+
+static ZRESULT UnzipData_Unzip(UnzipData *unz,int index,void *dst,unsigned int len,DWORD flags)
+{
+ ZIPENTRY ze;
+ HANDLE h;
+ DWORD haderr=0;
+ BOOL reached_eof,bres;
+ DWORD writ;
+ int res;
+ if(flags!=ZIP_MEMORY && flags!=ZIP_FILENAME && flags!=ZIP_HANDLE)
+ return ZR_ARGS;
+ if(flags==ZIP_MEMORY) {
+ BOOL reached_eof;
+ int res;
+ if(index!=unz->currentfile) {
+ if(unz->currentfile!=-1) unzCloseCurrentFile(unz->uf);
+ unz->currentfile=-1;
+ if(index>=(int)unz->uf->gi.number_entry) return ZR_ARGS;
+ if(index<(int)unz->uf->num_file) unzGoToFirstFile(unz->uf);
+ while((int)unz->uf->num_file<index) unzGoToNextFile(unz->uf);
+ unzOpenCurrentFile(unz->uf,unz->password);
+ unz->currentfile=index;
+ }
+ res=unzReadCurrentFile(unz->uf,dst,len,&reached_eof);
+ if(res<=0) { unzCloseCurrentFile(unz->uf); unz->currentfile=-1; }
+ if(reached_eof) return ZR_OK;
+ if(res>0) return ZR_MORE;
+ if(res==UNZ_PASSWORD) return ZR_PASSWORD;
+ return ZR_FLATE;
+ }
+ // otherwise we're writing to a handle or a file
+ if(unz->currentfile!=-1) unzCloseCurrentFile(unz->uf);
+ unz->currentfile=-1;
+ if(index>=(int)unz->uf->gi.number_entry) return ZR_ARGS;
+ if(index<(int)unz->uf->num_file) unzGoToFirstFile(unz->uf);
+ while((int)unz->uf->num_file<index) unzGoToNextFile(unz->uf);
+ UnzipData_Get(unz,index,&ze);
+ // zipentry=directory is handled specially
+ if(ze.attr&FILE_ATTRIBUTE_DIRECTORY) {
+ BOOL isabsolute;
+ TCHAR *dir;
+ if(flags==ZIP_HANDLE) return ZR_OK; // don't do anything
+ dir=(TCHAR*)dst;
+ isabsolute=(dir[0]=='/' || dir[0]=='\\' || (dir[0]!=0 && dir[1]==':'));
+ if(isabsolute) EnsureDirectory(0,dir);
+ else EnsureDirectory(unz->rootdir,dir);
+ return ZR_OK;
+ }
+ // otherwise, we write the zipentry to a file/handle
+ if(flags==ZIP_HANDLE) h=dst;
+ else {
+ const TCHAR *ufn = (const TCHAR*)dst;
+ const TCHAR *name=ufn; const TCHAR *c=name;
+ TCHAR dir[MAX_PATH];
+ TCHAR fn[MAX_PATH];
+ BOOL isabsolute;
+ // We'll qualify all relative names to our root dir, and leave absolute names as they are
+ // ufn="zipfile.txt" dir="" name="zipfile.txt" fn="c:\\currentdir\\zipfile.txt"
+ // ufn="dir1/dir2/subfile.txt" dir="dir1/dir2/" name="subfile.txt" fn="c:\\currentdir\\dir1/dir2/subfiles.txt"
+ // ufn="\z\file.txt" dir="\z\" name="file.txt" fn="\z\file.txt"
+ // This might be a security risk, in the case where we just use the zipentry's name as "ufn", where
+ // a malicious zip could unzip itself into c:\windows. Our solution is that GetZipItem (which
+ // is how the user retrieve's the file's name within the zip) never returns absolute paths.
+ while (*c!=0) { if (*c=='/' || *c=='\\') name=c+1; c++; }
+ lstrcpy(dir,ufn); if (name==ufn) *dir=0; else dir[name-ufn]=0;
+ isabsolute = (dir[0]=='/' || dir[0]=='\\' || (dir[0]!=0 && dir[1]==':'));
+ if(isabsolute) { wsprintf(fn,_T("%s%s"),dir,name); EnsureDirectory(0,dir); }
+ else { wsprintf(fn,_T("%s%s%s"),unz->rootdir,dir,name); EnsureDirectory(unz->rootdir,dir); }
+ h=CreateFile(fn,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,ze.attr,NULL);
+ }
+ if(h==INVALID_HANDLE_VALUE) return ZR_NOFILE;
+ unzOpenCurrentFile(unz->uf,unz->password);
+ if(unz->unzbuf==0) unz->unzbuf=(char*)mir_alloc(16384);
+ for(;haderr==0;) {
+ res=unzReadCurrentFile(unz->uf,unz->unzbuf,16384,&reached_eof);
+ if(res==UNZ_PASSWORD) { haderr=ZR_PASSWORD; break; }
+ if(res<0) { haderr=ZR_FLATE; break; }
+ if(res>0) { bres=WriteFile(h,unz->unzbuf,res,&writ,NULL); if(!bres) { haderr=ZR_WRITE; break; } }
+ if(reached_eof) break;
+ if(res==0) {haderr=ZR_FLATE; break;}
+ }
+ if(!haderr) SetFileTime(h,&ze.ctime,&ze.atime,&ze.mtime); // may fail if it was a pipe
+ if(flags!=ZIP_HANDLE) CloseHandle(h);
+ unzCloseCurrentFile(unz->uf);
+ if(haderr!=0) return haderr;
+ return ZR_OK;
+}
+
+static ZRESULT UnzipData_Close(UnzipData *unz)
+{
+ if(unz->currentfile!=-1) unzCloseCurrentFile(unz->uf);
+ unz->currentfile=-1;
+ if(unz->uf!=0) unzClose(unz->uf);
+ unz->uf=0;
+ return ZR_OK;
+}
+
+typedef struct {
+ DWORD flag;
+ UnzipData *unz;
+} UnzipHandleData;
+
+HZIP OpenZip(void *z,unsigned int len,DWORD flags,const char *password)
+{
+ UnzipData *unz;
+ UnzipHandleData *han;
+ unz=UnzipData_Create(password);
+ if(UnzipData_Open(unz,z,len,flags)!=ZR_OK) {
+ UnzipData_Destroy(unz);
+ return 0;
+ }
+ han=(UnzipHandleData*)mir_alloc(sizeof(UnzipHandleData));
+ han->flag=1;
+ han->unz=unz;
+ return (HZIP)han;
+}
+
+ZRESULT GetZipItem(HZIP hz,int index,ZIPENTRY *ze)
+{
+ UnzipHandleData *han=(UnzipHandleData*)hz;
+ ze->index=0; *ze->name=0; ze->unc_size=0;
+ if(hz==NULL) return ZR_ARGS;
+ if(han->flag!=1) return ZR_ZMODE;
+ return UnzipData_Get(han->unz,index,ze);
+}
+
+ZRESULT FindZipItem(HZIP hz,const TCHAR *name,BOOL ic,int *index,ZIPENTRY *ze)
+{
+ UnzipHandleData *han=(UnzipHandleData*)hz;
+ if(hz==NULL) return ZR_ARGS;
+ if(han->flag!=1) return ZR_ZMODE;
+ return UnzipData_Find(han->unz,name,ic,index,ze);
+}
+
+ZRESULT UnzipItem(HZIP hz,int index,void *dst,unsigned int len,DWORD type)
+{
+ UnzipHandleData *han=(UnzipHandleData*)hz;
+ if(hz==NULL) return ZR_ARGS;
+ if(han->flag!=1) return ZR_ZMODE;
+ return UnzipData_Unzip(han->unz,index,dst,len,type);
+}
+
+ZRESULT SetUnzipBaseDir(HZIP hz,const TCHAR *dir)
+{
+ UnzipHandleData *han=(UnzipHandleData*)hz;
+ if(hz==NULL) return ZR_ARGS;
+ if(han->flag!=1) return ZR_ZMODE;
+ return UnzipData_SetUnzipBaseDir(han->unz,dir);
+}
+
+ZRESULT CloseZip(HZIP hz)
+{
+ ZRESULT err;
+ UnzipHandleData *han=(UnzipHandleData*)hz;
+ if(hz==NULL) return ZR_ARGS;
+ if(han->flag!=1) return ZR_ZMODE;
+ err=UnzipData_Close(han->unz);
+ UnzipData_Destroy(han->unz);
+ mir_free(han);
+ return err;
+}
diff --git a/Help/unzip.h b/Help/unzip.h
new file mode 100644
index 0000000..aba0d1f
--- /dev/null
+++ b/Help/unzip.h
@@ -0,0 +1,122 @@
+
+// UNZIPPING functions -- for unzipping.
+
+// This file is a repackaged form of extracts from the zlib code available
+// at http://www.gzip.org/zlib, by Jean-Loup Gailly and Mark Adler. The original
+// copyright notice may be found in unzip.c. The repackaging was done
+// by Lucian Wischik to simplify and extend its use in Windows/C++. Also
+// encryption and Unicode filenames have been added.
+
+// An HZIP identifies a zip file that has been opened
+DECLARE_HANDLE(HZIP);
+
+// return codes from any of the zip functions
+typedef DWORD ZRESULT;
+// These are the result codes:
+#define ZR_OK 0x00000000
+// The following come from general system stuff (e.g. files not openable)
+#define ZR_GENMASK 0x0000FF00
+#define ZR_NODUPH 0x00000100 // couldn't duplicate the handle
+#define ZR_NOFILE 0x00000200 // couldn't create/open the file
+#define ZR_NOALLOC 0x00000300 // failed to allocate some resource
+#define ZR_WRITE 0x00000400 // a general error writing to the file
+#define ZR_NOTFOUND 0x00000500 // couldn't find that file in the zip
+#define ZR_MORE 0x00000600 // there's still more data to be unzipped
+#define ZR_CORRUPT 0x00000700 // the zipfile is corrupt or not a zipfile
+#define ZR_READ 0x00000800 // a general error reading the file
+#define ZR_PASSWORD 0x00001000 // we didn't get the right password to unzip the file
+// The following come from mistakes on the part of the caller
+#define ZR_CALLERMASK 0x00FF0000
+#define ZR_ARGS 0x00010000 // general mistake with the arguments
+#define ZR_MEMSIZE 0x00030000 // the memory size is too small
+#define ZR_FAILED 0x00040000 // the thing was already failed when you called this function
+#define ZR_ENDED 0x00050000 // the zip creation has already been closed
+#define ZR_MISSIZE 0x00060000 // the indicated input file size turned out mistaken
+#define ZR_ZMODE 0x00080000 // tried to mix creating/opening a zip
+// The following come from bugs within the zip library itself
+#define ZR_BUGMASK 0xFF000000
+#define ZR_NOTINITED 0x01000000 // initialisation didn't work
+#define ZR_SEEK 0x02000000 // trying to seek in an unseekable file
+#define ZR_NOCHANGE 0x04000000 // changed its mind on storage, but not allowed
+#define ZR_FLATE 0x05000000 // an internal error in the de/inflation code
+
+// parameter types
+#define ZIP_HANDLE 1 // expects HANDLE hFile
+#define ZIP_FILENAME 2 // expects TCHAR* filename
+#define ZIP_MEMORY 3 // expects memory buffer
+
+// OpenZip - opens a zip file and returns a handle with which you can
+// subsequently examine its contents. You can open a zip file from:
+// from a file (by handle): OpenZipHandle(hfile,0);
+// from a file (by name): OpenZipFile("c:\\test.zip","password");
+// from a memory block: OpenZipMem(bufstart, buflen,0);
+// If the file is opened through a pipe, then items may only be
+// accessed in increasing order, and an item may only be unzipped once,
+// although GetZipItem can be called immediately before and after unzipping
+// it. If it's opened in any other way, then full random access is possible.
+// Note: pipe input is not yet implemented.
+// Note: zip passwords are ascii, not unicode.
+// Note: for windows-ce, you cannot close the handle until after CloseZip.
+// but for real windows, the zip makes its own copy of your handle, so you
+// can close yours anytime.
+HZIP OpenZip(void *z,unsigned int len,DWORD flags,const char *password);
+#define OpenZipHandle(h,password) OpenZip((void*)h,0,ZIP_HANDLE,password)
+#define OpenZipFile(fn,password) OpenZip((void*)fn,0,ZIP_FILENAME,password)
+#define OpenZipMem(z,len,password) OpenZip(z,len,ZIP_MEMORY,password)
+
+// GetZipItem - call this to get information about an item in the zip.
+// If index is -1 and the file wasn't opened through a pipe,
+// then it returns information about the whole zipfile
+// (and in particular ze.index returns the number of index items).
+// Note: the item might be a directory (ze.attr & FILE_ATTRIBUTE_DIRECTORY)
+// See below for notes on what happens when you unzip such an item.
+// Note: if you are opening the zip through a pipe, then random access
+// is not possible and GetZipItem(-1) fails and you can't discover the number
+// of items except by calling GetZipItem on each one of them in turn,
+// starting at 0, until eventually the call fails. Also, in the event that
+// you are opening through a pipe and the zip was itself created into a pipe,
+// then then comp_size and sometimes unc_size as well may not be known until
+// after the item has been unzipped.
+typedef struct {
+ int index; // index of this file within the zip
+ TCHAR name[MAX_PATH]; // filename within the zip
+ DWORD attr; // attributes, as in GetFileAttributes.
+ FILETIME atime,ctime,mtime; // access, create, modify filetimes
+ long comp_size; // sizes of item, compressed and uncompressed. These
+ long unc_size; // may be -1 if not yet known (e.g. being streamed in)
+} ZIPENTRY;
+ZRESULT GetZipItem(HZIP hz,int index,ZIPENTRY *ze);
+
+// FindZipItem - finds an item by name. ic means 'insensitive to case'.
+// If index is not NULL it contains the index where the search begin on input.
+// It returns the index of the item, and returns information about it.
+// If nothing was found, then index is set to -1 and the function returns
+// an error code.
+// name is allowed to contain wildcards.
+ZRESULT FindZipItem(HZIP hz, const TCHAR *name, BOOL ic, int *index, ZIPENTRY *ze);
+
+// UnzipItem - given an index to an item, unzips it. You can unzip to:
+// to a file (by handle): UnzipItemHandle(hz,i, hfile);
+// to a file (by name): UnzipItemFile(hz,i, ze.name);
+// to a memory block: UnzipItemMem(hz,i, buf,buflen);
+// In the final case, if the buffer isn't large enough to hold it all,
+// then the return code indicates that more is yet to come. If it was
+// large enough, and you want to know precisely how big, GetZipItem.
+// Note: zip files are normally stored with relative pathnames. If you
+// unzip with ZIP_FILENAME a relative pathname then the item gets created
+// relative to the current directory - it first ensures that all necessary
+// subdirectories have been created. Also, the item may itself be a directory.
+// If you unzip a directory with ZIP_FILENAME, then the directory gets created.
+// If you unzip it to a handle or a memory block, then nothing gets created
+// and it emits 0 bytes.
+ZRESULT UnzipItem(HZIP hz,int index,void *dst,unsigned int len,DWORD type);
+#define UnzipItemHandle(hz,index,h) UnzipItem(hz,index,(void*)h,0,ZIP_HANDLE)
+#define UnzipItemFile(hz,index,fn) UnzipItem(hz,index,(void*)fn,0,ZIP_FILENAME)
+#define UnzipItemMem(hz,index,z,len) UnzipItem(hz,index,z,len,ZIP_MEMORY)
+
+// if unzipping to a filename, and it's a relative filename, then it will be relative to here.
+// (defaults to current-directory).
+ZRESULT SetUnzipBaseDir(HZIP hz,const TCHAR *dir);
+
+// CloseZip - the zip handle must be closed with this function.
+ZRESULT CloseZip(HZIP hz);
diff --git a/Help/update.c b/Help/update.c
new file mode 100644
index 0000000..4dafe61
--- /dev/null
+++ b/Help/update.c
@@ -0,0 +1,1082 @@
+/*
+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 <tchar.h>
+#include <stdio.h>
+#define _WIN32_WINNT 0x0500
+#define __RPCASYNC_H__ /* header shows warnings in VS6 */
+#include <windows.h>
+#include <win2k.h>
+#define MIRANDA_VER 0x0600
+#include <newpluginapi.h>
+#include <m_system.h>
+#include <m_database.h>
+#include <m_utils.h>
+#include <m_langpack.h>
+#include <m_netlib.h>
+#include <m_skin.h>
+#include <m_icolib.h>
+#include <m_clist.h>
+#include "m_help.h"
+#include "help.h"
+#include "unzip.h"
+#include "resource.h"
+#include "version.h"
+
+/* Lang Dlg */
+static HANDLE hServiceShowLangDialog;
+/* Misc */
+extern HINSTANCE hInst;
+static HANDLE hHookModulesLoaded,hHookPreShutdown;
+static HANDLE hNetlibUser;
+
+/************************* Download Update ****************************/
+
+static BOOL FillUserAgent(char *pszUserAgent,int nSize)
+{
+ char *pspace,szMirandaVer[32];
+ if(!CallService(MS_SYSTEM_GETVERSIONTEXT,SIZEOF(szMirandaVer),(LPARAM)szMirandaVer)) {
+ pspace=strchr(szMirandaVer,' ');
+ if(pspace) {
+ *pspace++='\0';
+ mir_snprintf(pszUserAgent,nSize,"Miranda/%s (%s) HelpPlugin/%s",szMirandaVer,pspace,USERAGENT_VERSION);
+ }
+ else mir_snprintf(pszUserAgent,nSize,"Miranda/%s HelpPlugin/%s",szMirandaVer,USERAGENT_VERSION);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static void EnsurePackHeader(HANDLE hFile,const char *pszFileVersionHeader,const char *pszTitle,const char *pszVersion)
+{
+ DWORD dataSize,read;
+ BYTE *pData,*pBuf;
+ int headerLength,infoLength;
+
+ /* file size */
+ dataSize=GetFileSize(hFile,NULL);
+ if(dataSize==INVALID_FILE_SIZE) return;
+ headerLength=lstrlenA(pszFileVersionHeader);
+ pData=(BYTE*)mir_alloc(dataSize);
+ infoLength=lstrlenA(pszTitle)+lstrlenA(pszVersion)+27;
+ pBuf=(BYTE*)mir_alloc(infoLength);
+ if(pData!=NULL && pBuf!=NULL) {
+ /* compare header */
+ Netlib_Logf(hNetlibUser,"Ensure pack header");
+ SetFilePointer(hFile,0,NULL,FILE_BEGIN);
+ read=0;
+ if(ReadFile(hFile,pData,headerLength,&read,NULL)) {
+ if(!strncmp(pszFileVersionHeader,(char*)pData,read)) {
+ /* read all data */
+ read=0;
+ if(ReadFile(hFile,pData,dataSize-headerLength,&read,NULL)) {
+ dataSize=read;
+ /* prepend header */
+ SetFilePointer(hFile,headerLength,NULL,FILE_BEGIN);
+ wsprintfA((char*)pBuf,"\r\nX-FLName: %s\r\nX-Version: %s",pszTitle,pszVersion); /* buffer safe */
+ WriteFile(hFile,pBuf,infoLength-1,&read,NULL);
+ /* write it back */
+ if(!WriteFile(hFile,pData,dataSize,&read,NULL))
+ Netlib_Logf(hNetlibUser,"Write pack failed (%u)",GetLastError());
+ } else Netlib_Logf(hNetlibUser,"Read pack failed (%u)",GetLastError());
+ } else Netlib_Logf(hNetlibUser,"Invalid pack file format");
+ } else Netlib_Logf(hNetlibUser,"Read pack failed (%u)",GetLastError());
+ }
+ mir_free(pData); /* does NULL check */
+ mir_free(pBuf); /* does NULL check */
+}
+
+static void CleanupFileName(TCHAR *pszFileName,const char *pszVersion)
+{
+ TCHAR *p,*p2;
+ int len;
+ TCHAR szVersion[16];
+#if defined(_UNICODE)
+ szVersion[0]=_T('\0');
+ MultiByteToWideChar(CP_ACP,0,pszVersion,-1,szVersion,SIZEOF(szVersion));
+#else
+ lstrcpyn(szVersion,pszVersion,SIZEOF(szVersion));
+#endif
+ /* disallow version indicator in filename */
+ p=_tcsstr(pszFileName,szVersion);
+ if(p!=NULL) {
+ len=lstrlen(szVersion);
+ p2=CharPrev(pszFileName,p);
+ if(*p2=='v') p2=CharPrev(pszFileName,p2);
+ if(p2==pszFileName || (*p2!='-' && *p2!='_')) p2=p;
+ MoveMemory(p2,p+len,(lstrlen(p+len)+1)*sizeof(TCHAR));
+ }
+ /* lower case */
+ CharLower(pszFileName);
+ /* replace any '-' by '_' */
+ for(p=pszFileName;*p!='\0';p=CharNext(p)) {
+ if(*p=='-') *p='_';
+ else if(*p==' ') *p='_';
+ }
+ /* disallow digits */
+ for(p=pszFileName;*p!='\0';p=CharNext(p))
+ if(isdigit(*p)) {
+ p2=CharPrev(pszFileName,p);
+ if(*p2=='-' || *p2=='_')
+ p=p2;
+ *p='.'; /* handle together with dots */
+ break;
+ }
+ /* disallow any dots except extension */
+ p=_tcschr(pszFileName,'.');
+ p2=_tcsrchr(pszFileName,'.');
+ if(p!=NULL && p2!=NULL)
+ MoveMemory(p,p2,(lstrlen(p2)+1)*sizeof(TCHAR));
+}
+
+// pszFileName is allowed to be NULL, uses obtained file name in this case
+static BOOL DownloadPack(WORD id,const TCHAR *pszFilePattern,BOOL fEnabledPacks,const TCHAR *pszFileName,const char *pszFileVersionHeader,const char *pszTitle,const char *pszVersion)
+{
+ TCHAR *pszFilePatternPrefix,*pszFilePatternExt;
+ NETLIBHTTPREQUEST req,*resp;
+ NETLIBHTTPHEADER headers[1];
+ char szUrl[64],szUserAgent[128];
+ BOOL fSuccess=FALSE;
+ TCHAR *pszContentFileName,*pszExt;
+ TCHAR szFileName[MAX_PATH];
+ HANDLE hFile;
+ DWORD written;
+ int i;
+#if defined(_UNICODE)
+ TCHAR szContentDisp[MAX_PATH];
+#endif
+
+ /* split file pattern */
+ pszFilePatternPrefix=lstrcpy((TCHAR*)_alloca(lstrlen(pszFilePattern)+1),pszFilePattern);
+ pszFilePatternExt=_tcschr(pszFilePatternPrefix,_T('*')); /* can't fail, static input */
+ *(pszFilePatternExt++)='\0';
+
+ ZeroMemory(&req,sizeof(req));
+ req.cbSize=sizeof(req);
+ req.requestType=REQUEST_GET;
+ mir_snprintf(szUrl,sizeof(szUrl),"http://addons.miranda-im.org/feed.php?dlfile=%u",id);
+ req.szUrl=szUrl;
+ req.flags=NLHRF_HTTP11|NLHRF_NODUMP;
+ headers[0].szName="User-Agent";
+ headers[0].szValue=szUserAgent;
+ if(FillUserAgent(szUserAgent,SIZEOF(szUserAgent)))
+ req.headersCount=1;
+ req.headers=headers;
+
+ Netlib_Logf(hNetlibUser,"Download pack: %s (ver:%s)",szUrl,pszVersion);
+ resp=(NETLIBHTTPREQUEST*)CallService(MS_NETLIB_HTTPTRANSACTION,(WPARAM)hNetlibUser,(LPARAM)&req);
+ if(resp!=NULL) {
+ /* get content filename */
+ pszContentFileName=pszExt=NULL;
+ for(i=0;i<resp->headersCount;++i)
+ if(!lstrcmpA(resp->headers[i].szName,"Content-Disposition")) {
+#if defined(_UNICODE)
+ szContentDisp[0]=_T('\0');
+ MultiByteToWideChar(CP_ACP,0,resp->headers[i].szValue,-1,szContentDisp,SIZEOF(szContentDisp));
+ pszContentFileName=_tcsrchr(szContentDisp,_T('='));
+ pszExt=_tcsrchr(szContentDisp,_T('.'));
+#else
+ pszContentFileName=_tcsrchr(resp->headers[i].szValue,_T('='));
+ pszExt=_tcsrchr(resp->headers[i].szValue,_T('.'));
+#endif
+ break;
+ }
+ /* valid result? */
+ if(resp->resultCode==200 && pszContentFileName!=NULL && pszExt!=NULL && resp->dataLength) {
+ ++pszContentFileName;
+ /* txt-file, save directly */
+ if(!lstrcmpi(pszExt,pszFilePatternExt)) {
+ Netlib_Logf(hNetlibUser,"txt-data ("TCHAR_STR_PARAM")",pszContentFileName);
+ /* proper file name */
+ if(pszFileName!=NULL) pszContentFileName=(TCHAR*)pszFileName;
+ else CleanupFileName(pszContentFileName,pszVersion);
+ /* write file */
+ if(GetPackPath(szFileName,SIZEOF(szFileName),fEnabledPacks,pszContentFileName)) {
+ hFile=CreateFile(szFileName,GENERIC_WRITE|GENERIC_READ,FILE_SHARE_READ,0,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,0);
+ if(hFile!=INVALID_HANDLE_VALUE) {
+ Netlib_Logf(hNetlibUser,"Output: "TCHAR_STR_PARAM,szFileName);
+ fSuccess=WriteFile(hFile,resp->pData,resp->dataLength,&written,NULL);
+ if(fSuccess) EnsurePackHeader(hFile,pszFileVersionHeader,pszTitle,pszVersion);
+ CloseHandle(hFile);
+ /* remove duplicate */
+ if(fEnabledPacks && GetPackPath(szFileName,SIZEOF(szFileName),FALSE,pszContentFileName))
+ DeleteFile(szFileName);
+ }
+ if(!fSuccess) Netlib_Logf(hNetlibUser,"Write failed (%u)",GetLastError());
+ }
+ else Netlib_Logf(hNetlibUser,"Write failed");
+ }
+ /* zip-file, unzip txt-file in it */
+ else {
+ HZIP hz;
+ ZIPENTRY ze;
+ int index=0;
+ BOOL fFound=FALSE;
+ /* open zip */
+ Netlib_Logf(hNetlibUser,"zip-data ("TCHAR_STR_PARAM")",pszContentFileName);
+ hz=OpenZipMem(resp->pData,resp->dataLength,NULL);
+ if(hz!=NULL) {
+ Netlib_Logf(hNetlibUser,"Search "TCHAR_STR_PARAM" in zip",pszFilePattern);
+ /* enum pack file in zip */
+ while(!FindZipItem(hz,pszFilePattern,TRUE,&index,&ze)) {
+ /* skip some confusingly named files */
+ if(_tcsstr(ze.name,_T("readme"))==NULL && _tcsstr(ze.name,_T("history"))==NULL) {
+ fFound=TRUE;
+ Netlib_Logf(hNetlibUser,"Found "TCHAR_STR_PARAM" in zip",ze.name);
+ /* proper file name */
+ if(pszFileName!=NULL) pszContentFileName=(TCHAR*)pszFileName;
+ else CleanupFileName(pszContentFileName=ze.name,pszVersion);
+ /* open file */
+ if(GetPackPath(szFileName,SIZEOF(szFileName),fEnabledPacks,pszContentFileName)) {
+ hFile=CreateFile(szFileName,GENERIC_WRITE|GENERIC_READ,FILE_SHARE_READ,0,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,0);
+ if(hFile!=INVALID_HANDLE_VALUE) {
+ Netlib_Logf(hNetlibUser,"Output: "TCHAR_STR_PARAM,szFileName);
+ /* unzip */
+ fSuccess=!UnzipItemHandle(hz,ze.index,hFile);
+ if(fSuccess) EnsurePackHeader(hFile,pszFileVersionHeader,pszTitle,pszVersion);
+ else Netlib_Logf(hNetlibUser,"Invalid zip-item");
+ CloseHandle(hFile);
+ /* remove duplicate */
+ if(fEnabledPacks && GetPackPath(szFileName,SIZEOF(szFileName),FALSE,pszContentFileName))
+ DeleteFile(szFileName);
+ } else Netlib_Logf(hNetlibUser,"Write failed (%u)",GetLastError());
+ } else Netlib_Logf(hNetlibUser,"Write failed (%u)",GetLastError());
+ }
+ ++index; /* skip current */
+ }
+ CloseZip(hz);
+ if(!fFound) Netlib_Logf(hNetlibUser,"No match found");
+ }
+ else Netlib_Logf(hNetlibUser,"Invalid zip-data");
+ }
+ }
+ else Netlib_Logf(hNetlibUser,"No acceptable response from HTTP request");
+ CallService(MS_NETLIB_FREEHTTPREQUESTSTRUCT,0,(LPARAM)resp);
+ }
+ else Netlib_Logf(hNetlibUser,"No response from HTTP request");
+
+ return fSuccess;
+}
+
+/************************* Enum Updates *******************************/
+
+#define CACHETIME 23*60*60 // refresh cache every 23 hours (seconds)
+
+typedef struct {
+ char *pszTitle;
+ WORD id;
+ char *pszVersion;
+ char *pszSubCategory;
+ FILETIME ftFileDate;
+} UPDATE_INFO;
+typedef BOOL (CALLBACK *ENUM_UPDATES_CALLBACK)(UPDATE_INFO *upd,WORD nRemaining,WPARAM wParam,LPARAM lParam);
+
+// similar to strstr but allowes the searched buffer to contain zeros
+static BYTE* FindStrInBlobI(const BYTE *pData,const BYTE *pLast,const char *pszStr)
+{
+ register BYTE *p;
+ int i;
+ for(p=(BYTE*)pData;p<=pLast;++p) {
+ for(i=0;pszStr[i] && (p+i)<=pLast;++i)
+ if(_tolower(*(p+i))!=_tolower(pszStr[i]))
+ break;
+ if(pszStr[i]=='\0') return (BYTE*)p;
+ }
+ return NULL;
+}
+
+// pszBeginTag is allowed to be NULL
+// returned value points into the buffer, returns an empty string on error
+static char* GetTagValue(const BYTE *pBlock,int blockLength,const char *pszBeginTag,const char *pszEndTag)
+{
+ register BYTE *p,*pLast,*pVal;
+ pLast=(BYTE*)pBlock+blockLength-1;
+ /* begin tag */
+ if(pszBeginTag!=NULL) {
+ pVal=FindStrInBlobI(pBlock,pLast,pszBeginTag);
+ if(pVal==NULL) return ""; /* static */
+ pVal+=lstrlenA(pszBeginTag);
+ } else pVal=(BYTE*)pBlock;
+ /* end tag */
+ p=FindStrInBlobI(pBlock,pLast,pszEndTag);
+ if(p==NULL) return ""; /* static */
+ *p='\0';
+ return (char*)pVal;
+}
+
+// pBlock and blockLength must be set to the previous block before call
+static BOOL GetNextBlock(const BYTE *pData,int dataLength,const char *pszBlockBeginTag,const char *pszBlockEndTag,BYTE **ppBlock,int *blockLength)
+{
+ register BYTE *p,*pLast;
+ pLast=(BYTE*)pData+dataLength-1;
+ /* begin tag */
+ p=FindStrInBlobI((*ppBlock)+(*blockLength),pLast,pszBlockBeginTag);
+ if(p==NULL) return FALSE;
+ *ppBlock=p+lstrlenA(pszBlockBeginTag);
+ /* end tag */
+ p=FindStrInBlobI(p,pLast,pszBlockEndTag);
+ if(p==NULL) return FALSE;
+ *blockLength=p-(*ppBlock);
+ return TRUE;
+}
+
+// ppsz points just after first occurence of chr on return
+static WORD ParseWord(char **ppsz,int chr)
+{
+ register char *p1,*p2;
+ p1=strchr(*ppsz,chr);
+ if(p1==NULL) return 0;
+ *p1='\0';
+ p2=*ppsz;
+ *ppsz=p1+1;
+ return (WORD)atoi(p2);
+}
+
+static void EnumUpdates_Worker(BYTE *pData,int dataLength,BOOL *pbSuccess,BOOL fAllowRefetch,ENUM_UPDATES_CALLBACK callback,WPARAM wParam,LPARAM lParam)
+{
+ UPDATE_INFO upd;
+ WORD nRemaining;
+ SYSTEMTIME st;
+ BYTE *pBlock;
+ int blockLength;
+ char *pszUpdated;
+
+ /* count items */
+ pBlock=pData;
+ blockLength=0;
+ for(nRemaining=0;GetNextBlock(pData,dataLength,"<item>","</item>",&pBlock,&blockLength);++nRemaining);
+ if(fAllowRefetch) Netlib_Logf(hNetlibUser,"Data sets: %u",nRemaining);
+
+ /* parse data */
+ pBlock=pData;
+ blockLength=0;
+ ZeroMemory(&st,sizeof(st)); /* init unused members */
+ for(;;) {
+ if(!GetNextBlock(pData,dataLength,"<item>","</item>",&pBlock,&blockLength))
+ break;
+ --nRemaining;
+ ZeroMemory(&upd,sizeof(upd));
+ upd.pszTitle=GetTagValue(pBlock,blockLength,"<title>","</title>");
+ upd.id=(WORD)atoi(GetTagValue(pBlock,blockLength,"<id>","</id>"));
+ if(!upd.id) continue; /* never happens */
+ upd.pszVersion=GetTagValue(pBlock,blockLength,"<version>","</version>");
+ upd.pszSubCategory=GetTagValue(pBlock,blockLength,"<subcategory>","</subcategory>");
+
+ /* parse time */
+ pszUpdated=GetTagValue(pBlock,blockLength,"<updated>","</updated>");
+ st.wYear=ParseWord(&pszUpdated,'-'); /* time is formated as follows: */
+ st.wMonth=ParseWord(&pszUpdated,'-'); /* yyyy-mm-dd hh:mm:ss */
+ st.wDay=ParseWord(&pszUpdated,' ');
+ st.wHour=ParseWord(&pszUpdated,':');
+ st.wMinute=ParseWord(&pszUpdated,':');
+ st.wSecond=(WORD)atoi(pszUpdated);
+ SystemTimeToFileTime(&st,&upd.ftFileDate);
+
+ /* callback */
+ *pbSuccess=callback(&upd,nRemaining,wParam,lParam);
+ if(!*pbSuccess) break;
+ }
+}
+
+static BOOL EnumUpdates(ENUM_UPDATES_CALLBACK callback,const TCHAR *pszDataFile,BOOL fAllowRefetch,WPARAM wParam,LPARAM lParam)
+{
+ TCHAR szCacheFile[MAX_PATH],*p;
+ HANDLE hFile;
+ BOOL fSuccess=FALSE;
+
+ if(fAllowRefetch) Netlib_Logf(hNetlibUser,"Enumerate data sets");
+
+ /* read from cache */
+ if(GetTempPath(SIZEOF(szCacheFile)-lstrlen(pszDataFile),szCacheFile)) {
+ BYTE *pData;
+ int dataLength;
+ DWORD read,age;
+ FILETIME ftLastWrite,ft;
+ /* ensure last subdirectory exists */
+ CreateDirectory(szCacheFile,NULL);
+ /* file name */
+ p=_tcsrchr(szCacheFile,_T('\\'));
+ if(p!=NULL && *p!=_T('\\')) lstrcat(p,_T("\\")); /* buffer safe */
+ lstrcat(szCacheFile,pszDataFile); /* buffer safe */
+ /* try to open file */
+ hFile=CreateFile(szCacheFile,GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,0,0);
+ if(fAllowRefetch) Netlib_Logf(hNetlibUser,"Try to read from cache ("TCHAR_STR_PARAM")...",szCacheFile);
+ if(hFile!=INVALID_HANDLE_VALUE) {
+ /* analyze file age */
+ /* last-write file time resolution is acceptable
+ * on file systems for our calculation */
+ GetSystemTimeAsFileTime(&ft);
+ if(GetFileTime(hFile,NULL,NULL,&ftLastWrite)) {
+ ft.dwHighDateTime-=ftLastWrite.dwHighDateTime;
+ ft.dwLowDateTime-=ftLastWrite.dwLowDateTime;
+ /* calc elapsed seconds */
+ age=(DWORD)((((ULONGLONG)ft.dwHighDateTime)<<32)/10000000)+(ft.dwLowDateTime/10000000);
+ if(age<CACHETIME) {
+ /* file size */
+ dataLength=GetFileSize(hFile,NULL); /* low size is enough as our http transact can't handle more */
+ if(dataLength==INVALID_FILE_SIZE) dataLength=0;
+ pData=(BYTE*)mir_alloc(dataLength+1);
+ /* load all data */
+ read=0;
+ if(pData!=NULL && ReadFile(hFile,pData,dataLength,&read,NULL)) {
+ CloseHandle(hFile);
+ /* enum cached data */
+ if(fAllowRefetch) Netlib_Logf(hNetlibUser,"Cache valid (age:%usec, threshold:%usec)",age,CACHETIME);
+ EnumUpdates_Worker(pData,read,&fSuccess,fAllowRefetch,callback,wParam,lParam);
+ mir_free(pData);
+ return TRUE; /* done */
+ }
+ else Netlib_Logf(hNetlibUser,"Cache access failed (%u)",GetLastError());
+ mir_free(pData); /* does NULL check */
+ }
+ else Netlib_Logf(hNetlibUser,"Cache is too old (age: %u sec, threshold: %u sec)",age,CACHETIME);
+ }
+ CloseHandle(hFile);
+ }
+ else Netlib_Logf(hNetlibUser,"Cache not available");
+ }
+ else {
+ Netlib_Logf(hNetlibUser,"Cache access failed (%u)",GetLastError());
+ szCacheFile[0]=_T('\0');
+ }
+
+ /* download again */
+ if(fAllowRefetch) {
+ NETLIBHTTPREQUEST req,*resp;
+ NETLIBHTTPHEADER headers[1];
+ DWORD written;
+ char szUrl[64],szUserAgent[128];
+
+ ZeroMemory(&req,sizeof(req));
+ req.cbSize=sizeof(req);
+ req.requestType=REQUEST_GET;
+ mir_snprintf(szUrl,sizeof(szUrl),"http://addons.miranda-im.org/backend/"TCHAR_STR_PARAM,pszDataFile);
+ req.szUrl=szUrl;
+ req.flags=NLHRF_HTTP11|NLHRF_DUMPASTEXT;
+ headers[0].szName="User-Agent";
+ headers[0].szValue=szUserAgent;
+ if(FillUserAgent(szUserAgent,SIZEOF(szUserAgent)))
+ req.headersCount=1;
+ req.headers=headers;
+
+ Netlib_Logf(hNetlibUser,"Downloading data sets: "TCHAR_STR_PARAM,pszDataFile);
+ resp=(NETLIBHTTPREQUEST*)CallService(MS_NETLIB_HTTPTRANSACTION,(WPARAM)hNetlibUser,(LPARAM)&req);
+ if(resp!=NULL) {
+ if(resp->resultCode==200 && resp->dataLength) {
+ /* keep cache */
+ hFile=CreateFile(szCacheFile,GENERIC_WRITE,FILE_SHARE_READ,0,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,0);
+ if(hFile!=INVALID_HANDLE_VALUE) {
+ if(WriteFile(hFile,resp->pData,resp->dataLength,&written,NULL))
+ Netlib_Logf(hNetlibUser,"Cache output: "TCHAR_STR_PARAM,szCacheFile);
+ CloseHandle(hFile);
+ }
+ else Netlib_Logf(hNetlibUser,"Cache output failed (%u)",GetLastError());
+ EnumUpdates_Worker((BYTE*)resp->pData,resp->dataLength,&fSuccess,fAllowRefetch,callback,wParam,lParam);
+ }
+ else Netlib_Logf(hNetlibUser,"No acceptable response from HTTP request");
+ CallService(MS_NETLIB_FREEHTTPREQUESTSTRUCT,0,(LPARAM)resp);
+ }
+ else Netlib_Logf(hNetlibUser,"No response from HTTP request");
+ }
+
+ return fSuccess;
+}
+
+/************************* Lang Dlg ***********************************/
+
+static HWND hwndLangDlg;
+
+#define UPDATEANIMFRAMES 20
+#define M_STARTANIM (WM_APP+1)
+#define M_STOPANIM (WM_APP+2)
+#define M_FINISH (WM_APP+3)
+
+struct DownloadSelectionParams {
+ HWND hwndDlg;
+ HWND hwndCombo;
+ BOOL fDownloadAll;
+};
+
+static BOOL CALLBACK DownloadLatestEnumProc(UPDATE_INFO *upd,WORD nRemaining,WPARAM wParam,LPARAM lParam)
+{
+ UPDATE_INFO *updLast=(UPDATE_INFO*)lParam;
+ /* find latest */
+ if(!lstrcmpA(upd->pszSubCategory,updLast->pszSubCategory))
+ if(!updLast->id || CompareFileTime(&upd->ftFileDate,&updLast->ftFileDate)>0)
+ CopyMemory(updLast,upd,sizeof(UPDATE_INFO));
+ /* download */
+ if(!nRemaining && updLast->id)
+ if(!DownloadPack(updLast->id,_T("helppack_*.txt"),(BOOL)wParam,NULL,"Miranda Help Pack Version 1",updLast->pszTitle,updLast->pszVersion)) {
+ updLast->id=0;
+ if((BOOL)wParam) return FALSE; /* stop it */
+ }
+ return TRUE;
+}
+
+static void DownloadSelectionThread(struct DownloadSelectionParams *arg)
+{
+ UPDATE_INFO updLast;
+ int index,sel,count;
+ int fSuccess=0;
+
+ SendMessage(arg->hwndDlg,M_STARTANIM,0,0);
+ sel=SendMessage(arg->hwndCombo,CB_GETCURSEL,0,0);
+ updLast.pszTitle=NULL;
+
+ /* disable all */
+ CorrectPacks(_T("helppack_*.txt"),_T("helppack_english.txt"),TRUE);
+
+ /* enum subcategories */
+ count=SendMessage(arg->hwndCombo,CB_GETCOUNT,0,0);
+ for(index=0;index<count;++index) {
+ if(!arg->fDownloadAll && sel!=index) continue;
+ /* get subcategory */
+ ZeroMemory(&updLast,sizeof(UPDATE_INFO));
+ updLast.pszSubCategory=(char*)SendMessage(arg->hwndCombo,CB_GETITEMDATA,index,0);
+ if(updLast.pszSubCategory==NULL || (int)updLast.pszSubCategory==CB_ERR) {
+ if(!arg->fDownloadAll) fSuccess=-1;
+ continue;
+ }
+ /* show status */
+ if(arg->fDownloadAll) SendMessage(arg->hwndCombo,CB_SETCURSEL,index,0);
+ /* download latest */
+ EnumUpdates(DownloadLatestEnumProc,_T("category_localisation.xml"),FALSE,sel==index,(LPARAM)&updLast);
+ if(updLast.id) fSuccess=1;
+ if(!IsWindowVisible(arg->hwndDlg)) break; /* canceled? */
+ if(!arg->fDownloadAll) break;
+ }
+
+ if(arg->fDownloadAll) SendMessage(arg->hwndCombo,CB_SETCURSEL,sel,0);
+
+ /* ensure one is enabled */
+ CorrectPacks(_T("helppack_*.txt"),_T("helppack_english.txt"),FALSE);
+
+ ReloadLangOptList();
+ SendMessage(arg->hwndDlg,M_STOPANIM,0,0);
+ PostMessage(arg->hwndDlg,M_FINISH,fSuccess,0);
+
+ mir_free(arg);
+}
+
+struct PopulateComboBoxParams {
+ HWND hwndDlg;
+ HWND hwndCombo;
+ HWND hwndOk;
+};
+
+static BOOL CALLBACK PopulateComboBoxEnumProc(UPDATE_INFO *upd,WORD nRemaining,WPARAM wParam,LPARAM lParam)
+{
+ struct PopulateComboBoxParams *arg=(struct PopulateComboBoxParams*)wParam;
+ int index;
+ char *pszParam;
+ UNREFERENCED_PARAMETER(nRemaining);
+
+ /* stop enum if canceled */
+ if(!IsWindowVisible(arg->hwndDlg)) return FALSE;
+ /* skip 'Others' section */
+ if(!lstrcmpA(upd->pszSubCategory,"Others")) return TRUE;
+
+ /* find out if already in list */
+ for(index=SendMessage(arg->hwndCombo,CB_GETCOUNT,0,0);index!=CB_ERR;--index) {
+ pszParam=(char*)SendMessage(arg->hwndCombo,CB_GETITEMDATA,index,0);
+ if((int)pszParam==CB_ERR) continue;
+ if(!lstrcmpA(upd->pszSubCategory,pszParam))
+ return TRUE; /* already there */
+ }
+ /* insert new item */
+ index=SendMessageA(arg->hwndCombo,CB_ADDSTRING,0,(LPARAM)Translate(upd->pszSubCategory));
+ if(index!=CB_ERR) {
+ SendMessage(arg->hwndCombo,CB_SETITEMDATA,index,(LPARAM)mir_strdup(upd->pszSubCategory));
+ /* select current UI language */
+ if(strstr(upd->pszSubCategory,(char*)lParam)!=NULL)
+ SendMessage(arg->hwndCombo,CB_SETCURSEL,index,0);
+ }
+ return TRUE;
+}
+
+static void PopulateComboBoxThread(struct PopulateComboBoxParams *arg)
+{
+ char szCurrentLang[64];
+
+ /* get current UI language name */
+ SendMessage(arg->hwndDlg,M_STARTANIM,0,0);
+ if(!GetLocaleInfoA(LOCALE_USER_DEFAULT,LOCALE_SENGLANGUAGE,szCurrentLang,SIZEOF(szCurrentLang)))
+ szCurrentLang[0]='\0';
+ /* enum all language sections */
+ EnumUpdates(PopulateComboBoxEnumProc,_T("category_localisation.xml"),TRUE,(WPARAM)arg,(LPARAM)szCurrentLang);
+
+ /* enable dialog */
+ SendMessage(arg->hwndDlg,M_STOPANIM,0,0);
+ EnableWindow(arg->hwndOk,TRUE);
+ /* close dialog (if canceled) */
+ if(!IsWindowVisible(arg->hwndDlg))
+ PostMessage(arg->hwndDlg,M_FINISH,(WPARAM)-1,0);
+
+ mir_free(arg);
+}
+
+static BOOL CALLBACK DownloadLangDlgProc(HWND hwndDlg,UINT msg,WPARAM wParam,LPARAM lParam)
+{
+ switch(msg) {
+ case WM_INITDIALOG:
+ { HWND hwndCombo;
+ /* init dialog */
+ hwndLangDlg=hwndDlg;
+ TranslateDialogDefault(hwndDlg);
+ SendMessage(hwndDlg,WM_SETICON,ICON_SMALL,(LPARAM)LoadSkinnedIcon(SKINICON_OTHER_MIRANDA));
+ /* init combo box */
+ hwndCombo=GetDlgItem(hwndDlg,IDC_LANGCOMBO);
+ SendMessage(hwndCombo,CB_SETLOCALE,(LCID)CallService(MS_LANGPACK_GETLOCALE,0,0),0); /* for sort order */
+ SendMessage(hwndCombo,CB_SETEXTENDEDUI,TRUE,0);
+ SendMessage(hwndCombo,CB_INITSTORAGE,32,32*16); /* speed up */
+ if(SendMessageA(hwndCombo,CB_ADDSTRING,0,(LPARAM)Translate("English (default)"))!=CB_ERR) {
+ SendMessage(hwndCombo,CB_SETCURSEL,0,0);
+ SendMessage(hwndCombo,CB_SETITEMDATA,0,(LPARAM)NULL);
+ }
+ /* enum all language sections */
+ { struct PopulateComboBoxParams *arg;
+ arg=(struct PopulateComboBoxParams *)mir_alloc(sizeof(struct PopulateComboBoxParams));
+ if(arg!=NULL) {
+ arg->hwndDlg=hwndDlg;
+ arg->hwndCombo=hwndCombo;
+ arg->hwndOk=GetDlgItem(hwndDlg,IDOK);
+ if(mir_forkthread(PopulateComboBoxThread,(void*)arg)==(DWORD)-1)
+ mir_free(arg);
+ }
+ }
+ return TRUE;
+ }
+ case WM_DESTROY:
+ { int index;
+ char *pszParam;
+ HWND hwnd;
+ /* release icon */
+ hwndLangDlg=NULL;
+ CallService(MS_SKIN2_RELEASEICON,(WPARAM)SendMessage(hwndDlg,WM_SETICON,ICON_SMALL,(LPARAM)NULL),0);
+ /* free memory (WM_DELETEITEM does not fit) */
+ hwnd=GetDlgItem(hwndDlg,IDC_LANGCOMBO);
+ for(index=SendMessage(hwnd,CB_GETCOUNT,0,0);index!=CB_ERR;--index) {
+ pszParam=(char*)SendMessage(hwnd,CB_GETITEMDATA,index,0);
+ if((int)pszParam==CB_ERR) continue;
+ SendMessage(hwnd,CB_DELETESTRING,index,0);
+ mir_free(pszParam); /* does NULL check */
+ }
+ return TRUE;
+ }
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDOK:
+ /* disable */
+ EnableWindow(GetDlgItem(hwndDlg,IDOK),FALSE);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_LANGCOMBO),FALSE);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_DOWNLOADALL),FALSE);
+ /* download */
+ { struct DownloadSelectionParams *arg;
+ arg=(struct DownloadSelectionParams*)mir_alloc(sizeof(struct DownloadSelectionParams));
+ arg->hwndDlg=hwndDlg;
+ arg->hwndCombo=GetDlgItem(hwndDlg,IDC_LANGCOMBO);
+ arg->fDownloadAll=IsDlgButtonChecked(hwndDlg,IDC_DOWNLOADALL);
+ if(arg!=NULL && mir_forkthread(DownloadSelectionThread,arg)!=(DWORD)-1)
+ return TRUE;
+ else mir_free(arg); /* does NULL check */
+ }
+ // else fall through
+ case IDCANCEL: /* this is WM_CLOSE, too */
+ if(!IsWindowEnabled(GetDlgItem(hwndDlg,IDOK)))
+ ShowWindow(hwndDlg,SW_HIDE); /* worker thread will handle this */
+ else
+ PostMessage(hwndDlg,M_FINISH,(WPARAM)-1,0);
+ return TRUE;
+ }
+ break;
+ case M_FINISH:
+ if(wParam!=-1 && IsWindowVisible(hwndDlg)) {
+ MSGBOXPARAMS mbp;
+ mbp.cbSize=sizeof(mbp);
+ mbp.hwndOwner=hwndDlg; /* we get destroyed along with parent */
+ mbp.lpszCaption=TranslateT("Help Pack Download finished");
+ if((BOOL)wParam) {
+ mbp.dwStyle=MB_ICONINFORMATION;
+ mbp.lpszText=TranslateT("The download succeeded!");
+ } else {
+ mbp.dwStyle=MB_ICONERROR;
+ mbp.lpszText=TranslateT("The download failed!\n\nThe help pack could not be downloaded or extracted.");
+ }
+ mbp.dwStyle|=MB_OK;
+ mbp.dwLanguageId=LANGIDFROMLCID((LCID)CallService(MS_LANGPACK_GETLOCALE,0,0));
+ MessageBoxIndirect(&mbp);
+ }
+ DestroyWindow(hwndDlg); /* we must be in window thread to do this */
+ return TRUE;
+ case M_STARTANIM:
+ SetTimer(hwndDlg,1,100,NULL);
+ // fall through
+ case WM_TIMER:
+ { TCHAR str[128];
+ int updateAnimFrame;
+ HWND hwnd;
+ hwnd=GetDlgItem(hwndDlg,IDC_LOADING);
+ if(msg==M_STARTANIM) updateAnimFrame=0;
+ else updateAnimFrame=GetWindowLong(hwnd,GWL_USERDATA);
+ mir_sntprintf(str,SIZEOF(str),_T("%.*s%s%.*s"),updateAnimFrame%10,_T("........."),TranslateT("downloading"),updateAnimFrame%10,_T("........."));
+ SetWindowText(hwnd,str);
+ if(++updateAnimFrame==UPDATEANIMFRAMES) updateAnimFrame=0;
+ SetWindowLong(hwnd,GWL_USERDATA,updateAnimFrame);
+ if(msg==M_STARTANIM) ShowWindow(hwnd,SW_SHOW);
+ return TRUE;
+ }
+ case WM_CTLCOLORSTATIC:
+ switch(GetDlgCtrlID((HWND)lParam)) {
+ case IDC_LOADING:
+ { COLORREF textCol,bgCol,newCol;
+ int ratio,updateAnimFrame;
+ updateAnimFrame=GetWindowLong(GetDlgItem(hwndDlg,IDC_LOADING),GWL_USERDATA);
+ textCol=GetSysColor(COLOR_BTNTEXT);
+ bgCol=GetSysColor(COLOR_3DFACE);
+ ratio=abs(UPDATEANIMFRAMES/2-updateAnimFrame)*510/UPDATEANIMFRAMES;
+ newCol=RGB(GetRValue(bgCol)+(GetRValue(textCol)-GetRValue(bgCol))*ratio/256,
+ GetGValue(bgCol)+(GetGValue(textCol)-GetGValue(bgCol))*ratio/256,
+ GetBValue(bgCol)+(GetBValue(textCol)-GetBValue(bgCol))*ratio/256);
+ SetTextColor((HDC)wParam,newCol);
+ SetBkColor((HDC)wParam,GetSysColor(COLOR_3DFACE));
+ return (BOOL)GetSysColorBrush(COLOR_3DFACE);
+ }
+ }
+ break;
+ case M_STOPANIM:
+ KillTimer(hwndDlg,1);
+ ShowWindow(GetDlgItem(hwndDlg,IDC_LOADING),SW_HIDE);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+int ServiceShowLangDialog(WPARAM wParam,LPARAM lParam)
+{
+ UNREFERENCED_PARAMETER(wParam);
+ UNREFERENCED_PARAMETER(lParam);
+ if(Miranda_Terminated()) return 2; /* after pre-shutdown */
+ if(hwndLangDlg!=NULL && IsWindowVisible(hwndLangDlg)) {
+ SetForegroundWindow(hwndLangDlg);
+ return 0;
+ }
+ /* we can't allow a parent here as our window would get destroyed alongside with it */
+ return !CreateDialog(hInst,MAKEINTRESOURCE(IDD_DOWNLOADLANG),NULL,DownloadLangDlgProc);
+}
+
+/************************* Notify Dlg *********************************/
+
+static HWND hwndNotifyDlg;
+
+struct NotifyDlgParams {
+ const TCHAR *pszLanguage;
+ const FILETIME *ftCurrentVersion;
+ const FILETIME *ftNewVersion;
+};
+
+static BOOL CALLBACK UpdateNotifyDlgProc(HWND hwndDlg,UINT msg,WPARAM wParam,LPARAM lParam)
+{
+ switch(msg) {
+ case WM_INITDIALOG:
+ { struct NotifyDlgParams *arg=(struct NotifyDlgParams*)lParam;
+ SYSTEMTIME stFileDate;
+ TCHAR szDate[128];
+ LCID locale;
+ hwndNotifyDlg=hwndDlg;
+ TranslateDialogDefault(hwndDlg);
+ /* show update */
+ SendMessage(hwndDlg,WM_SETICON,ICON_SMALL,(LPARAM)LoadSkinnedIcon(SKINICON_OTHER_MIRANDA));
+ SetDlgItemText(hwndDlg,IDC_LANGUAGE,TranslateTS(arg->pszLanguage));
+ locale=(LCID)CallService(MS_LANGPACK_GETLOCALE,0,0);
+ szDate[0]=_T('\0');
+ if(FileTimeToSystemTime(arg->ftCurrentVersion,&stFileDate))
+ GetDateFormat(locale,DATE_SHORTDATE,&stFileDate,NULL,szDate,SIZEOF(szDate));
+ SetDlgItemText(hwndDlg,IDC_CURRENTVERSION,szDate);
+ szDate[0]=_T('\0');
+ if(FileTimeToSystemTime(arg->ftNewVersion,&stFileDate))
+ GetDateFormat(locale,DATE_SHORTDATE,&stFileDate,NULL,szDate,SIZEOF(szDate));
+ SetDlgItemText(hwndDlg,IDC_NEWVERSION,szDate);
+ /* make labels use bold font */
+ { HFONT hFont;
+ LOGFONT lf;
+ hFont=(HFONT)SendDlgItemMessage(hwndDlg,IDC_NEWVERSION,WM_GETFONT,0,0);
+ if(GetObject(hFont,sizeof(lf),&lf)) {
+ lf.lfWeight=FW_BOLD;
+ hFont=CreateFontIndirect(&lf);
+ } else hFont=NULL;
+ SendDlgItemMessage(hwndDlg,IDC_NEWVERSION,WM_SETFONT,(WPARAM)hFont,0);
+ SendDlgItemMessage(hwndDlg,IDC_NEWVERSIONLABEL,WM_SETFONT,(WPARAM)hFont,0);
+ SendDlgItemMessage(hwndDlg,IDC_LANGUAGE,WM_SETFONT,(WPARAM)hFont,0);
+ SendDlgItemMessage(hwndDlg,IDC_LANGUAGELABEL,WM_SETFONT,(WPARAM)hFont,0);
+ SetWindowLong(hwndDlg,DWL_USER,(LONG)hFont);
+ }
+ return TRUE;
+ }
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDOK:
+ case IDCANCEL: /* this is WM_CLOSE, too */
+ EndDialog(hwndDlg,LOWORD(wParam));
+ return TRUE;
+ }
+ break;
+ case WM_DESTROY:
+ hwndNotifyDlg=NULL;
+ IcoLib_ReleaseIcon((HICON)SendMessage(hwndDlg,WM_SETICON,ICON_SMALL,(LPARAM)NULL));
+ return TRUE;
+ case WM_NCDESTROY:
+ { HFONT hFont;
+ hFont=(HFONT)GetWindowLong(hwndDlg,DWL_USER);
+ if(hFont!=NULL) DeleteObject(hFont);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/************************* Marked Versions ****************************/
+
+static void SetVersionMarked(WORD id,const char *pszVersion,BOOL fMarked)
+{
+ char szSetting[18];
+ wsprintfA(szSetting,"NoVerNotify_%u",id);
+ if(fMarked) DBWriteContactSettingString(NULL,"HelpPlugin",szSetting,pszVersion);
+ else DBDeleteContactSetting(NULL,"HelpPlugin",szSetting);
+}
+
+static BOOL IsVersionMarked(WORD id,const char *pszVersion)
+{
+ DBVARIANT dbv;
+ BOOL fMarked=FALSE;
+ char szSetting[18];
+ wsprintfA(szSetting,"NoVerNotify_%u",id);
+ if(!DBGetContactSettingString(NULL,"HelpPlugin",szSetting,&dbv)) {
+ fMarked=!lstrcmpA(dbv.pszVal,pszVersion);
+ mir_free(dbv.pszVal);
+ }
+ return fMarked;
+}
+
+/************************* Error Output ***************************/
+
+static void MessageBoxIndirectFree(MSGBOXPARAMSA *mbp)
+{
+ MessageBoxIndirectA(mbp);
+ mir_free((char*)mbp->lpszCaption); /* does NULL check */
+ mir_free((char*)mbp->lpszText); /* does NULL check */
+ mir_free(mbp);
+}
+
+static void ShowInfoMessage(BYTE flags,const char *pszTitle,const char *pszTextFmt,...)
+{
+ char szText[256]; /* max for systray */
+ MSGBOXPARAMSA *mbp;
+
+ va_list va;
+ va_start(va,pszTextFmt);
+ mir_vsnprintf(szText,SIZEOF(szText),pszTextFmt,va);
+ va_end(va);
+
+ if(ServiceExists(MS_CLIST_SYSTRAY_NOTIFY)) {
+ MIRANDASYSTRAYNOTIFY msn;
+ msn.cbSize=sizeof(msn);
+ msn.szProto=NULL;
+ msn.szInfoTitle=(char*)pszTitle;
+ msn.szInfo=(char*)szText;
+ msn.uTimeout=30000; /* max timeout */
+ msn.dwInfoFlags=flags;
+ if(!CallServiceSync(MS_CLIST_SYSTRAY_NOTIFY,0,(LPARAM)&msn))
+ return; /* success */
+ }
+
+ mbp=(MSGBOXPARAMSA*)mir_calloc(sizeof(*mbp));
+ if(mbp==NULL) return;
+ mbp->cbSize=sizeof(*mbp);
+ mbp->lpszCaption=mir_strdup(pszTitle);
+ mbp->lpszText=mir_strdup(szText);
+ mbp->dwStyle=MB_OK|MB_SETFOREGROUND|MB_TASKMODAL;
+ mbp->dwLanguageId=LANGIDFROMLCID((LCID)CallService(MS_LANGPACK_GETLOCALE,0,0));
+ switch(flags&NIIF_ICON_MASK) {
+ case NIIF_INFO: mbp->dwStyle|=MB_ICONINFORMATION; break;
+ case NIIF_WARNING: mbp->dwStyle|=MB_ICONWARNING; break;
+ case NIIF_ERROR: mbp->dwStyle|=MB_ICONERROR;
+ }
+ mir_forkthread(MessageBoxIndirectFree,mbp);
+}
+
+/************************* Update Check ************************************/
+
+#define MINCHECKTIME 60*60 // check no more than once an hour (seconds)
+#define REALCHECKTIME 24*60*60 // check once every 24 hours (seconds)
+#define FIRSTCHECKTIME 15 // first check 15 seconds after startup (seconds)
+
+static UINT idUpdateTimer;
+static DWORD idUpdateThread;
+
+static BOOL CALLBACK FindCurrentPackEnumProc(HELPPACK_INFO *pack,WPARAM wParam,LPARAM lParam)
+{
+ UPDATE_INFO *upd=(UPDATE_INFO*)wParam;
+ if(!lstrcmpiA(upd->pszTitle,pack->szFLName)) {
+ CopyMemory((HELPPACK_INFO*)lParam,pack,sizeof(HELPPACK_INFO));
+ return FALSE; /* stop if found */
+ }
+ return TRUE;
+}
+
+static BOOL CALLBACK FindLatestUpdEnumProc(UPDATE_INFO *upd,WORD nRemaining,WPARAM wParam,LPARAM lParam)
+{
+ UPDATE_INFO *updFind=(UPDATE_INFO*)lParam;
+ UNREFERENCED_PARAMETER(nRemaining);
+
+ /* is there any later item? */
+ if(!lstrcmpiA(upd->pszTitle,updFind->pszTitle))
+ if(CompareFileTime(&upd->ftFileDate,&updFind->ftFileDate)>0) {
+ *(BOOL*)wParam=TRUE;
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static BOOL CALLBACK UpdateCheckEnumProc(UPDATE_INFO *upd,WORD nRemaining,WPARAM wParam,LPARAM lParam)
+{
+ HELPPACK_INFO pack;
+ UNREFERENCED_PARAMETER(nRemaining);
+ UNREFERENCED_PARAMETER(wParam);
+ UNREFERENCED_PARAMETER(lParam);
+ /* search if installed */
+ pack.szFLName[0]='\0';
+ EnumPacks(FindCurrentPackEnumProc,_T("helppack_*.txt"),"Miranda Help Pack Version 1",(WPARAM)upd,(LPARAM)&pack);
+ if(Miranda_Terminated()) return FALSE;
+ if(pack.szVersion[0] && pack.szFLName[0]) {
+ BOOL fHasNewerWithSameName;
+ Netlib_Logf(hNetlibUser,TCHAR_STR_PARAM" (name:\"%s\", ver:%s)",pack.szFileName,pack.szFLName,pack.szVersion);
+ /* skip earlier items with that same name (if any) */
+ fHasNewerWithSameName=FALSE; /* tentatively */
+ EnumUpdates(FindLatestUpdEnumProc,_T("category_localisation.xml"),FALSE,(WPARAM)&fHasNewerWithSameName,(LPARAM)upd);
+ if(Miranda_Terminated()) return FALSE;
+ if(fHasNewerWithSameName)
+ Netlib_Logf(hNetlibUser,"Skip old duplicate (name:\"%s\", ver:%s, cat:\"%s\")",upd->pszTitle,upd->pszVersion,upd->pszSubCategory);
+ /* cheap version check, allows for literals */
+ else if(lstrcmpiA(pack.szVersion,upd->pszVersion)) {
+ Netlib_Logf(hNetlibUser,"New version found (name:\"%s\", ver:%s, cat:\"%s\")",upd->pszTitle,upd->pszVersion,upd->pszSubCategory);
+ /* do not notify again when canceled once */
+ if(!IsVersionMarked(upd->id,upd->pszVersion)) {
+ /* show notify dlg */
+ struct NotifyDlgParams arg;
+ BOOL fSuccess=FALSE;
+ arg.pszLanguage=pack.szLanguage;
+ arg.ftCurrentVersion=&pack.ftFileDate;
+ arg.ftNewVersion=&upd->ftFileDate;
+ if(Miranda_Terminated()) return FALSE;
+ if(DialogBoxParam(hInst,MAKEINTRESOURCE(IDD_UPDATENOTIFY),0,UpdateNotifyDlgProc,(LPARAM)&arg)==IDOK) {
+ fSuccess=DownloadPack(upd->id,_T("helppack_*.txt"),pack.flags&HPF_ENABLED,pack.szFileName,"Miranda Help Pack Version 1",upd->pszTitle,upd->pszVersion);
+ if(fSuccess) ShowInfoMessage(NIIF_INFO,Translate("Help Pack Update succeeded"),Translate("The help pack \"%s\" has been sucessfully downloaded and installed."),TranslateTS(pack.szLanguage));
+ else ShowInfoMessage(NIIF_ERROR,Translate("Help Pack Update failed"),Translate("The help pack \"%s\" could not be downloaded or extracted."),TranslateTS(pack.szLanguage));
+ }
+ /* delete/add marked setting */
+ SetVersionMarked(upd->id,upd->pszVersion,!fSuccess);
+ }
+ else Netlib_Logf(hNetlibUser,"Already notified");
+ }
+ else Netlib_Logf(hNetlibUser,"Same version found (name:\"%s\", ver:%s, cat:\"%s\")",upd->pszTitle,upd->pszVersion,upd->pszSubCategory);
+ }
+ return !Miranda_Terminated();
+}
+
+static void UpdateCheckThread(void *unused)
+{
+ UNREFERENCED_PARAMETER(unused);
+ /* only if any pack installed */
+ if(EnumPacks(NULL,_T("helppack_*.txt"),"Miranda Help Pack Version 1",0,0))
+ EnumUpdates(UpdateCheckEnumProc,_T("category_localisation.xml"),TRUE,0,0);
+ else Netlib_Logf(hNetlibUser,"No "TCHAR_STR_PARAM" file present",_T("helppack_*.txt"));
+}
+
+static void CALLBACK UpdateCheckTimer(HWND hwnd,UINT msg,UINT idTimer,DWORD dwTime)
+{
+ UNREFERENCED_PARAMETER(msg);
+ UNREFERENCED_PARAMETER(dwTime);
+ if(idUpdateThread==-1 && DBGetContactSettingByte(NULL,"HelpPlugin","EnableHelpUpdates",SETTING_ENABLEHELPUPDATES_DEFAULT)) {
+ Netlib_Logf(hNetlibUser,"Running update check");
+ idUpdateThread=mir_forkthread(UpdateCheckThread,(void*)dwTime);
+ }
+ idUpdateTimer=SetTimer(hwnd,idTimer,1000*MINCHECKTIME,UpdateCheckTimer);
+}
+
+/************************* Misc ***************************************/
+
+static int UpdateModulesLoaded(WPARAM wParam,LPARAM lParam)
+{
+ NETLIBUSER nlu;
+ UNREFERENCED_PARAMETER(wParam);
+ UNREFERENCED_PARAMETER(lParam);
+ /* Shared */
+ /* netlib module is not available before this hook */
+ ZeroMemory(&nlu,sizeof(nlu));
+ nlu.cbSize=sizeof(nlu);
+ nlu.flags=NUF_OUTGOING|NUF_HTTPCONNS;
+ nlu.szSettingsModule="HelpPlugin";
+ nlu.szDescriptiveName=Translate("Help Pack Update HTTP connection");
+ hNetlibUser=(HANDLE)CallService(MS_NETLIB_REGISTERUSER,0,(LPARAM)&nlu);
+ /* Update Check */
+ idUpdateThread=(DWORD)-1;
+ idUpdateTimer=SetTimer(NULL,idUpdateTimer,1000*FIRSTCHECKTIME,UpdateCheckTimer);
+ /* First Run */
+// disabled temporarily
+// if(!DBGetContactSettingByte(NULL,"HelpPlugin","FirstRun",0))
+// if(!ServiceShowLangDialog(0,0))
+// DBWriteContactSettingByte(NULL,"HelpPlugin","FirstRun",1);
+ return 0;
+}
+
+static int UpdatePreShutdown(WPARAM wParam,LPARAM lParam)
+{
+ UNREFERENCED_PARAMETER(wParam);
+ UNREFERENCED_PARAMETER(lParam);
+ /* Notify Dlg (let the notify thread go unwind) */
+ if(hwndNotifyDlg!=NULL) SendMessage(hwndNotifyDlg,WM_CLOSE,0,0);
+ /* Lang Dlg (stop any running download enum) */
+ if(hwndLangDlg!=NULL) SendMessage(hwndLangDlg,WM_CLOSE,0,0);
+ /* Update Check (stop timer messages) */
+ if(idUpdateTimer) KillTimer(NULL,idUpdateTimer);
+ return 0;
+}
+
+void InitUpdate(void)
+{
+ /* Update Check */
+ idUpdateTimer=0;
+ /* Notify Dlg */
+ hwndNotifyDlg=NULL;
+ /* Lang Dlg */
+ hwndLangDlg=NULL;
+ hServiceShowLangDialog=CreateServiceFunction(MS_HELP_SHOWLANGDIALOG,ServiceShowLangDialog);
+ /* Misc */
+ hHookModulesLoaded=HookEvent(ME_SYSTEM_MODULESLOADED,UpdateModulesLoaded);
+ hHookPreShutdown=HookEvent(ME_SYSTEM_PRESHUTDOWN,UpdatePreShutdown);
+}
+
+void UninitUpdate(void)
+{
+ /* Misc */
+ UnhookEvent(hHookModulesLoaded);
+ UnhookEvent(hHookPreShutdown);
+ /* Lang Dlg */
+ DestroyServiceFunction(hServiceShowLangDialog);
+} \ No newline at end of file
diff --git a/Help/utils.c b/Help/utils.c
new file mode 100644
index 0000000..a6fb7a0
--- /dev/null
+++ b/Help/utils.c
@@ -0,0 +1,399 @@
+/*
+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 <tchar.h>
+#include <stdarg.h>
+#include <stdio.h>
+#define _WIN32_WINNT 0x0500
+#define __RPCASYNC_H__ /* header shows warnings in VS6 */
+#include <windows.h>
+#include <win2k.h>
+#define MIRANDA_VER 0x0600
+#include <newpluginapi.h>
+#include <m_utils.h>
+#include <m_system.h>
+#include <m_netlib.h>
+#include "help.h"
+
+#pragma warning(disable:4201) /* nonstandard extension used : nameless struct/union */
+#include <commctrl.h>
+#pragma warning(default:4201) /* nonstandard extension used : nameless struct/union */
+#include <richedit.h>
+#include <m_clc.h>
+#include <m_button.h>
+
+#define CHARBUFFER_ALLOCSTEP 512 // allocated buffer increase in bytes
+
+#ifdef EDITOR
+extern const TCHAR *szControlTypeNames[]={
+ _T("Unknown"),_T("Dialog Box"),_T("Button"),_T("Check Box"),_T("Radio Button"),
+ _T("Text"),_T("Image"),_T("Edit Box"),_T("Group Box"),_T("Combo Box"),
+ _T("List Box"),_T("Spin Edit Box"),_T("Progress Bar"),_T("Slider"),_T("List View"),
+ _T("Tree View"),_T("Date/Time Picker"),_T("IP Address"),_T("Status Bar"),_T("Hyperlink"),
+ _T("Contact List"),_T("Scroll Bar"),_T("Animation"),_T("Hotkey"),_T("Tabs"),
+ _T("Colour Picker"),_T("Tool Bar"),_T("Combo Edit Box"),_T("Size Grip")};
+#endif
+
+int GetControlType(HWND hwndCtl)
+{
+ TCHAR szClassName[32];
+ DWORD style;
+
+ if(GetClassLong(hwndCtl,GCW_ATOM)==32770)
+ return CTLTYPE_DIALOG;
+ if(!GetClassName(hwndCtl,szClassName,SIZEOF(szClassName))) return CTLTYPE_UNKNOWN;
+ if(!lstrcmpi(szClassName,_T("MDIClient")))
+ return CTLTYPE_DIALOG;
+ else if(!lstrcmpi(szClassName,_T("Static"))) {
+ if(GetClassName(GetParent(hwndCtl),szClassName,SIZEOF(szClassName)) && !lstrcmpi(szClassName,_T("ComboBox")) || !lstrcmpi(szClassName,WC_COMBOBOXEX))
+ return CTLTYPE_COMBO;
+ style=GetWindowLong(hwndCtl,GWL_STYLE);
+ switch(style&SS_TYPEMASK) {
+ case SS_BITMAP:
+ case SS_BLACKFRAME:
+ case SS_BLACKRECT:
+ case SS_ENHMETAFILE:
+ case SS_ETCHEDFRAME:
+ case SS_ETCHEDHORZ:
+ case SS_ETCHEDVERT:
+ case SS_WHITEFRAME:
+ case SS_WHITERECT:
+ case SS_GRAYFRAME:
+ case SS_GRAYRECT:
+ case SS_ICON:
+ case SS_OWNERDRAW:
+ return CTLTYPE_IMAGE;
+ }
+ return CTLTYPE_TEXT;
+ }
+ else if(GetClassLong(hwndCtl,GCW_ATOM)==32772) // WinNT/2000/XP: icon titles
+ return CTLTYPE_IMAGE; // class="#32772"
+ else if(!lstrcmpi(szClassName,_T("Button"))) {
+ style=GetWindowLong(hwndCtl,GWL_STYLE);
+ switch(style&0x24) {
+ case BS_CHECKBOX:
+ case BS_AUTOCHECKBOX:
+ case BS_3STATE:
+ case BS_AUTO3STATE:
+ if(style&BS_PUSHLIKE) break;
+ return CTLTYPE_CHECKBOX;
+ case BS_RADIOBUTTON:
+ case BS_AUTORADIOBUTTON:
+ if(style&BS_PUSHLIKE) break;
+ return CTLTYPE_RADIO;
+ case BS_GROUPBOX:
+ return CTLTYPE_GROUP;
+ }
+ return CTLTYPE_BUTTON;
+ }
+ else if(!lstrcmpi(szClassName,MIRANDABUTTONCLASS)) return CTLTYPE_BUTTON;
+ else if(!lstrcmpi(szClassName,_T("Edit"))) {
+ if(GetClassName(GetParent(hwndCtl),szClassName,SIZEOF(szClassName)) && !lstrcmpi(szClassName,_T("ComboBox")))
+ return CTLTYPE_COMBO;
+ if(GetClassName(GetWindow(hwndCtl,GW_HWNDNEXT),szClassName,SIZEOF(szClassName)) && !lstrcmpi(szClassName,UPDOWN_CLASS))
+ if((HWND)SendMessage(GetWindow(hwndCtl,GW_HWNDNEXT),UDM_GETBUDDY,0,0)==hwndCtl)
+ return CTLTYPE_SPINEDIT;
+ return CTLTYPE_EDIT;
+ }
+ else if(!_tcsnicmp(szClassName,_T("RichEdit"),8)) return CTLTYPE_EDIT; // RICHEDIT,RichEdit20A,RichEdit20W,RichEdit50W and future versions
+ else if(!lstrcmpi(szClassName,_T("ListBox"))) {
+ style=GetWindowLong(hwndCtl,GWL_STYLE);
+ if(style&LBS_COMBOBOX) return CTLTYPE_COMBO;
+ return CTLTYPE_LIST;
+ } else if(!lstrcmpi(szClassName,_T("ComboLBox")) || !lstrcmpi(szClassName,_T("ComboBox")) || !lstrcmpi(szClassName,WC_COMBOBOXEX))
+ return CTLTYPE_COMBO;
+ else if(!lstrcmpi(szClassName,_T("ScrollBar"))) {
+ style=GetWindowLong(hwndCtl,GWL_STYLE);
+ if(style&SBS_SIZEBOX) return CTLTYPE_SIZEGRIP;
+ return CTLTYPE_SCROLL;
+ }
+ else if(!lstrcmpi(szClassName,WC_PAGESCROLLER)) return CTLTYPE_SCROLL;
+ else if(!lstrcmpi(szClassName,UPDOWN_CLASS)) {
+ if(GetClassName((HWND)SendMessage(hwndCtl,UDM_GETBUDDY,0,0),szClassName,SIZEOF(szClassName)) && !lstrcmpi(szClassName,_T("Edit")))
+ return CTLTYPE_SPINEDIT;
+ return CTLTYPE_SCROLL;
+ }
+ else if(!lstrcmpi(szClassName,PROGRESS_CLASS)) return CTLTYPE_PROGRESS;
+ else if(!lstrcmpi(szClassName,TRACKBAR_CLASS)) return CTLTYPE_SLIDER;
+ else if(!lstrcmpi(szClassName,WC_LISTVIEW) || !lstrcmpi(szClassName,WC_HEADER))
+ return CTLTYPE_LISTVIEW;
+ else if(!lstrcmpi(szClassName,WC_TREEVIEW)) return CTLTYPE_TREEVIEW;
+ else if(!lstrcmpi(szClassName,DATETIMEPICK_CLASS) || !lstrcmpi(szClassName,MONTHCAL_CLASS))
+ return CTLTYPE_DATETIME;
+ else if(!lstrcmpi(szClassName,WC_IPADDRESS)) return CTLTYPE_IP;
+ else if(!lstrcmpi(szClassName,STATUSCLASSNAME)) return CTLTYPE_STATUSBAR;
+ else if(!lstrcmpi(szClassName,CLISTCONTROL_CLASS)) return CTLTYPE_CLC;
+ else if(!lstrcmpi(szClassName,WNDCLASS_HYPERLINK) || !lstrcmpi(szClassName,_T("SysLink")))
+ return CTLTYPE_HYPERLINK;
+ else if(!lstrcmpi(szClassName,ANIMATE_CLASS)) return CTLTYPE_ANIMATION;
+ else if(!lstrcmpi(szClassName,HOTKEY_CLASS)) return CTLTYPE_HOTKEY;
+ else if(!lstrcmpi(szClassName,WC_TABCONTROL)) return CTLTYPE_TABS;
+ else if(!lstrcmpi(szClassName,WNDCLASS_COLOURPICKER)) return CTLTYPE_COLOUR;
+ else if(!lstrcmpi(szClassName,TOOLBARCLASSNAME) || !lstrcmpi(szClassName,REBARCLASSNAME))
+ return CTLTYPE_TOOLBAR;
+ switch(SendMessage(hwndCtl,WM_GETDLGCODE,0,(LPARAM)NULL)&0x2070) {
+ case DLGC_RADIOBUTTON:
+ return CTLTYPE_RADIO;
+ case DLGC_DEFPUSHBUTTON:
+ case DLGC_UNDEFPUSHBUTTON:
+ case DLGC_BUTTON:
+ return CTLTYPE_BUTTON;
+ }
+ hwndCtl=GetWindow(hwndCtl,GW_CHILD); // check for owner-extended control
+ if(hwndCtl!=NULL) return GetControlType(hwndCtl);
+ return CTLTYPE_UNKNOWN;
+}
+
+HWND GetControlDialog(HWND hwndCtl)
+{
+ TCHAR szClassName[32];
+ while(hwndCtl!=NULL) {
+ if(GetClassLong(hwndCtl,GCW_ATOM)==32770)
+ return hwndCtl;
+ if(GetClassName(hwndCtl,szClassName,SIZEOF(szClassName)))
+ if(!lstrcmpi(szClassName,_T("MDIClient")))
+ return hwndCtl;
+ hwndCtl=GetParent(hwndCtl);
+ }
+ return hwndCtl;
+}
+
+// never fails
+int GetControlTitle(HWND hwndCtl,TCHAR *pszTitle,int cchTitle)
+{
+ TCHAR *p;
+ int res=0;
+ if(cchTitle) pszTitle[0]=_T('\0');
+ switch(GetControlType(hwndCtl)) {
+ case CTLTYPE_DIALOG:
+ case CTLTYPE_BUTTON:
+ case CTLTYPE_CHECKBOX:
+ case CTLTYPE_RADIO:
+ case CTLTYPE_GROUP:
+ case CTLTYPE_TEXT:
+ case CTLTYPE_HYPERLINK:
+ res=GetWindowText(hwndCtl,pszTitle,cchTitle);
+ }
+ hwndCtl=GetWindow(hwndCtl,GW_HWNDPREV);
+ if(hwndCtl)
+ switch(GetControlType(hwndCtl)) {
+ case CTLTYPE_TEXT:
+ case CTLTYPE_GROUP:
+ res=GetWindowText(hwndCtl,pszTitle,cchTitle);
+ }
+ if(res)
+ for(p=pszTitle;*p!=0;p++) {
+ // strip-off ampersand (&) prefix character
+ if(*p==_T('&') && *(p+1)!=_T('&')) {
+ MoveMemory(p,p+1,(lstrlen(p+1)+1)*sizeof(TCHAR));
+ res--;
+ if(*(p+1)==0) break;
+ }
+ // strip-off last ':'
+ if(*p==_T(':') && *(p+1)==0) {
+ *p=0;
+ res--;
+ break;
+ }
+ }
+ return res;
+}
+
+// mir_free() the return value
+char *GetControlModuleName(HWND hwndCtl)
+{
+ char szModule[512],szMainModule[512];
+ char *pszFile,*buf;
+
+ if(!GetModuleFileNameA(NULL,szMainModule,sizeof(szMainModule)))
+ return NULL;
+ buf=strrchr(szMainModule,'\\');
+ if(buf!=NULL)
+ *buf='\0';
+ else buf=szMainModule;
+
+ do {
+ if(!GetModuleFileNameA((HINSTANCE)GetWindowLong(hwndCtl,GWL_HINSTANCE),szModule,sizeof(szModule)))
+ return NULL;
+ pszFile=strrchr(szModule,'\\');
+ if(pszFile!=NULL) {
+ *pszFile='\0';
+ pszFile++;
+ } else pszFile=szModule;
+ if(lstrlenA(szModule)>lstrlenA(szMainModule))
+ szModule[lstrlenA(szMainModule)]='\0';
+ if(!lstrcmpiA(szModule,szMainModule)) break; // found miranda module
+ hwndCtl=GetParent(hwndCtl);
+ } while(hwndCtl!=NULL);
+
+ buf=strrchr(pszFile,'.');
+ if(buf!=NULL) *buf++='\0';
+ return mir_strdup(pszFile);
+}
+
+
+struct CreateControlIdData {
+ int id;
+ HWND hwndCtl;
+};
+
+static BOOL CALLBACK CreateCtlIdEnumProc(HWND hwnd,LPARAM lParam)
+{
+ struct CreateControlIdData* ccid=(struct CreateControlIdData*)lParam;
+ TCHAR szClassName[32];
+ if(GetClassLong(hwnd,GCW_ATOM)==32770) // class="#32770"
+ return TRUE;
+ if(GetClassName(hwnd,szClassName,SIZEOF(szClassName)))
+ if(!lstrcmpi(szClassName,_T("MDIClient")))
+ return TRUE;
+ if(GetWindowLong(hwnd,GWL_ID)<=0 || GetWindowLong(hwnd,GWL_ID)==0xFFFF)
+ ccid->id--;
+ if(hwnd==ccid->hwndCtl) ccid->hwndCtl=NULL;
+ return ccid->hwndCtl!=NULL;
+}
+
+int GetControlID(HWND hwndCtl)
+{
+ struct CreateControlIdData ccid;
+ TCHAR szClassName[32];
+
+ // obey context ID when set (rarely)
+ ccid.id=GetWindowContextHelpId(hwndCtl);
+ if(ccid.id!=0) return ccid.id;
+
+ if(GetClassName(hwndCtl,szClassName,SIZEOF(szClassName))) {
+ if(!lstrcmpi(szClassName,UPDOWN_CLASS)) { // handle spinner controls as a whole
+ DWORD style;
+ HWND hwndBuddy;
+ style=GetWindowLong(hwndCtl,GWL_STYLE);
+ if(style&UDS_ALIGNRIGHT || style&UDS_ALIGNLEFT) {
+ hwndBuddy=(HWND)SendMessage(hwndCtl,UDM_GETBUDDY,0,0);
+ if(hwndBuddy!=NULL) hwndCtl=hwndBuddy;
+ }
+ } else if(GetClassLong(hwndCtl,GCW_ATOM)==32770 || !lstrcmpi(szClassName,_T("MDIClient")))
+ return 0; // ensure this is always unset
+ }
+ ccid.id=GetWindowLong(hwndCtl,GWL_ID);
+ if(ccid.id<=0 || ccid.id==0xFFFF) {
+ ccid.id=-1;
+ ccid.hwndCtl=hwndCtl;
+ EnumChildWindows(GetParent(hwndCtl),CreateCtlIdEnumProc,(LPARAM)&ccid);
+ if(ccid.hwndCtl!=NULL) return -1;
+ }
+ return ccid.id;
+}
+
+// mir_free() the return value
+static char *Base64Encode(PBYTE pBuf,int cbBuf)
+{
+ NETLIBBASE64 nlb64;
+ nlb64.pbDecoded=pBuf;
+ nlb64.cbDecoded=cbBuf;
+ nlb64.cchEncoded=Netlib_GetBase64EncodedBufferSize(nlb64.cbDecoded);
+ nlb64.pszEncoded=(char*)mir_alloc(nlb64.cchEncoded);
+ if(nlb64.pszEncoded==NULL || !CallService(MS_NETLIB_BASE64ENCODE,0,(LPARAM)&nlb64)) {
+ mir_free(nlb64.pszEncoded); /* does NULL check */
+ return NULL;
+ }
+ return nlb64.pszEncoded;
+}
+
+struct CreateDialogIdBinaryData {
+ int alloced,count;
+ PBYTE buf;
+ HWND hwndParent;
+};
+
+static BOOL CALLBACK CreateDlgIdBinEnumProc(HWND hwnd,LPARAM lParam)
+{
+ struct CreateDialogIdBinaryData *cdib=(struct CreateDialogIdBinaryData*)lParam;
+ int type;
+
+ if(GetParent(hwnd)!=cdib->hwndParent) return TRUE;
+ type=GetControlType(hwnd);
+ if(type==CTLTYPE_DIALOG || type==CTLTYPE_TEXT || type==CTLTYPE_GROUP) return TRUE;
+ if(cdib->count+3>cdib->alloced) {
+ PBYTE buf2;
+ buf2=(PBYTE)mir_realloc(cdib->buf,cdib->alloced+32);
+ if(buf2==NULL) return FALSE;
+ cdib->alloced+=32;
+ cdib->buf=buf2;
+ }
+ cdib->buf[cdib->count]=(BYTE)type;
+ *(PWORD)(cdib->buf+cdib->count+1)=(WORD)GetWindowLong(hwnd,GWL_ID);
+ cdib->count+=3;
+ return TRUE;
+}
+
+// mir_free() the return value
+char *CreateDialogIdString(HWND hwndDlg)
+{
+ struct CreateDialogIdBinaryData cdib;
+ char *szRet;
+
+ ZeroMemory(&cdib, sizeof(cdib));
+ if(hwndDlg==NULL) return NULL;
+ cdib.hwndParent=hwndDlg;
+ EnumChildWindows(hwndDlg,CreateDlgIdBinEnumProc,(LPARAM)&cdib);
+ if(cdib.buf==NULL) return NULL;
+ szRet=Base64Encode(cdib.buf,cdib.count);
+ mir_free(cdib.buf);
+ return szRet;
+}
+
+
+void AppendCharToCharBuffer(struct ResizableCharBuffer *rcb,char c)
+{
+ if(rcb->cbAlloced<=rcb->iEnd+1) {
+ char* buf=(char*)mir_realloc(rcb->sz,(rcb->cbAlloced+CHARBUFFER_ALLOCSTEP));
+ if(buf==NULL) return;
+ rcb->sz=buf;
+ rcb->cbAlloced+=CHARBUFFER_ALLOCSTEP;
+ }
+ rcb->sz[rcb->iEnd++]=c;
+ rcb->sz[rcb->iEnd]='\0';
+}
+
+void AppendToCharBuffer(struct ResizableCharBuffer *rcb,const char *fmt,...)
+{
+ va_list va;
+ int charsDone;
+ char *buf;
+
+ if(rcb->cbAlloced==0) {
+ buf=(char*)mir_alloc(CHARBUFFER_ALLOCSTEP);
+ if(buf==NULL) return;
+ rcb->sz=buf;
+ rcb->cbAlloced=CHARBUFFER_ALLOCSTEP;
+ }
+ va_start(va,fmt);
+ for(;;) {
+ charsDone=mir_vsnprintf(rcb->sz+rcb->iEnd,rcb->cbAlloced-rcb->iEnd,fmt,va);
+ if(charsDone>=0) break; // returns -1 when buffer not large enough
+ buf=(char*)mir_realloc(rcb->sz,rcb->cbAlloced+CHARBUFFER_ALLOCSTEP);
+ if(buf==NULL) {
+ charsDone=0;
+ break;
+ }
+ rcb->sz=buf;
+ rcb->cbAlloced+=CHARBUFFER_ALLOCSTEP;
+ }
+ va_end(va);
+ rcb->iEnd+=charsDone;
+}
diff --git a/Help/version.h b/Help/version.h
new file mode 100644
index 0000000..32254d4
--- /dev/null
+++ b/Help/version.h
@@ -0,0 +1,40 @@
+/*
+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.
+*/
+
+#define NEEDED_MIRANDA_VERSION PLUGIN_MAKE_VERSION(0,6,0,0)
+#define NEEDED_MIRANDA_VERSION_STR "0.6"
+#define PLUGIN_VERSION PLUGIN_MAKE_VERSION(0,2,1,2)
+#define FILE_VERSION 0,2,1,2
+
+#ifdef _DEBUG
+ #define FILE_VERSION_STR "0.2.1.3 alpha"
+ #define USERAGENT_VERSION "0.2.1.3 (alpha)"
+#else
+ #define FILE_VERSION_STR "0.2.1.2"
+ #define USERAGENT_VERSION "0.2.1.2"
+#endif
+
+#define PLUGIN_EMAIL "hrathh users.sourceforge.net"
+#define PLUGIN_EMAIL_ATT_POS 7 /* position of the @-sign in the email adress above */
+
+#ifdef _UNICODE
+ #define PLUGIN_WEBSITE "http://addons.miranda-im.org/details.php?action=viewfile&id=3475"
+#else
+ #define PLUGIN_WEBSITE "http://addons.miranda-im.org/details.php?action=viewfile&id=3474"
+#endif
diff --git a/Help/version.rc b/Help/version.rc
new file mode 100644
index 0000000..5568808
--- /dev/null
+++ b/Help/version.rc
@@ -0,0 +1,51 @@
+#ifndef _MAC
+
+#include "version.h"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION FILE_VERSION
+ PRODUCTVERSION FILE_VERSION
+ FILEFLAGSMASK 0x0L
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "000004b0"
+ BEGIN
+ VALUE "Comments", "Licensed under the terms of the GNU General Public License"
+ VALUE "FileDescription", "Help Plugin for Miranda IM"
+ VALUE "FileVersion", FILE_VERSION_STR
+#ifdef _UNICODE
+ VALUE "InternalName", "HelpPlugin (Unicode)"
+#else
+ VALUE "InternalName", "HelpPlugin"
+#endif
+ VALUE "LegalCopyright", "Copyright © Richard Hughes, H. Herkenrath"
+ VALUE "OriginalFilename", "help.dll"
+ VALUE "ProductName", "Help"
+ VALUE "ProductVersion", FILE_VERSION_STR
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x0, 1200
+ END
+END
+
+#endif // !_MAC
+
+
+
+