summaryrefslogtreecommitdiff
path: root/src/modules/utils
diff options
context:
space:
mode:
authorVadim Dashevskiy <watcherhd@gmail.com>2012-05-15 10:38:20 +0000
committerVadim Dashevskiy <watcherhd@gmail.com>2012-05-15 10:38:20 +0000
commit48540940b6c28bb4378abfeb500ec45a625b37b6 (patch)
tree2ef294c0763e802f91d868bdef4229b6868527de /src/modules/utils
parent5c350913f011e119127baeb32a6aedeb4f0d33bc (diff)
initial commit
git-svn-id: http://svn.miranda-ng.org/main/trunk@2 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'src/modules/utils')
-rw-r--r--src/modules/utils/bmpfilter.cpp242
-rw-r--r--src/modules/utils/colourpicker.cpp107
-rw-r--r--src/modules/utils/hyperlink.cpp274
-rw-r--r--src/modules/utils/imgconv.cpp152
-rw-r--r--src/modules/utils/md5.cpp374
-rw-r--r--src/modules/utils/openurl.cpp228
-rw-r--r--src/modules/utils/path.cpp600
-rw-r--r--src/modules/utils/resizer.cpp152
-rw-r--r--src/modules/utils/sha1.cpp175
-rw-r--r--src/modules/utils/timeutils.cpp277
-rw-r--r--src/modules/utils/timezones.cpp662
-rw-r--r--src/modules/utils/utf.cpp413
-rw-r--r--src/modules/utils/utils.cpp587
-rw-r--r--src/modules/utils/windowlist.cpp101
14 files changed, 4344 insertions, 0 deletions
diff --git a/src/modules/utils/bmpfilter.cpp b/src/modules/utils/bmpfilter.cpp
new file mode 100644
index 0000000000..6f92eba126
--- /dev/null
+++ b/src/modules/utils/bmpfilter.cpp
@@ -0,0 +1,242 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2009 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#include "commonheaders.h"
+#include <olectl.h>
+
+#include "m_png.h"
+#include "m_imgsrvc.h"
+
+static INT_PTR sttBitmapLoader( const TCHAR* ptszFileName )
+{
+ IPicture *pic;
+ HBITMAP hBmp,hBmpCopy;
+ HBITMAP hOldBitmap, hOldBitmap2;
+ BITMAP bmpInfo;
+ HDC hdc,hdcMem1,hdcMem2;
+ short picType;
+
+ TCHAR szFilename[MAX_PATH];
+ if ( !pathToAbsoluteT(ptszFileName, szFilename, NULL ))
+ mir_sntprintf(szFilename, SIZEOF(szFilename), _T("%s"), ptszFileName);
+
+ int filenameLen = lstrlen(szFilename);
+ if ( filenameLen > 4 ) {
+ TCHAR* pszExt = szFilename + filenameLen - 4;
+
+ if ( ServiceExists( MS_IMG_LOAD ))
+ return CallService( MS_IMG_LOAD, (WPARAM)szFilename, IMGL_TCHAR );
+
+ if ( !lstrcmpi( pszExt, _T(".bmp")) || !lstrcmpi( pszExt, _T(".rle"))) {
+ //LoadImage can do this much faster
+ return (INT_PTR)LoadImage( hMirandaInst, szFilename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
+ }
+
+ if ( !lstrcmpi( pszExt, _T(".png"))) {
+ HANDLE hFile, hMap = NULL;
+ BYTE* ppMap = NULL;
+ INT_PTR cbFileSize = 0;
+ BITMAPINFOHEADER* pDib;
+ BYTE* pDibBits;
+
+ if ( !ServiceExists( MS_PNG2DIB )) {
+ MessageBox( NULL, TranslateT( "You need an image services plugin to process PNG images." ), TranslateT( "Error" ), MB_OK );
+ return 0;
+ }
+
+ if (( hFile = CreateFile( szFilename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL )) != INVALID_HANDLE_VALUE )
+ if (( hMap = CreateFileMapping( hFile, NULL, PAGE_READONLY, 0, 0, NULL )) != NULL )
+ if (( ppMap = ( BYTE* )MapViewOfFile( hMap, FILE_MAP_READ, 0, 0, 0 )) != NULL )
+ cbFileSize = GetFileSize( hFile, NULL );
+
+ if ( cbFileSize != 0 ) {
+ PNG2DIB param;
+ param.pSource = ppMap;
+ param.cbSourceSize = cbFileSize;
+ param.pResult = &pDib;
+ if ( CallService( MS_PNG2DIB, 0, ( LPARAM )&param )) {
+ pDibBits = ( BYTE* )( pDib+1 );
+ HDC sDC = GetDC( NULL );
+ HBITMAP hBitmap = CreateDIBitmap( sDC, pDib, CBM_INIT, pDibBits, ( BITMAPINFO* )pDib, DIB_PAL_COLORS );
+ SelectObject( sDC, hBitmap );
+ ReleaseDC( NULL, sDC );
+ GlobalFree( pDib );
+ cbFileSize = (INT_PTR)hBitmap;
+ }
+ else cbFileSize = 0;
+ }
+
+ if ( ppMap != NULL ) UnmapViewOfFile( ppMap );
+ if ( hMap != NULL ) CloseHandle( hMap );
+ if ( hFile != NULL ) CloseHandle( hFile );
+
+ return (INT_PTR)cbFileSize;
+ } }
+
+ if (S_OK != OleLoadPicturePath( LPOLESTR(( const wchar_t* )StrConvU(szFilename)), NULL, 0, 0, IID_IPicture, (PVOID*)&pic ))
+ return 0;
+
+ pic->get_Type(&picType);
+ if (picType!=PICTYPE_BITMAP) {
+ pic->Release();
+ return 0;
+ }
+ OLE_HANDLE hOleBmp;
+ pic->get_Handle(&hOleBmp);
+ hBmp = (HBITMAP)hOleBmp;
+ GetObject(hBmp,sizeof(bmpInfo),&bmpInfo);
+
+ //need to copy bitmap so we can free the IPicture
+ hdc=GetDC(NULL);
+ hdcMem1=CreateCompatibleDC(hdc);
+ hdcMem2=CreateCompatibleDC(hdc);
+ hOldBitmap=( HBITMAP )SelectObject(hdcMem1,hBmp);
+ hBmpCopy=CreateCompatibleBitmap(hdcMem1,bmpInfo.bmWidth,bmpInfo.bmHeight);
+ hOldBitmap2=( HBITMAP )SelectObject(hdcMem2,hBmpCopy);
+ BitBlt(hdcMem2,0,0,bmpInfo.bmWidth,bmpInfo.bmHeight,hdcMem1,0,0,SRCCOPY);
+ SelectObject(hdcMem1,hOldBitmap);
+ SelectObject(hdcMem2,hOldBitmap2);
+ DeleteDC(hdcMem2);
+ DeleteDC(hdcMem1);
+ ReleaseDC(NULL,hdc);
+
+ DeleteObject(hBmp);
+ pic->Release();
+ return (INT_PTR)hBmpCopy;
+}
+
+static INT_PTR BmpFilterLoadBitmap(WPARAM, LPARAM lParam)
+{
+ return sttBitmapLoader( StrConvT(( const char* )lParam ));
+}
+
+#if defined( _UNICODE )
+static INT_PTR BmpFilterLoadBitmapW(WPARAM, LPARAM lParam)
+{
+ return sttBitmapLoader(( const wchar_t* )lParam );
+}
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+static INT_PTR BmpFilterGetStrings(WPARAM wParam,LPARAM lParam)
+{
+ int bytesLeft=wParam;
+ char *filter=(char*)lParam,*pfilter;
+
+ lstrcpynA(filter,Translate("All Bitmaps"),bytesLeft); bytesLeft-=lstrlenA(filter);
+ strncat(filter," (*.bmp;*.jpg;*.gif;*.png)",bytesLeft);
+ pfilter=filter+lstrlenA(filter)+1; bytesLeft=wParam-(pfilter-filter);
+ lstrcpynA(pfilter,"*.BMP;*.RLE;*.JPG;*.JPEG;*.GIF;*.PNG",bytesLeft);
+ pfilter+=lstrlenA(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+
+ lstrcpynA(pfilter,Translate("Windows Bitmaps"),bytesLeft); bytesLeft-=lstrlenA(pfilter);
+ strncat(pfilter," (*.bmp;*.rle)",bytesLeft);
+ pfilter+=lstrlenA(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+ lstrcpynA(pfilter,"*.BMP;*.RLE",bytesLeft);
+ pfilter+=lstrlenA(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+
+ lstrcpynA(pfilter,Translate("JPEG Bitmaps"),bytesLeft); bytesLeft-=lstrlenA(pfilter);
+ strncat(pfilter," (*.jpg;*.jpeg)",bytesLeft);
+ pfilter+=lstrlenA(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+ lstrcpynA(pfilter,"*.JPG;*.JPEG",bytesLeft);
+ pfilter+=lstrlenA(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+
+ lstrcpynA(pfilter,Translate("GIF Bitmaps"),bytesLeft); bytesLeft-=lstrlenA(pfilter);
+ strncat(pfilter," (*.gif)",bytesLeft);
+ pfilter+=lstrlenA(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+ lstrcpynA(pfilter,"*.GIF",bytesLeft);
+ pfilter+=lstrlenA(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+
+ lstrcpynA(pfilter,Translate("PNG Bitmaps"),bytesLeft); bytesLeft-=lstrlenA(pfilter);
+ strncat(pfilter," (*.png)",bytesLeft);
+ pfilter+=lstrlenA(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+ lstrcpynA(pfilter,"*.PNG",bytesLeft);
+ pfilter+=lstrlenA(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+
+ lstrcpynA(pfilter,Translate("All Files"),bytesLeft); bytesLeft-=lstrlenA(pfilter);
+ strncat(pfilter," (*)",bytesLeft);
+ pfilter+=lstrlenA(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+ lstrcpynA(pfilter,"*",bytesLeft);
+ pfilter+=lstrlenA(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+
+ if (bytesLeft) *pfilter='\0';
+ return 0;
+}
+
+#if defined( _UNICODE )
+static INT_PTR BmpFilterGetStringsW(WPARAM wParam,LPARAM lParam)
+{
+ int bytesLeft=wParam;
+ TCHAR *filter=(TCHAR*)lParam,*pfilter;
+
+ lstrcpyn(filter,TranslateT("All Bitmaps"),bytesLeft); bytesLeft-=lstrlen(filter);
+ _tcsncat(filter, _T(" (*.bmp;*.jpg;*.gif;*.png)"), bytesLeft );
+ pfilter=filter+lstrlen(filter)+1; bytesLeft=wParam-(pfilter-filter);
+ lstrcpyn(pfilter,_T("*.BMP;*.RLE;*.JPG;*.JPEG;*.GIF;*.PNG"),bytesLeft);
+ pfilter+=lstrlen(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+
+ lstrcpyn(pfilter,TranslateT("Windows Bitmaps"),bytesLeft); bytesLeft-=lstrlen(pfilter);
+ _tcsncat(pfilter,_T(" (*.bmp;*.rle)"),bytesLeft);
+ pfilter+=lstrlen(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+ lstrcpyn(pfilter,_T("*.BMP;*.RLE"),bytesLeft);
+ pfilter+=lstrlen(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+
+ lstrcpyn(pfilter,TranslateT("JPEG Bitmaps"),bytesLeft); bytesLeft-=lstrlen(pfilter);
+ _tcsncat(pfilter,_T(" (*.jpg;*.jpeg)"),bytesLeft);
+ pfilter+=lstrlen(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+ lstrcpyn(pfilter,_T("*.JPG;*.JPEG"),bytesLeft);
+ pfilter+=lstrlen(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+
+ lstrcpyn(pfilter,TranslateT("GIF Bitmaps"),bytesLeft); bytesLeft-=lstrlen(pfilter);
+ _tcsncat(pfilter,_T(" (*.gif)"),bytesLeft);
+ pfilter+=lstrlen(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+ lstrcpyn(pfilter,_T("*.GIF"),bytesLeft);
+ pfilter+=lstrlen(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+
+ lstrcpyn(pfilter,TranslateT("PNG Bitmaps"),bytesLeft); bytesLeft-=lstrlen(pfilter);
+ _tcsncat(pfilter,_T(" (*.png)"),bytesLeft);
+ pfilter+=lstrlen(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+ lstrcpyn(pfilter,_T("*.PNG"),bytesLeft);
+ pfilter+=lstrlen(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+
+ lstrcpyn(pfilter,TranslateT("All Files"),bytesLeft); bytesLeft-=lstrlen(pfilter);
+ _tcsncat(pfilter,_T(" (*)"),bytesLeft);
+ pfilter+=lstrlen(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+ lstrcpyn(pfilter,_T("*"),bytesLeft);
+ pfilter+=lstrlen(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+
+ if (bytesLeft) *pfilter='\0';
+ return 0;
+}
+#endif
+
+int InitBitmapFilter(void)
+{
+ CreateServiceFunction(MS_UTILS_LOADBITMAP,BmpFilterLoadBitmap);
+ CreateServiceFunction(MS_UTILS_GETBITMAPFILTERSTRINGS,BmpFilterGetStrings);
+ #if defined( _UNICODE )
+ CreateServiceFunction(MS_UTILS_GETBITMAPFILTERSTRINGSW,BmpFilterGetStringsW);
+ CreateServiceFunction(MS_UTILS_LOADBITMAPW,BmpFilterLoadBitmapW);
+ #endif
+ return 0;
+}
diff --git a/src/modules/utils/colourpicker.cpp b/src/modules/utils/colourpicker.cpp
new file mode 100644
index 0000000000..ec1a87153c
--- /dev/null
+++ b/src/modules/utils/colourpicker.cpp
@@ -0,0 +1,107 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2009 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#include "commonheaders.h"
+
+static LRESULT CALLBACK ColourPickerWndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
+{
+ switch(message) {
+ case WM_CREATE:
+ SetWindowLongPtr(hwnd,0,0);
+ SetWindowLongPtr(hwnd,sizeof(COLORREF),0);
+ break;
+ case CPM_SETDEFAULTCOLOUR:
+ SetWindowLongPtr(hwnd,sizeof(COLORREF),lParam);
+ break;
+ case CPM_GETDEFAULTCOLOUR:
+ return GetWindowLongPtr(hwnd,sizeof(COLORREF));
+ case CPM_SETCOLOUR:
+ SetWindowLongPtr(hwnd,0,lParam);
+ InvalidateRect(hwnd,NULL,FALSE);
+ break;
+ case CPM_GETCOLOUR:
+ return GetWindowLongPtr(hwnd,0);
+ case WM_LBUTTONUP:
+ {
+ CHOOSECOLOR cc={0};
+ COLORREF custColours[16]={0};
+ custColours[0]=GetWindowLongPtr(hwnd,sizeof(COLORREF));
+ cc.lStructSize=sizeof(CHOOSECOLOR);
+ cc.hwndOwner=hwnd;
+ cc.hInstance=(HWND)hMirandaInst;
+ cc.rgbResult=GetWindowLongPtr(hwnd,0);
+ cc.lpCustColors=custColours;
+ cc.Flags=CC_ANYCOLOR|CC_FULLOPEN|CC_RGBINIT;
+ if(ChooseColor(&cc)) {
+ SetWindowLongPtr(hwnd,0,cc.rgbResult);
+ SendMessage(GetParent(hwnd),WM_COMMAND,MAKEWPARAM(GetDlgCtrlID(hwnd),CPN_COLOURCHANGED),(LPARAM)hwnd);
+ InvalidateRect(hwnd,NULL,FALSE);
+ }
+ break;
+ }
+ case WM_ENABLE:
+ InvalidateRect(hwnd,NULL,FALSE);
+ break;
+ case WM_NCPAINT:
+ case WM_PAINT:
+ { PAINTSTRUCT ps;
+ HDC hdc1;
+ RECT rc;
+ HBRUSH hBrush;
+
+ hdc1=BeginPaint(hwnd,&ps);
+ GetClientRect(hwnd,&rc);
+ DrawEdge(hdc1,&rc,EDGE_ETCHED,BF_RECT);
+ InflateRect(&rc,-2,-2);
+ if(IsWindowEnabled(hwnd))
+ hBrush=CreateSolidBrush(GetWindowLongPtr(hwnd,0));
+ else
+ hBrush=CreateHatchBrush(HS_BDIAGONAL,GetSysColor(COLOR_GRAYTEXT));
+ SetBkColor(hdc1,GetSysColor(COLOR_BTNFACE));
+ FillRect(hdc1,&rc,hBrush);
+ DeleteObject(hBrush);
+ EndPaint(hwnd,&ps);
+ break;
+ }
+ case WM_DESTROY:
+ break;
+ }
+ return DefWindowProc(hwnd,message,wParam,lParam);
+}
+
+int InitColourPicker(void)
+{
+ WNDCLASS wcl;
+
+ wcl.lpfnWndProc=ColourPickerWndProc;
+ wcl.cbClsExtra=0;
+ wcl.cbWndExtra=sizeof(COLORREF)*2;
+ wcl.hInstance=hMirandaInst;
+ wcl.hCursor=NULL;
+ wcl.lpszClassName=WNDCLASS_COLOURPICKER;
+ wcl.hbrBackground=(HBRUSH)(COLOR_BTNFACE+1);
+ wcl.hIcon=NULL;
+ wcl.lpszMenuName=NULL;
+ wcl.style=CS_HREDRAW|CS_VREDRAW|CS_GLOBALCLASS;
+ RegisterClass(&wcl);
+ return 0;
+}
diff --git a/src/modules/utils/hyperlink.cpp b/src/modules/utils/hyperlink.cpp
new file mode 100644
index 0000000000..62d307a958
--- /dev/null
+++ b/src/modules/utils/hyperlink.cpp
@@ -0,0 +1,274 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2009 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#include "commonheaders.h"
+
+struct HyperlinkWndData {
+ HFONT hEnableFont,hDisableFont;
+ RECT rcText;
+ COLORREF enableColor, disableColor, focusColor;
+ BYTE flags; /* see HLKF_* */
+};
+
+/* flags */
+#define HLKF_HASENABLECOLOR 0x1 /* dat->enableColor is not system default */
+#define HLKF_HASDISABLECOLOR 0x2 /* dat->disableColor is not system default */
+
+/* internal messages */
+#define HLK_MEASURETEXT (WM_USER+1)
+#define HLK_INVALIDATE (WM_USER+2)
+
+static LRESULT CALLBACK HyperlinkWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
+{
+ struct HyperlinkWndData *dat=(struct HyperlinkWndData*)GetWindowLongPtr(hwnd,0);
+ switch(msg) {
+ case WM_NCCREATE:
+ dat=(struct HyperlinkWndData*)mir_calloc(sizeof(struct HyperlinkWndData));
+ if(dat==NULL) return FALSE; /* fail creation */
+ SetWindowLongPtr(hwnd,0,(LONG_PTR)dat); /* always succeeds */
+ /* fall thru */
+ case WM_SYSCOLORCHANGE:
+ if(!(dat->flags&HLKF_HASENABLECOLOR)) {
+ if(GetSysColorBrush(COLOR_HOTLIGHT)==NULL) dat->enableColor=RGB(0,0,255);
+ else dat->enableColor=GetSysColor(COLOR_HOTLIGHT);
+ dat->focusColor = RGB(GetRValue(dat->enableColor) / 2, GetGValue(dat->enableColor) / 2, GetBValue(dat->enableColor) / 2);
+ }
+ if(!(dat->flags&HLKF_HASDISABLECOLOR))
+ dat->disableColor=GetSysColor(COLOR_GRAYTEXT);
+ break;
+
+ case WM_SETFOCUS:
+ case WM_KILLFOCUS:
+ RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE);
+ break;
+ case WM_MOUSEACTIVATE:
+ SetFocus(hwnd);
+ return MA_ACTIVATE;
+ case WM_GETDLGCODE:
+ {
+ if (lParam)
+ {
+ MSG *msg = (MSG *) lParam;
+ if (msg->message == WM_KEYDOWN)
+ {
+ if (msg->wParam == VK_TAB)
+ return 0;
+ if (msg->wParam == VK_ESCAPE)
+ return 0;
+ } else
+ if (msg->message == WM_CHAR)
+ {
+ if (msg->wParam == '\t')
+ return 0;
+ if (msg->wParam == 27)
+ return 0;
+ }
+ }
+ return DLGC_WANTMESSAGE;
+ }
+
+ case WM_KEYDOWN:
+ {
+ switch (wParam)
+ {
+ case VK_SPACE:
+ case VK_RETURN:
+ SendMessage(GetParent(hwnd),WM_COMMAND,MAKEWPARAM(GetDlgCtrlID(hwnd),STN_CLICKED),(LPARAM)hwnd);
+ break;
+ }
+ return 0;
+ }
+
+ case WM_LBUTTONDOWN:
+ { POINT pt;
+ POINTSTOPOINT(pt,MAKEPOINTS(lParam));
+ if(!PtInRect(&dat->rcText,pt)) break;
+ SendMessage(GetParent(hwnd),WM_COMMAND,MAKEWPARAM(GetDlgCtrlID(hwnd),STN_CLICKED),(LPARAM)hwnd);
+ return 0;
+ }
+ case WM_SETFONT:
+ { LOGFONT lf;
+ HFONT hFont;
+ if((HFONT)wParam==NULL) { /* use default system color */
+ dat->hEnableFont=dat->hDisableFont=NULL;
+ return 0;
+ }
+ if(GetObject((HFONT)wParam,sizeof(lf),&lf)) {
+ lf.lfUnderline=1;
+ hFont=CreateFontIndirect(&lf);
+ if(hFont!=NULL) {
+ dat->hEnableFont=hFont;
+ dat->hDisableFont=(HFONT)wParam;
+ if(LOWORD(lParam)) SendMessage(hwnd,HLK_INVALIDATE,0,0);
+ SendMessage(hwnd,HLK_MEASURETEXT,0,0);
+ }
+ }
+ return 0;
+ }
+ case WM_ERASEBKGND:
+ return TRUE;
+ case WM_ENABLE:
+ case HLK_INVALIDATE:
+ { RECT rcWnd;
+ POINT pt;
+ HWND hwndParent;
+ if(!GetWindowRect(hwnd,&rcWnd)) break;
+ pt.x=rcWnd.left;
+ pt.y=rcWnd.top;
+ hwndParent=GetParent(hwnd);
+ if(hwndParent==NULL) hwndParent=hwnd;
+ if(!ScreenToClient(hwndParent,&pt)) break;
+ rcWnd.right=pt.x+(rcWnd.right-rcWnd.left);
+ rcWnd.bottom=pt.y+(rcWnd.bottom-rcWnd.top);
+ rcWnd.left=pt.x;
+ rcWnd.top=pt.y;
+ InvalidateRect(hwndParent,&rcWnd,TRUE);
+ return 0;
+ }
+ case WM_GETFONT:
+ return (LRESULT)dat->hDisableFont;
+ case WM_CREATE:
+ case HLK_MEASURETEXT:
+ { TCHAR szText[256];
+ if(!GetWindowText(hwnd,szText,SIZEOF(szText))) return 0;
+ lParam=(LPARAM)szText;
+ /* fall thru */
+ case WM_SETTEXT:
+ { HFONT hPrevFont = NULL;
+ SIZE textSize;
+ RECT rc;
+ HDC hdc;
+ LONG style;
+ BOOL fMeasured=FALSE;
+ hdc=GetDC(hwnd);
+ if(hdc==NULL) return 0; /* text change failed */
+ if(dat->hEnableFont!=NULL) hPrevFont=(HFONT)SelectObject(hdc,dat->hEnableFont);
+ if(dat->hEnableFont==NULL || hPrevFont!=NULL) /* select failed? */
+ if(GetTextExtentPoint32(hdc,(TCHAR*)lParam,lstrlen((TCHAR*)lParam),&textSize))
+ if(GetClientRect(hwnd,&rc)) {
+ dat->rcText.top=0;
+ dat->rcText.bottom=dat->rcText.top+textSize.cy;
+ style=GetWindowLongPtr(hwnd,GWL_STYLE);
+ if(style&SS_CENTER) dat->rcText.left=(rc.right-textSize.cx)/2;
+ else if(style&SS_RIGHT) dat->rcText.left=rc.right-textSize.cx;
+ else dat->rcText.left=0;
+ dat->rcText.right=dat->rcText.left+textSize.cx;
+ fMeasured=TRUE;
+ }
+ if(dat->hEnableFont!=NULL && hPrevFont!=NULL) SelectObject(hdc,hPrevFont);
+ ReleaseDC(hwnd,hdc);
+ if(!fMeasured) return 0; /* text change failed */
+ SendMessage(hwnd,HLK_INVALIDATE,0,0);
+ break;
+ }}
+ case WM_SETCURSOR:
+ { POINT pt;
+ HCURSOR hCursor;
+ if(!GetCursorPos(&pt)) return FALSE;
+ if(!ScreenToClient(hwnd,&pt)) return FALSE;
+ if(PtInRect(&dat->rcText,pt)) {
+ hCursor=(HCURSOR)GetClassLongPtr(hwnd,GCLP_HCURSOR);
+ if(hCursor==NULL) hCursor=LoadCursor(NULL,IDC_HAND); /* Win2000+ */
+ }
+ else hCursor=LoadCursor(NULL,IDC_ARROW);
+ SetCursor(hCursor);
+ return TRUE;
+ }
+ case HLK_SETENABLECOLOUR:
+ { COLORREF prevColor=dat->enableColor;
+ dat->enableColor=(COLORREF)wParam;
+ dat->focusColor = RGB(GetRValue(dat->enableColor) / 2, GetGValue(dat->enableColor) / 2, GetBValue(dat->enableColor) / 2);
+ dat->flags|=HLKF_HASENABLECOLOR;
+ return (LRESULT)prevColor;
+ }
+ case HLK_SETDISABLECOLOUR:
+ { COLORREF prevColor=dat->disableColor;
+ dat->disableColor=(COLORREF)wParam;
+ dat->flags|=HLKF_HASDISABLECOLOR;
+ return (LRESULT)prevColor;
+ }
+ case WM_NCPAINT:
+ return 0;
+ case WM_PAINT:
+ { HFONT hPrevFont;
+ RECT rc;
+ TCHAR szText[256];
+ UINT alignFlag;
+ COLORREF textColor;
+ PAINTSTRUCT ps;
+ HDC hdc;
+
+ hdc=BeginPaint(hwnd,&ps);
+ if(hdc!=NULL) {
+ if(IsWindowEnabled(hwnd)) {
+ hPrevFont=(HFONT)SelectObject(hdc,dat->hEnableFont);
+ textColor = (GetFocus() == hwnd) ? dat->focusColor : dat->enableColor;
+ } else {
+ hPrevFont=(HFONT)SelectObject(hdc,dat->hDisableFont);
+ textColor=dat->disableColor;
+ }
+ if(GetClientRect(hwnd,&rc) && GetWindowText(hwnd,szText,SIZEOF(szText))) {
+ if (drawThemeParentBackground && IsWinVerXPPlus())
+ {
+ BOOL fSmoothing;
+ UINT fSmoothingType;
+ SystemParametersInfo(SPI_GETFONTSMOOTHING, 0, &fSmoothing, 0);
+ SystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE, 0, &fSmoothingType, 0);
+ if (fSmoothing && fSmoothingType == FE_FONTSMOOTHINGCLEARTYPE)
+ drawThemeParentBackground(hwnd, hdc, &rc);
+ }
+ SetBkMode(hdc,TRANSPARENT);
+ SetTextColor(hdc,textColor);
+ alignFlag=(GetWindowLongPtr(hwnd,GWL_STYLE)&(SS_CENTER|SS_RIGHT|SS_LEFT));
+ DrawText(hdc,szText,-1,&rc,alignFlag|DT_NOPREFIX|DT_SINGLELINE|DT_TOP);
+ }
+ if(hPrevFont!=NULL) SelectObject(hdc,hPrevFont);
+ EndPaint(hwnd,&ps);
+ }
+ return 0;
+ }
+ case WM_NCDESTROY:
+ if(dat->hEnableFont!=NULL) DeleteObject(dat->hEnableFont);
+ mir_free(dat);
+ break;
+ }
+ return DefWindowProc(hwnd,msg,wParam,lParam);
+}
+
+int InitHyperlink(void)
+{
+ WNDCLASS wcl;
+
+ wcl.lpfnWndProc=HyperlinkWndProc;
+ wcl.cbClsExtra=0;
+ wcl.cbWndExtra=sizeof(struct HyperlinkWndData*);
+ wcl.hInstance=hMirandaInst;
+ if(IsWinVer2000Plus()) wcl.hCursor=NULL;
+ else wcl.hCursor=LoadCursor(wcl.hInstance,MAKEINTRESOURCE(IDC_HYPERLINKHAND));
+ wcl.lpszClassName=WNDCLASS_HYPERLINK;
+ wcl.hbrBackground=NULL;
+ wcl.hIcon=NULL;
+ wcl.lpszMenuName=NULL;
+ wcl.style=CS_HREDRAW|CS_VREDRAW|CS_GLOBALCLASS|CS_PARENTDC;
+ RegisterClass(&wcl); /* automatically unregistered on exit */
+ return 0;
+}
diff --git a/src/modules/utils/imgconv.cpp b/src/modules/utils/imgconv.cpp
new file mode 100644
index 0000000000..e25953e471
--- /dev/null
+++ b/src/modules/utils/imgconv.cpp
@@ -0,0 +1,152 @@
+/*
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2010 Miranda IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#include "commonheaders.h"
+
+typedef DWORD ARGB;
+
+void InitBitmapInfo(BITMAPINFO &bmi, const SIZE &size)
+{
+ ZeroMemory(&bmi, sizeof(BITMAPINFO));
+ bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ bmi.bmiHeader.biPlanes = 1;
+ bmi.bmiHeader.biCompression = BI_RGB;
+ bmi.bmiHeader.biBitCount = 32;
+
+ bmi.bmiHeader.biWidth = size.cx;
+ bmi.bmiHeader.biHeight = size.cy;
+}
+
+void ConvertToPARGB32(HDC hdc, ARGB *pargb, HBITMAP hbmp, SIZE& sizImage, int cxRow)
+{
+ BITMAPINFO bmi;
+ InitBitmapInfo(bmi, sizImage);
+
+ void *pvBits = malloc(sizImage.cx * 4 * sizImage.cy);
+ if (GetDIBits(hdc, hbmp, 0, bmi.bmiHeader.biHeight, pvBits, &bmi, DIB_RGB_COLORS) == bmi.bmiHeader.biHeight)
+ {
+ ULONG cxDelta = cxRow - bmi.bmiHeader.biWidth;
+ ARGB *pargbMask = (ARGB *)pvBits;
+
+ for (ULONG y = bmi.bmiHeader.biHeight + 1; --y; )
+ {
+ for (ULONG x = bmi.bmiHeader.biWidth + 1; --x; )
+ {
+ if (*pargbMask++)
+ {
+ // transparent pixel
+ *pargb++ = 0;
+ }
+ else
+ {
+ // opaque pixel
+ *pargb++ |= 0xFF000000;
+ }
+ }
+
+ pargb += cxDelta;
+ }
+ }
+ free(pvBits);
+}
+
+bool HasAlpha( ARGB *pargb, SIZE& sizImage, int cxRow)
+{
+ ULONG cxDelta = cxRow - sizImage.cx;
+ for (ULONG y = sizImage.cy; y--; )
+ {
+ for (ULONG x = sizImage.cx; x--; )
+ {
+ if (*pargb++ & 0xFF000000)
+ return true;
+ }
+ pargb += cxDelta;
+ }
+
+ return false;
+}
+
+void ConvertBufferToPARGB32(HANDLE hPaintBuffer, HDC hdc, HICON hIcon, SIZE& sizIcon)
+{
+ RGBQUAD *prgbQuad;
+ int cxRow;
+ HRESULT hr = getBufferedPaintBits(hPaintBuffer, &prgbQuad, &cxRow);
+ if (SUCCEEDED(hr))
+ {
+ ARGB *pargb = (ARGB *)prgbQuad;
+ if (!HasAlpha(pargb, sizIcon, cxRow))
+ {
+ ICONINFO info;
+ if (GetIconInfo(hIcon, &info))
+ {
+ if (info.hbmMask)
+ ConvertToPARGB32(hdc, pargb, info.hbmMask, sizIcon, cxRow);
+
+ DeleteObject(info.hbmColor);
+ DeleteObject(info.hbmMask);
+ }
+ }
+ }
+}
+
+HBITMAP ConvertIconToBitmap(HICON hicon, HIMAGELIST hIml, int iconId)
+{
+ SIZE sizIcon;
+ sizIcon.cx = GetSystemMetrics(SM_CXSMICON);
+ sizIcon.cy = GetSystemMetrics(SM_CYSMICON);
+
+ RECT rcIcon = { 0, 0, sizIcon.cx, sizIcon.cy };
+
+ HDC hdc = CreateCompatibleDC(NULL);
+
+ BITMAPINFO bmi;
+ InitBitmapInfo(bmi, sizIcon);
+
+ HBITMAP hbmp = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, NULL, NULL, 0);
+ HBITMAP hbmpOld = (HBITMAP)SelectObject(hdc, hbmp);
+
+ BLENDFUNCTION bfAlpha = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
+ BP_PAINTPARAMS paintParams = {0};
+ paintParams.cbSize = sizeof(paintParams);
+ paintParams.dwFlags = BPPF_ERASE;
+ paintParams.pBlendFunction = &bfAlpha;
+
+ HDC hdcBuffer;
+ HANDLE hPaintBuffer = beginBufferedPaint(hdc, &rcIcon, BPBF_DIB, &paintParams, &hdcBuffer);
+ if (hPaintBuffer)
+ {
+ if (hIml)
+ ImageList_Draw(hIml, iconId, hdc, 0, 0, ILD_TRANSPARENT);
+ else
+ DrawIconEx(hdcBuffer, 0, 0, hicon, sizIcon.cx, sizIcon.cy, 0, NULL, DI_NORMAL);
+
+ // If icon did not have an alpha channel we need to convert buffer to PARGB
+ ConvertBufferToPARGB32(hPaintBuffer, hdc, hicon, sizIcon);
+
+ // This will write the buffer contents to the destination bitmap
+ endBufferedPaint(hPaintBuffer, TRUE);
+ }
+
+ SelectObject(hdc, hbmpOld);
+ DeleteDC(hdc);
+
+ return hbmp;
+}
diff --git a/src/modules/utils/md5.cpp b/src/modules/utils/md5.cpp
new file mode 100644
index 0000000000..0fcaccb9ae
--- /dev/null
+++ b/src/modules/utils/md5.cpp
@@ -0,0 +1,374 @@
+/*
+ Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved.
+
+ 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.
+
+ L. Peter Deutsch
+ ghost@aladdin.com
+
+ */
+/* $Id: md5.c 2874 2006-05-16 21:38:00Z ghazan $ */
+/*
+ Independent implementation of MD5 (RFC 1321).
+
+ This code implements the MD5 Algorithm defined in RFC 1321, whose
+ text is available at
+ http://www.ietf.org/rfc/rfc1321.txt
+ The code is derived from the text of the RFC, including the test suite
+ (section A.5) but excluding the rest of Appendix A. It does not include
+ any code or documentation that is identified in the RFC as being
+ copyrighted.
+
+ The original and principal author of md5.c is L. Peter Deutsch
+ <ghost@aladdin.com>. Other authors are noted in the change history
+ that follows (in reverse chronological order):
+
+ 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order
+ either statically or dynamically; added missing #include <string.h>
+ in library.
+ 2002-03-11 lpd Corrected argument list for main(), and added int return
+ type, in test program and T value program.
+ 2002-02-21 lpd Added missing #include <stdio.h> in test program.
+ 2000-07-03 lpd Patched to eliminate warnings about "constant is
+ unsigned in ANSI C, signed in traditional"; made test program
+ self-checking.
+ 1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
+ 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
+ 1999-05-03 lpd Original version.
+ */
+
+// (C) 2005 Joe @ Whale - changed to compile with Miranda
+
+#include "commonheaders.h"
+
+
+#define T_MASK ((mir_md5_word_t)~0)
+#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
+#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
+#define T3 0x242070db
+#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
+#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
+#define T6 0x4787c62a
+#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
+#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
+#define T9 0x698098d8
+#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
+#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
+#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
+#define T13 0x6b901122
+#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
+#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
+#define T16 0x49b40821
+#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
+#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
+#define T19 0x265e5a51
+#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
+#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
+#define T22 0x02441453
+#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
+#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
+#define T25 0x21e1cde6
+#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
+#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
+#define T28 0x455a14ed
+#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
+#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
+#define T31 0x676f02d9
+#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
+#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
+#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
+#define T35 0x6d9d6122
+#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
+#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
+#define T38 0x4bdecfa9
+#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
+#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
+#define T41 0x289b7ec6
+#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
+#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
+#define T44 0x04881d05
+#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
+#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
+#define T47 0x1fa27cf8
+#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
+#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
+#define T50 0x432aff97
+#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
+#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
+#define T53 0x655b59c3
+#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
+#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
+#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
+#define T57 0x6fa87e4f
+#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
+#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
+#define T60 0x4e0811a1
+#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
+#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
+#define T63 0x2ad7d2bb
+#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
+
+//gfd*
+static void md5_process(mir_md5_state_t *pms, const mir_md5_byte_t *data /*[64]*/)
+{
+ mir_md5_word_t
+ a = pms->abcd[0], b = pms->abcd[1],
+ c = pms->abcd[2], d = pms->abcd[3];
+ mir_md5_word_t t;
+ /* Define storage for little-endian or both types of CPUs. */
+ mir_md5_word_t xbuf[16];
+ const mir_md5_word_t *X;
+
+ {
+ /*
+ * Determine dynamically whether this is a big-endian or
+ * little-endian machine, since we can use a more efficient
+ * algorithm on the latter.
+ */
+ static const int w = 1;
+
+ if (*((const mir_md5_byte_t *)&w)) /* dynamic little-endian */
+ {
+ /*
+ * On little-endian machines, we can process properly aligned
+ * data without copying it.
+ */
+ if (!((data - (const mir_md5_byte_t *)0) & 3)) {
+ /* data are properly aligned */
+ X = (const mir_md5_word_t *)data;
+ } else {
+ /* not aligned */
+ memcpy(xbuf, data, 64);
+ X = xbuf;
+ }
+ }
+ else /* dynamic big-endian */
+ {
+ /*
+ * On big-endian machines, we must arrange the bytes in the
+ * right order.
+ */
+ const mir_md5_byte_t *xp = data;
+ int i;
+
+ X = xbuf; /* (dynamic only) */
+ for (i = 0; i < 16; ++i, xp += 4)
+ xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
+ }
+ }
+
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
+
+ /* Round 1. */
+ /* Let [abcd k s i] denote the operation
+ a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
+#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
+#define SET1(a, b, c, d, k, s, Ti)\
+ t = a + F(b,c,d) + X[k] + Ti;\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET1(a, b, c, d, 0, 7, T1);
+ SET1(d, a, b, c, 1, 12, T2);
+ SET1(c, d, a, b, 2, 17, T3);
+ SET1(b, c, d, a, 3, 22, T4);
+ SET1(a, b, c, d, 4, 7, T5);
+ SET1(d, a, b, c, 5, 12, T6);
+ SET1(c, d, a, b, 6, 17, T7);
+ SET1(b, c, d, a, 7, 22, T8);
+ SET1(a, b, c, d, 8, 7, T9);
+ SET1(d, a, b, c, 9, 12, T10);
+ SET1(c, d, a, b, 10, 17, T11);
+ SET1(b, c, d, a, 11, 22, T12);
+ SET1(a, b, c, d, 12, 7, T13);
+ SET1(d, a, b, c, 13, 12, T14);
+ SET1(c, d, a, b, 14, 17, T15);
+ SET1(b, c, d, a, 15, 22, T16);
+
+ /* Round 2. */
+ /* Let [abcd k s i] denote the operation
+ a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
+#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
+#define SET2(a, b, c, d, k, s, Ti)\
+ t = a + G(b,c,d) + X[k] + Ti;\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET2(a, b, c, d, 1, 5, T17);
+ SET2(d, a, b, c, 6, 9, T18);
+ SET2(c, d, a, b, 11, 14, T19);
+ SET2(b, c, d, a, 0, 20, T20);
+ SET2(a, b, c, d, 5, 5, T21);
+ SET2(d, a, b, c, 10, 9, T22);
+ SET2(c, d, a, b, 15, 14, T23);
+ SET2(b, c, d, a, 4, 20, T24);
+ SET2(a, b, c, d, 9, 5, T25);
+ SET2(d, a, b, c, 14, 9, T26);
+ SET2(c, d, a, b, 3, 14, T27);
+ SET2(b, c, d, a, 8, 20, T28);
+ SET2(a, b, c, d, 13, 5, T29);
+ SET2(d, a, b, c, 2, 9, T30);
+ SET2(c, d, a, b, 7, 14, T31);
+ SET2(b, c, d, a, 12, 20, T32);
+
+ /* Round 3. */
+ /* Let [abcd k s t] denote the operation
+ a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define SET3(a, b, c, d, k, s, Ti)\
+ t = a + H(b,c,d) + X[k] + Ti;\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET3(a, b, c, d, 5, 4, T33);
+ SET3(d, a, b, c, 8, 11, T34);
+ SET3(c, d, a, b, 11, 16, T35);
+ SET3(b, c, d, a, 14, 23, T36);
+ SET3(a, b, c, d, 1, 4, T37);
+ SET3(d, a, b, c, 4, 11, T38);
+ SET3(c, d, a, b, 7, 16, T39);
+ SET3(b, c, d, a, 10, 23, T40);
+ SET3(a, b, c, d, 13, 4, T41);
+ SET3(d, a, b, c, 0, 11, T42);
+ SET3(c, d, a, b, 3, 16, T43);
+ SET3(b, c, d, a, 6, 23, T44);
+ SET3(a, b, c, d, 9, 4, T45);
+ SET3(d, a, b, c, 12, 11, T46);
+ SET3(c, d, a, b, 15, 16, T47);
+ SET3(b, c, d, a, 2, 23, T48);
+
+ /* Round 4. */
+ /* Let [abcd k s t] denote the operation
+ a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
+#define I(x, y, z) ((y) ^ ((x) | ~(z)))
+#define SET4(a, b, c, d, k, s, Ti)\
+ t = a + I(b,c,d) + X[k] + Ti;\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET4(a, b, c, d, 0, 6, T49);
+ SET4(d, a, b, c, 7, 10, T50);
+ SET4(c, d, a, b, 14, 15, T51);
+ SET4(b, c, d, a, 5, 21, T52);
+ SET4(a, b, c, d, 12, 6, T53);
+ SET4(d, a, b, c, 3, 10, T54);
+ SET4(c, d, a, b, 10, 15, T55);
+ SET4(b, c, d, a, 1, 21, T56);
+ SET4(a, b, c, d, 8, 6, T57);
+ SET4(d, a, b, c, 15, 10, T58);
+ SET4(c, d, a, b, 6, 15, T59);
+ SET4(b, c, d, a, 13, 21, T60);
+ SET4(a, b, c, d, 4, 6, T61);
+ SET4(d, a, b, c, 11, 10, T62);
+ SET4(c, d, a, b, 2, 15, T63);
+ SET4(b, c, d, a, 9, 21, T64);
+
+ /* Then perform the following additions. (That is increment each
+ of the four registers by the value it had before this block
+ was started.) */
+ pms->abcd[0] += a;
+ pms->abcd[1] += b;
+ pms->abcd[2] += c;
+ pms->abcd[3] += d;
+}
+
+void md5_init(mir_md5_state_t *pms)
+{
+ pms->count[0] = pms->count[1] = 0;
+ pms->abcd[0] = 0x67452301;
+ pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
+ pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
+ pms->abcd[3] = 0x10325476;
+}
+
+void md5_append(mir_md5_state_t *pms, const mir_md5_byte_t *data, int nbytes)
+{
+ const mir_md5_byte_t *p = data;
+ int left = nbytes;
+ int offset = (pms->count[0] >> 3) & 63;
+ mir_md5_word_t nbits = (mir_md5_word_t)(nbytes << 3);
+
+ if (nbytes <= 0)
+ return;
+
+ /* Update the message length. */
+ pms->count[1] += nbytes >> 29;
+ pms->count[0] += nbits;
+ if (pms->count[0] < nbits)
+ pms->count[1]++;
+
+ /* Process an initial partial block. */
+ if (offset) {
+ int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
+
+ memcpy(pms->buf + offset, p, copy);
+ if (offset + copy < 64)
+ return;
+ p += copy;
+ left -= copy;
+ md5_process(pms, pms->buf);
+ }
+
+ /* Process full blocks. */
+ for (; left >= 64; p += 64, left -= 64)
+ md5_process(pms, p);
+
+ /* Process a final partial block. */
+ if (left)
+ memcpy(pms->buf, p, left);
+}
+
+void md5_finish(mir_md5_state_t *pms, mir_md5_byte_t digest[16])
+{
+ static const mir_md5_byte_t pad[64] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+ mir_md5_byte_t data[8];
+ int i;
+
+ /* Save the length before padding. */
+ for (i = 0; i < 8; ++i)
+ data[i] = (mir_md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
+ /* Pad to 56 bytes mod 64. */
+ md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
+ /* Append the length. */
+ md5_append(pms, data, 8);
+ for (i = 0; i < 16; ++i)
+ digest[i] = (mir_md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
+}
+
+void md5_hash_string(const mir_md5_byte_t *data, int len, mir_md5_byte_t digest[16])
+{
+ mir_md5_state_t state;
+ md5_init(&state);
+ md5_append(&state, data, len);
+ md5_finish(&state, digest);
+}
+
+INT_PTR GetMD5Interface(WPARAM, LPARAM lParam)
+{
+ struct MD5_INTERFACE *md5i = (struct MD5_INTERFACE*) lParam;
+ if ( md5i == NULL )
+ return 1;
+ if ( md5i->cbSize != sizeof( struct MD5_INTERFACE ))
+ return 1;
+
+ md5i->md5_init = md5_init;
+ md5i->md5_append = md5_append;
+ md5i->md5_finish = md5_finish;
+ md5i->md5_hash = md5_hash_string;
+ return 0;
+}
diff --git a/src/modules/utils/openurl.cpp b/src/modules/utils/openurl.cpp
new file mode 100644
index 0000000000..ef66d89f8c
--- /dev/null
+++ b/src/modules/utils/openurl.cpp
@@ -0,0 +1,228 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2009 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#include "commonheaders.h"
+#include <ctype.h>
+
+#define DDEMESSAGETIMEOUT 1000
+#define WNDCLASS_DDEMSGWINDOW _T("MirandaDdeMsgWindow")
+
+struct DdeMsgWindowData {
+ int fAcked,fData;
+ HWND hwndDde;
+};
+
+static LRESULT CALLBACK DdeMessageWindow(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
+{
+ struct DdeMsgWindowData *dat;
+ ATOM hSzItem;
+ HGLOBAL hDdeData;
+
+ dat=(struct DdeMsgWindowData*)GetWindowLongPtr(hwnd,0);
+ switch(msg) {
+ case WM_DDE_ACK:
+ dat->fAcked=1;
+ dat->hwndDde=(HWND)wParam;
+ return 0;
+ case WM_DDE_DATA:
+ UnpackDDElParam(msg,lParam,(PUINT_PTR)&hDdeData,(PUINT_PTR)&hSzItem);
+ dat->fData=1;
+ if(hDdeData) {
+ DDEDATA *data;
+ int release;
+ data=(DDEDATA*)GlobalLock(hDdeData);
+ if(data->fAckReq) {
+ DDEACK ack={0};
+ PostMessage((HWND)wParam,WM_DDE_ACK,(WPARAM)hwnd,PackDDElParam(WM_DDE_ACK,*(PUINT)&ack,(UINT)hSzItem));
+ }
+ else GlobalDeleteAtom(hSzItem);
+ release=data->fRelease;
+ GlobalUnlock(hDdeData);
+ if(release) GlobalFree(hDdeData);
+ }
+ else GlobalDeleteAtom(hSzItem);
+ return 0;
+ }
+ return DefWindowProc(hwnd,msg,wParam,lParam);
+}
+
+static int DoDdeRequest(const char *szItemName,HWND hwndDdeMsg)
+{
+ ATOM hSzItemName;
+ DWORD timeoutTick,thisTick;
+ MSG msg;
+ struct DdeMsgWindowData *dat=(struct DdeMsgWindowData*)GetWindowLongPtr(hwndDdeMsg,0);
+
+ hSzItemName=GlobalAddAtomA(szItemName);
+ if(!PostMessage(dat->hwndDde,WM_DDE_REQUEST,(WPARAM)hwndDdeMsg,MAKELPARAM(CF_TEXT,hSzItemName))) {
+ GlobalDeleteAtom(hSzItemName);
+ return 1;
+ }
+ timeoutTick=GetTickCount()+5000;
+ dat->fData=0; dat->fAcked=0;
+ do {
+ if(PeekMessage(&msg,NULL,0,0,PM_REMOVE)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ if(dat->fData || dat->fAcked) break;
+ thisTick=GetTickCount();
+ if(thisTick>timeoutTick) break;
+ } while(MsgWaitForMultipleObjects(0,NULL,FALSE,timeoutTick-thisTick,QS_ALLINPUT)==WAIT_OBJECT_0);
+
+ if(!dat->fData) {
+ GlobalDeleteAtom(hSzItemName);
+ return 1;
+ }
+ return 0;
+}
+
+//see Q160957 and http://developer.netscape.com/docs/manuals/communicator/DDE/index.htm
+static int DdeOpenUrl(const char *szBrowser,char *szUrl,int newWindow,HWND hwndDdeMsg)
+{
+ ATOM hSzBrowser,hSzTopic;
+ DWORD_PTR dwResult;
+ char *szItemName;
+ struct DdeMsgWindowData *dat=(struct DdeMsgWindowData*)GetWindowLongPtr(hwndDdeMsg,0);
+
+ hSzBrowser=GlobalAddAtomA(szBrowser);
+ hSzTopic=GlobalAddAtomA("WWW_OpenURL");
+ dat->fAcked=0;
+ if(!SendMessageTimeout(HWND_BROADCAST,WM_DDE_INITIATE,(WPARAM)hwndDdeMsg,MAKELPARAM(hSzBrowser,hSzTopic),SMTO_ABORTIFHUNG|SMTO_NORMAL,DDEMESSAGETIMEOUT,&dwResult)
+ || !dat->fAcked) {
+ GlobalDeleteAtom(hSzTopic);
+ GlobalDeleteAtom(hSzBrowser);
+ return 1;
+ }
+ szItemName=(char*)mir_alloc(lstrlenA(szUrl)+7);
+ wsprintfA(szItemName,"\"%s\",,%d",szUrl,newWindow?0:-1);
+ if(DoDdeRequest(szItemName,hwndDdeMsg)) {
+ mir_free(szItemName);
+ GlobalDeleteAtom(hSzTopic);
+ GlobalDeleteAtom(hSzBrowser);
+ return 1;
+ }
+ PostMessage(dat->hwndDde,WM_DDE_TERMINATE,(WPARAM)hwndDdeMsg,0);
+ GlobalDeleteAtom(hSzTopic);
+ GlobalDeleteAtom(hSzBrowser);
+ mir_free(szItemName);
+ return 0;
+}
+
+typedef struct {
+ char *szUrl;
+ int newWindow;
+} TOpenUrlInfo;
+
+static void OpenURLThread(void *arg)
+{
+ TOpenUrlInfo *hUrlInfo = (TOpenUrlInfo*)arg;
+ char *szResult;
+ HWND hwndDdeMsg;
+ struct DdeMsgWindowData msgWndData={0};
+ char *pszProtocol;
+ HKEY hKey;
+ char szSubkey[80];
+ char szCommandName[MAX_PATH];
+ DWORD dataLength;
+ int success=0;
+
+ if (!hUrlInfo->szUrl) return;
+ hwndDdeMsg=CreateWindow(WNDCLASS_DDEMSGWINDOW,_T(""),0,0,0,0,0,NULL,NULL,hMirandaInst,NULL);
+ SetWindowLongPtr(hwndDdeMsg,0,(LONG_PTR)&msgWndData);
+
+ if(!_strnicmp(hUrlInfo->szUrl,"ftp:",4) || !_strnicmp(hUrlInfo->szUrl,"ftp.",4)) pszProtocol="ftp";
+ if(!_strnicmp(hUrlInfo->szUrl,"mailto:",7)) pszProtocol="mailto";
+ if(!_strnicmp(hUrlInfo->szUrl,"news:",5)) pszProtocol="news";
+ else pszProtocol="http";
+ wsprintfA(szSubkey,"%s\\shell\\open\\command",pszProtocol);
+ if(RegOpenKeyExA(HKEY_CURRENT_USER,szSubkey,0,KEY_QUERY_VALUE,&hKey)==ERROR_SUCCESS
+ || RegOpenKeyExA(HKEY_CLASSES_ROOT,szSubkey,0,KEY_QUERY_VALUE,&hKey)==ERROR_SUCCESS) {
+ dataLength=SIZEOF(szCommandName);
+ if(RegQueryValueEx(hKey,NULL,NULL,NULL,(PBYTE)szCommandName,&dataLength)==ERROR_SUCCESS) {
+ _strlwr(szCommandName);
+ if(strstr(szCommandName,"mozilla") || strstr(szCommandName,"netscape"))
+ success=(DdeOpenUrl("mozilla",hUrlInfo->szUrl,hUrlInfo->newWindow,hwndDdeMsg)==0 || DdeOpenUrl("netscape",hUrlInfo->szUrl,hUrlInfo->newWindow,hwndDdeMsg)==0);
+ else if(strstr(szCommandName,"iexplore") || strstr(szCommandName,"msimn"))
+ success=0==DdeOpenUrl("iexplore",hUrlInfo->szUrl,hUrlInfo->newWindow,hwndDdeMsg);
+ else if(strstr(szCommandName,"opera"))
+ success=0==DdeOpenUrl("opera",hUrlInfo->szUrl,hUrlInfo->newWindow,hwndDdeMsg);
+ //opera's the default anyway
+ }
+ RegCloseKey(hKey);
+ }
+
+ DestroyWindow(hwndDdeMsg);
+ if(success) return;
+
+ //wack a protocol on it
+ if((isalpha(hUrlInfo->szUrl[0]) && hUrlInfo->szUrl[1]==':') || hUrlInfo->szUrl[0]=='\\') {
+ szResult=(char*)mir_alloc(lstrlenA(hUrlInfo->szUrl)+9);
+ wsprintfA(szResult,"file:///%s",hUrlInfo->szUrl);
+ }
+ else {
+ int i;
+ for(i=0;isalpha(hUrlInfo->szUrl[i]);i++);
+ if(hUrlInfo->szUrl[i]==':') szResult=mir_strdup(hUrlInfo->szUrl);
+ else {
+ if(!_strnicmp(hUrlInfo->szUrl,"ftp.",4)) {
+ szResult=(char*)mir_alloc(lstrlenA(hUrlInfo->szUrl)+7);
+ wsprintfA(szResult,"ftp://%s",hUrlInfo->szUrl);
+ }
+ else {
+ szResult=(char*)mir_alloc(lstrlenA(hUrlInfo->szUrl)+8);
+ wsprintfA(szResult,"http://%s",hUrlInfo->szUrl);
+ }
+ }
+ }
+ ShellExecuteA(NULL, "open", szResult, NULL, NULL, SW_SHOWDEFAULT);
+ mir_free(szResult);
+ mir_free(hUrlInfo->szUrl);
+ mir_free(hUrlInfo);
+ return;
+}
+
+static INT_PTR OpenURL(WPARAM wParam,LPARAM lParam) {
+ TOpenUrlInfo *hUrlInfo = (TOpenUrlInfo*)mir_alloc(sizeof(TOpenUrlInfo));
+ hUrlInfo->szUrl = (char*)lParam?mir_strdup((char*)lParam):NULL;
+ hUrlInfo->newWindow = (int)wParam;
+ forkthread(OpenURLThread, 0, (void*)hUrlInfo);
+ return 0;
+}
+
+int InitOpenUrl(void)
+{
+ WNDCLASS wcl;
+ wcl.lpfnWndProc=DdeMessageWindow;
+ wcl.cbClsExtra=0;
+ wcl.cbWndExtra=sizeof(void*);
+ wcl.hInstance=hMirandaInst;
+ wcl.hCursor=NULL;
+ wcl.lpszClassName=WNDCLASS_DDEMSGWINDOW;
+ wcl.hbrBackground=NULL;
+ wcl.hIcon=NULL;
+ wcl.lpszMenuName=NULL;
+ wcl.style=0;
+ RegisterClass(&wcl);
+ CreateServiceFunction(MS_UTILS_OPENURL,OpenURL);
+ return 0;
+}
diff --git a/src/modules/utils/path.cpp b/src/modules/utils/path.cpp
new file mode 100644
index 0000000000..80333a3075
--- /dev/null
+++ b/src/modules/utils/path.cpp
@@ -0,0 +1,600 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2009 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#include "commonheaders.h"
+#include "../database/profilemanager.h"
+#include "../srfile/file.h"
+
+extern TCHAR g_profileDir[MAX_PATH];
+
+static char szMirandaPath[MAX_PATH];
+static char szMirandaPathLower[MAX_PATH];
+
+static INT_PTR replaceVars(WPARAM wParam, LPARAM lParam);
+
+static int pathIsAbsolute(const char *path)
+{
+ if ( strlen(path) <= 2 )
+ return 0;
+ if ((path[1]==':'&&path[2]=='\\')||(path[0]=='\\'&&path[1]=='\\'))
+ return 1;
+ return 0;
+}
+
+static INT_PTR pathToRelative(WPARAM wParam, LPARAM lParam)
+{
+ char *pSrc = (char*)wParam;
+ char *pOut = (char*)lParam;
+ if (!pSrc||!strlen(pSrc)||strlen(pSrc)>MAX_PATH) return 0;
+ if (!pathIsAbsolute(pSrc)) {
+ mir_snprintf(pOut, MAX_PATH, "%s", pSrc);
+ return strlen(pOut);
+ }
+ else {
+ char szTmp[MAX_PATH];
+
+ mir_snprintf(szTmp, SIZEOF(szTmp), "%s", pSrc);
+ _strlwr(szTmp);
+ if (strstr(szTmp, szMirandaPathLower)) {
+ mir_snprintf(pOut, MAX_PATH, "%s", pSrc+strlen(szMirandaPathLower));
+ return strlen(pOut);
+ }
+ else {
+ mir_snprintf(pOut, MAX_PATH, "%s", pSrc);
+ return strlen(pOut);
+ }
+ }
+}
+
+int pathToAbsolute(const char *pSrc, char *pOut, char* base)
+{
+ if ( !pSrc || !strlen( pSrc ) || strlen( pSrc ) > MAX_PATH )
+ return 0;
+
+ if ( base == NULL )
+ base = szMirandaPath;
+
+ char buf[MAX_PATH];
+ if ( pSrc[0] < ' ')
+ return mir_snprintf( pOut, MAX_PATH, "%s", pSrc );
+ else if ( pathIsAbsolute( pSrc ))
+ return GetFullPathNameA(pSrc, MAX_PATH, pOut, NULL);
+ else if ( pSrc[0] != '\\' )
+ mir_snprintf( buf, MAX_PATH, "%s%s", base, pSrc );
+ else
+ mir_snprintf( buf, MAX_PATH, "%s%s", base, pSrc+1 );
+
+ return GetFullPathNameA(buf, MAX_PATH, pOut, NULL);
+}
+
+static INT_PTR pathToAbsolute(WPARAM wParam, LPARAM lParam)
+{
+ return pathToAbsolute((char*)wParam, (char*)lParam, szMirandaPath);
+}
+
+void CreatePathToFile( char* szFilePath )
+{
+ char* pszLastBackslash = strrchr( szFilePath, '\\' );
+ if ( pszLastBackslash == NULL )
+ return;
+
+ *pszLastBackslash = '\0';
+ CreateDirectoryTree( szFilePath );
+ *pszLastBackslash = '\\';
+}
+
+int CreateDirectoryTree( const char *szDir )
+{
+ DWORD dwAttributes;
+ char *pszLastBackslash, szTestDir[ MAX_PATH ];
+
+ lstrcpynA( szTestDir, szDir, SIZEOF( szTestDir ));
+ if (( dwAttributes = GetFileAttributesA( szTestDir )) != INVALID_FILE_ATTRIBUTES && ( dwAttributes & FILE_ATTRIBUTE_DIRECTORY ))
+ return 0;
+
+ pszLastBackslash = strrchr( szTestDir, '\\' );
+ if ( pszLastBackslash == NULL )
+ return 0;
+
+ *pszLastBackslash = '\0';
+ CreateDirectoryTree( szTestDir );
+ *pszLastBackslash = '\\';
+ return ( CreateDirectoryA( szTestDir, NULL ) == 0 ) ? GetLastError() : 0;
+}
+
+static INT_PTR createDirTree(WPARAM, LPARAM lParam)
+{
+ if ( lParam == 0 )
+ return 1;
+
+ return CreateDirectoryTree(( char* )lParam );
+}
+
+#ifdef _UNICODE
+static TCHAR szMirandaPathW[MAX_PATH];
+static TCHAR szMirandaPathWLower[MAX_PATH];
+
+static int pathIsAbsoluteW(const TCHAR *path)
+{
+ if ( lstrlen(path) <= 2 )
+ return 0;
+ if ((path[1]==':'&&path[2]=='\\')||(path[0]=='\\'&&path[1]=='\\'))
+ return 1;
+ return 0;
+}
+
+static INT_PTR pathToRelativeW(WPARAM wParam, LPARAM lParam)
+{
+ TCHAR *pSrc = (TCHAR*)wParam;
+ TCHAR *pOut = (TCHAR*)lParam;
+ if ( !pSrc || !lstrlen(pSrc) || lstrlen(pSrc) > MAX_PATH )
+ return 0;
+
+ if ( !pathIsAbsoluteW( pSrc ))
+ mir_sntprintf(pOut, MAX_PATH, _T("%s"), pSrc);
+ else {
+ TCHAR szTmp[MAX_PATH];
+
+ mir_sntprintf(szTmp, SIZEOF(szTmp), _T("%s"), pSrc);
+ _tcslwr(szTmp);
+ if (_tcsstr(szTmp, szMirandaPathWLower))
+ mir_sntprintf(pOut, MAX_PATH, _T("%s"), pSrc+lstrlen(szMirandaPathWLower));
+ else
+ mir_sntprintf(pOut, MAX_PATH, _T("%s"), pSrc);
+ }
+ return lstrlen(pOut);
+}
+
+int pathToAbsoluteW(const TCHAR *pSrc, TCHAR *pOut, TCHAR* base)
+{
+ if ( !pSrc || !wcslen(pSrc) || wcslen(pSrc) > MAX_PATH)
+ return 0;
+
+ if ( base == NULL )
+ base = szMirandaPathW;
+
+ TCHAR buf[MAX_PATH];
+ if ( pSrc[0] < ' ')
+ return mir_sntprintf( pOut, MAX_PATH, _T("%s"), pSrc );
+ else if ( pathIsAbsoluteW( pSrc ))
+ return GetFullPathName(pSrc, MAX_PATH, pOut, NULL);
+ else if ( pSrc[0] != '\\' )
+ mir_sntprintf( buf, MAX_PATH, _T("%s%s"), base, pSrc );
+ else
+ mir_sntprintf( buf, MAX_PATH, _T("%s%s"), base, pSrc+1 );
+
+ return GetFullPathName(buf, MAX_PATH, pOut, NULL);
+}
+
+static INT_PTR pathToAbsoluteW(WPARAM wParam, LPARAM lParam)
+{
+ return pathToAbsoluteW((TCHAR*)wParam, (TCHAR*)lParam, szMirandaPathW);
+}
+
+void CreatePathToFileW( WCHAR* wszFilePath )
+{
+ WCHAR* pszLastBackslash = wcsrchr( wszFilePath, '\\' );
+ if ( pszLastBackslash == NULL )
+ return;
+
+ *pszLastBackslash = '\0';
+ CreateDirectoryTreeW( wszFilePath );
+ *pszLastBackslash = '\\';
+}
+
+int CreateDirectoryTreeW( const WCHAR* szDir )
+{
+ DWORD dwAttributes;
+ WCHAR* pszLastBackslash, szTestDir[ MAX_PATH ];
+
+ lstrcpynW( szTestDir, szDir, SIZEOF( szTestDir ));
+ if (( dwAttributes = GetFileAttributesW( szTestDir )) != INVALID_FILE_ATTRIBUTES && ( dwAttributes & FILE_ATTRIBUTE_DIRECTORY ))
+ return 0;
+
+ pszLastBackslash = wcsrchr( szTestDir, '\\' );
+ if ( pszLastBackslash == NULL )
+ return 0;
+
+ *pszLastBackslash = '\0';
+ CreateDirectoryTreeW( szTestDir );
+ *pszLastBackslash = '\\';
+ return ( CreateDirectoryW( szTestDir, NULL ) == 0 ) ? GetLastError() : 0;
+}
+
+static INT_PTR createDirTreeW(WPARAM, LPARAM lParam)
+{
+ if ( lParam == 0 )
+ return 1;
+
+ return CreateDirectoryTreeW(( WCHAR* )lParam );
+}
+
+int InitPathUtilsW(void)
+{
+ GetModuleFileName(hMirandaInst, szMirandaPathW, SIZEOF(szMirandaPathW));
+ TCHAR *p = _tcsrchr(szMirandaPathW,'\\');
+ if ( p )
+ p[1] = 0;
+ mir_sntprintf(szMirandaPathWLower, SIZEOF(szMirandaPathWLower), _T("%s"), szMirandaPathW);
+ _tcslwr(szMirandaPathWLower);
+ CreateServiceFunction(MS_UTILS_PATHTORELATIVEW, pathToRelativeW);
+ CreateServiceFunction(MS_UTILS_PATHTOABSOLUTEW, pathToAbsoluteW);
+ CreateServiceFunction(MS_UTILS_CREATEDIRTREEW, createDirTreeW);
+ return 0;
+}
+#endif
+
+TCHAR *GetContactID(HANDLE hContact)
+{
+ TCHAR *theValue = {0};
+ char *szProto = ( char* )CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0);
+ if (DBGetContactSettingByte(hContact, szProto, "ChatRoom", 0) == 1) {
+ DBVARIANT dbv;
+ if (!DBGetContactSettingTString(hContact, szProto, "ChatRoomID", &dbv)) {
+ theValue = (TCHAR *)mir_tstrdup(dbv.ptszVal);
+ DBFreeVariant(&dbv);
+ return theValue;
+ } }
+ else {
+ CONTACTINFO ci = {0};
+ ci.cbSize = sizeof(ci);
+ ci.hContact = hContact;
+ ci.szProto = szProto;
+ ci.dwFlag = CNF_UNIQUEID | CNF_TCHAR;
+ if (!CallService(MS_CONTACT_GETCONTACTINFO, 0, (LPARAM) & ci)) {
+ switch (ci.type) {
+ case CNFT_ASCIIZ:
+ return (TCHAR *)ci.pszVal;
+ break;
+ case CNFT_DWORD:
+ return _itot(ci.dVal, (TCHAR *)mir_alloc(sizeof(TCHAR)*32), 10);
+ break;
+ } } }
+ return NULL;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Variables parser
+
+#define XSTR(target, s) _xstrselect(target, s, _T(s))
+
+static __forceinline int _xcscmp(const char *s1, const char *s2) { return strcmp(s1, s2); }
+static __forceinline int _xcsncmp(const char *s1, const char *s2, size_t n) { return strncmp(s1, s2, n); }
+static __forceinline size_t _xcslen(const char *s1) { return strlen(s1); }
+static __forceinline char *_xcscpy(char *s1, const char *s2) { return strcpy(s1, s2); }
+static __forceinline char *_xcsncpy(char *s1, const char *s2, size_t n) { return strncpy(s1, s2, n); }
+static __forceinline char *_xstrselect(char *, char *s1, TCHAR *s2) { return s1; }
+static __forceinline char *_itox(char *, int a) { return itoa(a, (char *)mir_alloc(sizeof(char)*20), 10); }
+static __forceinline char *mir_a2x(char *, char *s) { return mir_strdup(s); }
+static __forceinline char *GetContactNickX(char *, HANDLE hContact)
+{
+ return mir_strdup((char *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, 0));
+}
+static __forceinline char *GetContactIDX(char *, HANDLE hContact)
+{
+ TCHAR *id = GetContactID(hContact);
+ char* res = mir_t2a(id);
+ mir_free(id);
+ return res;
+}
+static __forceinline char *GetEnvironmentVariableX(char *variable)
+{
+ char result[512];
+ if (GetEnvironmentVariableA(variable, result, SIZEOF(result)))
+ return mir_strdup(result);
+ return NULL;
+}
+static __forceinline char *GetProfileDirX( char* )
+{
+ return mir_t2a( g_profileDir );
+}
+static __forceinline char *SHGetSpecialFolderPathX(int iCSIDL, char* var)
+{
+ char result[512];
+ if (shGetSpecialFolderPathA && shGetSpecialFolderPathA(NULL, result, iCSIDL, FALSE))
+ return mir_strdup(result);
+ return NULL;
+}
+static __forceinline char *GetModulePathX(char *, HMODULE hModule)
+{
+ char result[MAX_PATH];
+ GetModuleFileNameA(hModule, result, sizeof(result));
+ char* str = strrchr(result, '\\');
+ if (str) *str = 0;
+ return mir_strdup(result);
+}
+static __forceinline char *GetUserNameX(char *)
+{
+ char result[128];
+ DWORD size = SIZEOF(result);
+ if (GetUserNameA(result, &size))
+ return mir_strdup(result);
+ return NULL;
+}
+static __forceinline char *GetProfileNameX(char *)
+{
+ TCHAR szProfileName[MAX_PATH];
+ _tcscpy( szProfileName, g_profileName );
+ TCHAR *pos = _tcsrchr(szProfileName, '.');
+ if ( lstrcmp( pos, _T(".dat")) == 0 )
+ *pos = 0;
+ return mir_t2a( szProfileName );
+}
+static __forceinline char *GetPathVarX(char *, int code)
+{
+ TCHAR szFullPath[MAX_PATH], szProfileName[MAX_PATH];
+ _tcscpy( szProfileName, g_profileName );
+ _tcslwr( szProfileName );
+ TCHAR *pos = _tcsrchr(szProfileName, '.');
+ if ( lstrcmp( pos, _T(".dat")) == 0 )
+ *pos = 0;
+
+ switch( code ) {
+ case 1:
+ mir_sntprintf(szFullPath, SIZEOF(szFullPath), _T("%s\\%s\\AvatarCache"), g_profileDir, szProfileName);
+ break;
+ case 2:
+ mir_sntprintf(szFullPath, SIZEOF(szFullPath), _T("%s\\%s\\Logs"), g_profileDir, szProfileName);
+ break;
+ case 3:
+ mir_sntprintf(szFullPath, SIZEOF(szFullPath), _T("%s\\%s"), g_profileDir, szProfileName);
+ break;
+ }
+ return makeFileName( szFullPath );
+}
+
+#ifdef _UNICODE
+static __forceinline int _xcscmp(const TCHAR *s1, const TCHAR *s2) { return _tcscmp(s1, s2); }
+static __forceinline int _xcsncmp(const TCHAR *s1, const TCHAR *s2, size_t n) { return _tcsncmp(s1, s2, n); }
+static __forceinline size_t _xcslen(const TCHAR *s1) { return _tcslen(s1); }
+static __forceinline TCHAR *_xcscpy(TCHAR *s1, const TCHAR *s2) { return _tcscpy(s1, s2); }
+static __forceinline TCHAR *_xcsncpy(TCHAR *s1, const TCHAR *s2, size_t n) { return _tcsncpy(s1, s2, n); }
+static __forceinline TCHAR *_xstrselect(TCHAR *, char *s1, TCHAR *s2) { return s2; }
+static __forceinline TCHAR *_itox(TCHAR *, int a) { return _itot(a, (TCHAR *)mir_alloc(sizeof(TCHAR)*20), 10); }
+static __forceinline TCHAR *mir_a2x(TCHAR *, char *s) { return mir_a2t(s); }
+static __forceinline TCHAR *GetContactNickX(TCHAR *, HANDLE hContact)
+{
+ return mir_tstrdup((TCHAR *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, GCDNF_TCHAR));
+}
+static __forceinline TCHAR *GetContactIDX(TCHAR *, HANDLE hContact)
+{
+ return GetContactID(hContact);
+}
+static __forceinline TCHAR *GetEnvironmentVariableX(TCHAR *variable)
+{
+ TCHAR result[512];
+ if (GetEnvironmentVariable(variable, result, SIZEOF(result)))
+ return mir_tstrdup(result);
+ return NULL;
+}
+static __forceinline TCHAR *SHGetSpecialFolderPathX(int iCSIDL, TCHAR* var)
+{
+ TCHAR result[512];
+ if (shGetSpecialFolderPath && shGetSpecialFolderPath(NULL, result, iCSIDL, FALSE))
+ return mir_tstrdup(result);
+ return NULL;
+}
+static __forceinline TCHAR *GetProfileDirX( TCHAR* )
+{
+ return mir_tstrdup( g_profileDir );
+}
+static __forceinline TCHAR *GetModulePathX(TCHAR *, HMODULE hModule)
+{
+ TCHAR result[MAX_PATH];
+ GetModuleFileName(hModule, result, SIZEOF(result));
+ TCHAR* str = _tcsrchr(result, '\\');
+ if (str) *str = 0;
+ return mir_tstrdup(result);
+}
+static __forceinline TCHAR *GetUserNameX(TCHAR *)
+{
+ TCHAR result[128];
+ DWORD size = SIZEOF(result);
+ if (GetUserName(result, &size))
+ return mir_tstrdup(result);
+ return NULL;
+}
+static __forceinline TCHAR *GetProfileNameX(TCHAR *)
+{
+ TCHAR szProfileName[MAX_PATH];
+ _tcscpy( szProfileName, g_profileName );
+ TCHAR *pos = _tcsrchr(szProfileName, '.');
+ if ( lstrcmp( pos, _T(".dat")) == 0 )
+ *pos = 0;
+ return mir_tstrdup( szProfileName );
+}
+static __forceinline TCHAR *GetPathVarX(TCHAR *, int code)
+{
+ TCHAR szFullPath[MAX_PATH], szProfileName[MAX_PATH];
+ _tcscpy( szProfileName, g_profileName );
+ TCHAR *pos = _tcsrchr(szProfileName, '.');
+ if ( lstrcmp( pos, _T(".dat")) == 0 )
+ *pos = 0;
+
+ switch( code ) {
+ case 1:
+ mir_sntprintf(szFullPath, SIZEOF(szFullPath), _T("%s\\%s\\AvatarCache"), g_profileDir, szProfileName);
+ break;
+ case 2:
+ mir_sntprintf(szFullPath, SIZEOF(szFullPath), _T("%s\\%s\\Logs"), g_profileDir, szProfileName);
+ break;
+ case 3:
+ mir_sntprintf(szFullPath, SIZEOF(szFullPath), _T("%s\\%s"), g_profileDir, szProfileName);
+ break;
+ }
+ return mir_tstrdup( szFullPath );
+}
+#endif
+
+template<typename XCHAR>
+XCHAR *GetInternalVariable(XCHAR *key, size_t keyLength, HANDLE hContact)
+{
+ XCHAR *theValue = NULL;
+ XCHAR *theKey = (XCHAR *)_alloca(sizeof(XCHAR) * (keyLength + 1));
+ _xcsncpy(theKey, key, keyLength);
+ theKey[keyLength] = 0;
+
+ if (hContact) {
+ if (!_xcscmp(theKey, XSTR(key, "nick")))
+ theValue = GetContactNickX(key, hContact);
+ else if (!_xcscmp(theKey, XSTR(key, "proto")))
+ theValue = mir_a2x(key, (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact,0));
+ else if (!_xcscmp(theKey, XSTR(key, "userid")))
+ theValue = GetContactIDX(key, hContact);
+ }
+
+ if (!theValue) {
+ if (!_xcscmp(theKey, XSTR(key, "miranda_path")))
+ theValue = GetModulePathX(key, NULL);
+ else if (!_xcscmp(theKey, XSTR(key, "appdata")))
+ theValue = SHGetSpecialFolderPathX(CSIDL_APPDATA, theKey);
+ else if (!_xcscmp(theKey, XSTR(key, "mydocuments")))
+ theValue = SHGetSpecialFolderPathX(CSIDL_PERSONAL, theKey);
+ else if (!_xcscmp(theKey, XSTR(key, "desktop")))
+ theValue = SHGetSpecialFolderPathX(CSIDL_DESKTOPDIRECTORY, theKey);
+ else if (!_xcscmp(theKey, XSTR(key, "miranda_profile")))
+ theValue = GetProfileDirX(key);
+ else if (!_xcscmp(theKey, XSTR(key, "miranda_profilename")))
+ theValue = GetProfileNameX(key);
+ else if (!_xcscmp(theKey, XSTR(key, "username")))
+ theValue = GetUserNameX(key);
+ else if (!_xcscmp(theKey, XSTR(key, "miranda_avatarcache")))
+ theValue = GetPathVarX(key,1);
+ else if (!_xcscmp(theKey, XSTR(key, "miranda_logpath")))
+ theValue = GetPathVarX(key,2);
+ else if (!_xcscmp(theKey, XSTR(key, "miranda_userdata")))
+ theValue = GetPathVarX(key,3);
+ }
+
+ if (!theValue)
+ theValue = GetEnvironmentVariableX(theKey);
+
+ return theValue;
+}
+
+template<typename XCHAR>
+XCHAR *GetVariableFromArray(REPLACEVARSARRAY *vars, XCHAR *key, size_t keyLength, HANDLE hContact, bool *bFree)
+{
+ *bFree = false;
+ for (REPLACEVARSARRAY *var = vars; var && var->lptzKey; ++var)
+ if ((_xcslen((XCHAR *)var->lptzKey) == keyLength) && !_xcsncmp(key, (XCHAR *)var->lptzKey, keyLength))
+ return (XCHAR *)var->lptzValue;
+
+ *bFree = true;
+ return GetInternalVariable(key, keyLength, hContact);
+}
+
+template<typename XCHAR>
+XCHAR *ReplaceVariables(XCHAR *str, REPLACEVARSDATA *data)
+{
+ if (!str)
+ return NULL;
+
+ XCHAR *p;
+ XCHAR *varStart = 0;
+ size_t length = 0;
+ bool bFree;
+
+ for (p = str; *p; ++p) {
+ if (*p == '%') {
+ if (varStart) {
+ if (p == varStart)
+ length++;
+ else if (XCHAR *value = GetVariableFromArray(data->variables, varStart, p-varStart, data->hContact, &bFree)) {
+ length += _xcslen(value);
+ if (bFree) mir_free(value);
+ }
+ else // variable not found
+ length += p-varStart+2;
+
+ varStart = 0;
+ }
+ else varStart = p+1;
+ }
+ else if (!varStart)
+ length++;
+ }
+
+ XCHAR *result = (XCHAR *)mir_alloc(sizeof(XCHAR) * (length + 1));
+ XCHAR *q = result;
+ varStart = NULL;
+
+ for (p = str; *p; ++p) {
+ if (*p == '%') {
+ if (varStart) {
+ if (p == varStart)
+ *q++ = '%';
+ else if (XCHAR *value = GetVariableFromArray(data->variables, varStart, p-varStart, data->hContact, &bFree)) {
+ _xcscpy(q, value);
+ q += _xcslen(value);
+ if (bFree) mir_free(value);
+ }
+ else {
+ // variable not found
+ _xcsncpy(q, varStart-1, p-varStart+2);
+ q += p-varStart+2;
+ }
+ varStart = 0;
+ }
+ else varStart = p+1;
+ }
+ else if (!varStart)
+ *q++ = *p;
+ }
+
+ *q = 0;
+
+ return result;
+}
+
+static INT_PTR replaceVars(WPARAM wParam, LPARAM lParam)
+{
+ REPLACEVARSDATA *data = (REPLACEVARSDATA *)lParam;
+ if (!(data->dwFlags & RVF_UNICODE))
+ return (INT_PTR)ReplaceVariables<char>((char *)wParam, data);
+
+#ifdef _UNICODE
+ return (INT_PTR)ReplaceVariables<WCHAR>((WCHAR *)wParam, data);
+#else
+ return NULL;
+#endif
+}
+
+int InitPathUtils(void)
+{
+ char *p = 0;
+ GetModuleFileNameA(hMirandaInst, szMirandaPath, SIZEOF(szMirandaPath));
+ p = strrchr(szMirandaPath,'\\');
+ if ( p )
+ p[1] = 0;
+ mir_snprintf(szMirandaPathLower, MAX_PATH, "%s", szMirandaPath);
+ _strlwr(szMirandaPathLower);
+ CreateServiceFunction(MS_UTILS_PATHTORELATIVE, pathToRelative);
+ CreateServiceFunction(MS_UTILS_PATHTOABSOLUTE, pathToAbsolute);
+ CreateServiceFunction(MS_UTILS_CREATEDIRTREE, createDirTree);
+ CreateServiceFunction(MS_UTILS_REPLACEVARS, replaceVars);
+#ifdef _UNICODE
+ return InitPathUtilsW();
+#else
+ return 0;
+#endif
+}
diff --git a/src/modules/utils/resizer.cpp b/src/modules/utils/resizer.cpp
new file mode 100644
index 0000000000..ea0daa057a
--- /dev/null
+++ b/src/modules/utils/resizer.cpp
@@ -0,0 +1,152 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2009 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#include "commonheaders.h"
+
+typedef struct {
+ DWORD helpID;
+ DWORD exStyle;
+ DWORD style;
+ short x;
+ short y;
+ short cx;
+ short cy;
+ DWORD id;
+} START_OF_DLGITEMTEMPLATEEX;
+
+typedef struct {
+ WORD dlgVer;
+ WORD signature;
+ DWORD helpID;
+ DWORD exStyle;
+ DWORD style;
+ WORD cDlgItems;
+ short x;
+ short y;
+ short cx;
+ short cy;
+} START_OF_DLGTEMPLATEEX;
+
+INT_PTR ResizeDialog(WPARAM, LPARAM lParam)
+{
+ UTILRESIZEDIALOG *urd=(UTILRESIZEDIALOG*)lParam;
+ HDWP hDwp;
+ int i;
+ DLGITEMTEMPLATE *pItem = NULL;
+ START_OF_DLGITEMTEMPLATEEX *pItemEx = NULL;
+ RECT rc;
+ PWORD pWord;
+ DLGTEMPLATE *pTemplate;
+ START_OF_DLGTEMPLATEEX *pTemplateEx;
+ UTILRESIZECONTROL urc;
+ int procResult;
+ int extendedDlg,itemCount;
+
+ if(urd==NULL||urd->cbSize!=sizeof(UTILRESIZEDIALOG)) return 1;
+ pTemplate=(DLGTEMPLATE*)LockResource(LoadResource(urd->hInstance,FindResourceA(urd->hInstance,urd->lpTemplate,MAKEINTRESOURCEA(5))));
+ pTemplateEx=(START_OF_DLGTEMPLATEEX*)pTemplate;
+ extendedDlg=pTemplateEx->signature==0xFFFF;
+ if(extendedDlg && pTemplateEx->dlgVer!=1)
+ return 1;
+
+ if(extendedDlg) pWord=(PWORD)(pTemplateEx+1);
+ else pWord=(PWORD)(pTemplate+1);
+ if(*pWord==0xFFFF) pWord+=2; else while(*pWord++); //menu
+ if(*pWord==0xFFFF) pWord+=2; else while(*pWord++); //class
+ while(*pWord++); //title
+ if(extendedDlg) {
+ if(pTemplateEx->style&DS_SETFONT) {
+ pWord+=3; //font size,weight,italic
+ while(*pWord++); //font name
+ }
+ }
+ else {
+ if(pTemplate->style&DS_SETFONT) {
+ pWord++; //font size
+ while(*pWord++); //font name
+ }
+ }
+
+ urc.cbSize=sizeof(UTILRESIZECONTROL);
+ rc.left=0; rc.top=0;
+ if(extendedDlg) {rc.right=pTemplateEx->cx; rc.bottom=pTemplateEx->cy;}
+ else {rc.right=pTemplate->cx; rc.bottom=pTemplate->cy;}
+ MapDialogRect(urd->hwndDlg,&rc);
+ urc.dlgOriginalSize.cx=rc.right; urc.dlgOriginalSize.cy=rc.bottom;
+ GetClientRect(urd->hwndDlg,&rc);
+ urc.dlgNewSize.cx=rc.right; urc.dlgNewSize.cy=rc.bottom;
+
+ if(extendedDlg) itemCount=pTemplateEx->cDlgItems;
+ else itemCount=pTemplate->cdit;
+ hDwp=BeginDeferWindowPos(itemCount);
+ for(i=0;i<itemCount;i++) {
+ if((UINT_PTR)pWord&2) pWord++; //dword align
+
+ if(extendedDlg) {
+ pItemEx=(START_OF_DLGITEMTEMPLATEEX*)pWord;
+ pWord=(PWORD)(pItemEx+1);
+
+ urc.wId=pItemEx->id;
+ urc.rcItem.left=pItemEx->x; urc.rcItem.top=pItemEx->y;
+ urc.rcItem.right=urc.rcItem.left+pItemEx->cx; urc.rcItem.bottom=urc.rcItem.top+pItemEx->cy;
+ }
+ else {
+ pItem=(DLGITEMTEMPLATE*)pWord;
+ pWord=(PWORD)(pItem+1);
+
+ urc.wId=pItem->id;
+ urc.rcItem.left=pItem->x; urc.rcItem.top=pItem->y;
+ urc.rcItem.right=urc.rcItem.left+pItem->cx; urc.rcItem.bottom=urc.rcItem.top+pItem->cy;
+ }
+ if(*pWord==0xFFFF) pWord+=2; else while(*pWord++); //menu
+ if(*pWord==0xFFFF) pWord+=2; else while(*pWord++); //class
+ pWord+=1+(1+*pWord)/2; //creation data
+
+ if(urc.wId==65535) continue; //using this breaks the dwp, so just ignore it
+
+ MapDialogRect(urd->hwndDlg,&urc.rcItem);
+ procResult=(urd->pfnResizer)(urd->hwndDlg,urd->lParam,&urc);
+ if(procResult&RD_ANCHORX_RIGHT) {
+ urc.rcItem.left+=urc.dlgNewSize.cx-urc.dlgOriginalSize.cx;
+ urc.rcItem.right+=urc.dlgNewSize.cx-urc.dlgOriginalSize.cx;
+ }
+ else if(procResult&RD_ANCHORX_WIDTH)
+ urc.rcItem.right+=urc.dlgNewSize.cx-urc.dlgOriginalSize.cx;
+ else if(procResult&RD_ANCHORX_CENTRE) {
+ urc.rcItem.left+=(urc.dlgNewSize.cx-urc.dlgOriginalSize.cx)/2;
+ urc.rcItem.right+=(urc.dlgNewSize.cx-urc.dlgOriginalSize.cx)/2;
+ }
+ if(procResult&RD_ANCHORY_BOTTOM) {
+ urc.rcItem.top+=urc.dlgNewSize.cy-urc.dlgOriginalSize.cy;
+ urc.rcItem.bottom+=urc.dlgNewSize.cy-urc.dlgOriginalSize.cy;
+ }
+ else if(procResult&RD_ANCHORY_HEIGHT)
+ urc.rcItem.bottom+=urc.dlgNewSize.cy-urc.dlgOriginalSize.cy;
+ else if(procResult&RD_ANCHORY_CENTRE) {
+ urc.rcItem.top+=(urc.dlgNewSize.cy-urc.dlgOriginalSize.cy)/2;
+ urc.rcItem.bottom+=(urc.dlgNewSize.cy-urc.dlgOriginalSize.cy)/2;
+ }
+ hDwp = DeferWindowPos(hDwp,GetDlgItem(urd->hwndDlg,extendedDlg?pItemEx->id:pItem->id),0,urc.rcItem.left,urc.rcItem.top,urc.rcItem.right-urc.rcItem.left,urc.rcItem.bottom-urc.rcItem.top,SWP_NOZORDER);
+ }
+ EndDeferWindowPos(hDwp);
+ return 0;
+}
diff --git a/src/modules/utils/sha1.cpp b/src/modules/utils/sha1.cpp
new file mode 100644
index 0000000000..c89a60ca46
--- /dev/null
+++ b/src/modules/utils/sha1.cpp
@@ -0,0 +1,175 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is SHA 180-1 Reference Implementation (Compact version).
+ *
+ * The Initial Developer of the Original Code is
+ * Paul Kocher of Cryptography Research.
+ * Portions created by the Initial Developer are Copyright (C) 1995-9
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "commonheaders.h"
+
+static void shaHashBlock(mir_sha1_ctx *ctx);
+
+void shaInit(mir_sha1_ctx *ctx) {
+ int i;
+
+ ctx->lenW = 0;
+ ctx->sizeHi = ctx->sizeLo = 0;
+
+ /* Initialize H with the magic constants (see FIPS180 for constants)
+ */
+ ctx->H[0] = 0x67452301L;
+ ctx->H[1] = 0xefcdab89L;
+ ctx->H[2] = 0x98badcfeL;
+ ctx->H[3] = 0x10325476L;
+ ctx->H[4] = 0xc3d2e1f0L;
+
+ for (i = 0; i < 80; i++)
+ ctx->W[i] = 0;
+}
+
+
+void shaUpdate(mir_sha1_ctx *ctx, mir_sha1_byte_t *dataIn, int len) {
+ int i;
+
+ /* Read the data into W and process blocks as they get full
+ */
+ for (i = 0; i < len; i++) {
+ ctx->W[ctx->lenW / 4] <<= 8;
+ ctx->W[ctx->lenW / 4] |= (unsigned long)dataIn[i];
+ if ((++ctx->lenW) % 64 == 0) {
+ shaHashBlock(ctx);
+ ctx->lenW = 0;
+ }
+ ctx->sizeLo += 8;
+ ctx->sizeHi += (ctx->sizeLo < 8);
+ }
+}
+
+
+void shaFinal(mir_sha1_ctx *ctx, mir_sha1_byte_t hashout[20]) {
+ unsigned char pad0x80 = 0x80;
+ unsigned char pad0x00 = 0x00;
+ unsigned char padlen[8];
+ int i;
+
+ /* Pad with a binary 1 (e.g. 0x80), then zeroes, then length
+ */
+ padlen[0] = (unsigned char)((ctx->sizeHi >> 24) & 255);
+ padlen[1] = (unsigned char)((ctx->sizeHi >> 16) & 255);
+ padlen[2] = (unsigned char)((ctx->sizeHi >> 8) & 255);
+ padlen[3] = (unsigned char)((ctx->sizeHi >> 0) & 255);
+ padlen[4] = (unsigned char)((ctx->sizeLo >> 24) & 255);
+ padlen[5] = (unsigned char)((ctx->sizeLo >> 16) & 255);
+ padlen[6] = (unsigned char)((ctx->sizeLo >> 8) & 255);
+ padlen[7] = (unsigned char)((ctx->sizeLo >> 0) & 255);
+ shaUpdate(ctx, &pad0x80, 1);
+ while (ctx->lenW != 56)
+ shaUpdate(ctx, &pad0x00, 1);
+ shaUpdate(ctx, padlen, 8);
+
+ /* Output hash
+ */
+ for (i = 0; i < 20; i++) {
+ hashout[i] = (unsigned char)(ctx->H[i / 4] >> 24);
+ ctx->H[i / 4] <<= 8;
+ }
+
+ /*
+ * Re-initialize the context (also zeroizes contents)
+ */
+ shaInit(ctx);
+}
+
+
+void shaBlock(mir_sha1_byte_t *dataIn, int len, mir_sha1_byte_t hashout[20]) {
+ mir_sha1_ctx ctx;
+
+ shaInit(&ctx);
+ shaUpdate(&ctx, dataIn, len);
+ shaFinal(&ctx, hashout);
+}
+
+
+#define SHA_ROTL(X,n) (((X) << (n)) | ((X) >> (32-(n))))
+
+static void shaHashBlock(mir_sha1_ctx *ctx) {
+ int t;
+ unsigned long A,B,C,D,E,TEMP;
+
+ for (t = 16; t <= 79; t++)
+ ctx->W[t] =
+ SHA_ROTL(ctx->W[t-3] ^ ctx->W[t-8] ^ ctx->W[t-14] ^ ctx->W[t-16], 1);
+
+ A = ctx->H[0];
+ B = ctx->H[1];
+ C = ctx->H[2];
+ D = ctx->H[3];
+ E = ctx->H[4];
+
+ for (t = 0; t <= 19; t++) {
+ TEMP = SHA_ROTL(A,5) + (((C^D)&B)^D) + E + ctx->W[t] + 0x5a827999L;
+ E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP;
+ }
+ for (t = 20; t <= 39; t++) {
+ TEMP = SHA_ROTL(A,5) + (B^C^D) + E + ctx->W[t] + 0x6ed9eba1L;
+ E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP;
+ }
+ for (t = 40; t <= 59; t++) {
+ TEMP = SHA_ROTL(A,5) + ((B&C)|(D&(B|C))) + E + ctx->W[t] + 0x8f1bbcdcL;
+ E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP;
+ }
+ for (t = 60; t <= 79; t++) {
+ TEMP = SHA_ROTL(A,5) + (B^C^D) + E + ctx->W[t] + 0xca62c1d6L;
+ E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP;
+ }
+
+ ctx->H[0] += A;
+ ctx->H[1] += B;
+ ctx->H[2] += C;
+ ctx->H[3] += D;
+ ctx->H[4] += E;
+}
+
+INT_PTR GetSHA1Interface(WPARAM, LPARAM lParam)
+{
+ struct SHA1_INTERFACE *sha1i = (struct SHA1_INTERFACE*) lParam;
+ if ( sha1i == NULL )
+ return 1;
+ if ( sha1i->cbSize != sizeof( struct SHA1_INTERFACE ))
+ return 1;
+
+ sha1i->sha1_init = shaInit;
+ sha1i->sha1_append = shaUpdate;
+ sha1i->sha1_finish = shaFinal;
+ sha1i->sha1_hash = shaBlock;
+ return 0;
+}
diff --git a/src/modules/utils/timeutils.cpp b/src/modules/utils/timeutils.cpp
new file mode 100644
index 0000000000..a0d4c02e46
--- /dev/null
+++ b/src/modules/utils/timeutils.cpp
@@ -0,0 +1,277 @@
+/*
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2010 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+implements services to handle location - based timezones, instead of
+simple UTC offsets.
+*/
+
+#include "commonheaders.h"
+
+//KB167296
+void UnixTimeToFileTime(time_t ts, LPFILETIME pft)
+{
+ unsigned __int64 ll = UInt32x32To64(ts, 10000000) + 116444736000000000i64;
+ pft->dwLowDateTime = (DWORD)ll;
+ pft->dwHighDateTime = ll >> 32;
+}
+
+time_t FileTimeToUnixTime(LPFILETIME pft)
+{
+ unsigned __int64 ll = (unsigned __int64)pft->dwHighDateTime << 32 | pft->dwLowDateTime;
+ ll -= 116444736000000000i64;
+ return (time_t)(ll / 10000000);
+}
+
+void FormatTime(const SYSTEMTIME *st, const TCHAR *szFormat, TCHAR *szDest, int cbDest)
+{
+ if (szDest == NULL || cbDest == 0) return;
+
+ TCHAR *pDest = szDest;
+ int destCharsLeft = cbDest - 1;
+
+ for (const TCHAR* pFormat = szFormat; *pFormat; ++pFormat)
+ {
+ DWORD fmt;
+ bool date, iso = false;
+ switch (*pFormat)
+ {
+ case 't':
+ fmt = TIME_NOSECONDS;
+ date = false;
+ break;
+
+ case 's':
+ fmt = 0;
+ date = false;
+ break;
+
+ case 'm':
+ fmt = TIME_NOMINUTESORSECONDS;
+ date = false;
+ break;
+
+ case 'd':
+ fmt = DATE_SHORTDATE;
+ date = true;
+ break;
+
+ case 'D':
+ fmt = DATE_LONGDATE;
+ date = true;
+ break;
+
+ case 'I':
+ iso = true;
+ break;
+
+ default:
+ if (destCharsLeft--)
+ *pDest++ = *pFormat;
+ continue;
+ }
+
+ TCHAR dateTimeStr[64];
+ int dateTimeStrLen;
+
+ if (iso)
+ {
+ dateTimeStrLen = mir_sntprintf(dateTimeStr, SIZEOF(dateTimeStr),
+ _T("%d-%02d-%02dT%02d:%02d:%02dZ"),
+ st->wYear, st->wMonth, st->wDay,
+ st->wHour, st->wMinute, st->wSecond) + 1;
+ }
+ else if (date)
+ dateTimeStrLen = GetDateFormat(LOCALE_USER_DEFAULT, fmt, st, NULL,
+ dateTimeStr, SIZEOF(dateTimeStr));
+ else
+ dateTimeStrLen = GetTimeFormat(LOCALE_USER_DEFAULT, fmt, st, NULL,
+ dateTimeStr, SIZEOF(dateTimeStr));
+
+ if (dateTimeStrLen) --dateTimeStrLen;
+ if (destCharsLeft < dateTimeStrLen) dateTimeStrLen = destCharsLeft;
+ memcpy(pDest, dateTimeStr, dateTimeStrLen * sizeof(dateTimeStr[0]));
+ destCharsLeft -= dateTimeStrLen;
+ pDest += dateTimeStrLen;
+ }
+ *pDest = 0;
+}
+
+
+#ifndef _UNICODE
+void ConvertToAbsolute (const SYSTEMTIME * pstLoc, const SYSTEMTIME * pstDst, SYSTEMTIME * pstDstAbs)
+{
+ static int iDays [12] = { 31, 28, 31, 30, 31, 30,
+ 31, 31, 30, 31, 30, 31 } ;
+ int iDay ;
+
+ // Set up the aboluste date structure except for wDay, which we must find
+
+ pstDstAbs->wYear = pstLoc->wYear ; // Notice from local date/time
+ pstDstAbs->wMonth = pstDst->wMonth ;
+ pstDstAbs->wDayOfWeek = pstDst->wDayOfWeek ;
+
+ pstDstAbs->wHour = pstDst->wHour ;
+ pstDstAbs->wMinute = pstDst->wMinute ;
+ pstDstAbs->wSecond = pstDst->wSecond ;
+ pstDstAbs->wMilliseconds = pstDst->wMilliseconds ;
+
+ // Fix the iDays array for leap years
+
+ if ((pstLoc->wYear % 4 == 0) && ((pstLoc->wYear % 100 != 0) ||
+ (pstLoc->wYear % 400 == 0)))
+ {
+ iDays[1] = 29 ;
+ }
+
+ // Find a day of the month that falls on the same
+ // day of the week as the transition.
+
+ // Suppose today is the 20th of the month (pstLoc->wDay = 20)
+ // Suppose today is a Wednesday (pstLoc->wDayOfWeek = 3)
+ // Suppose the transition occurs on a Friday (pstDst->wDayOfWeek = 5)
+ // Then iDay = 31, meaning that the 31st falls on a Friday
+ // (The 7 is this formula avoids negatives.)
+
+ iDay = pstLoc->wDay + pstDst->wDayOfWeek + 7 - pstLoc->wDayOfWeek ;
+
+ // Now shrink iDay to a value between 1 and 7.
+
+ iDay = (iDay - 1) % 7 + 1 ;
+
+ // Now iDay is a day of the month ranging from 1 to 7.
+ // Recall that the wDay field of the structure can range
+ // from 1 to 5, 1 meaning "first", 2 meaning "second",
+ // and 5 meaning "last".
+ // So, increase iDay so it's the proper day of the month.
+
+ iDay += 7 * (pstDst->wDay - 1) ;
+
+ // Could be that iDay overshot the end of the month, so
+ // fix it up using the number of days in each month
+
+ if (iDay > iDays[pstDst->wMonth - 1])
+ iDay -= 7 ;
+
+ // Assign that day to the structure.
+
+ pstDstAbs->wDay = iDay ;
+}
+
+BOOL LocalGreaterThanTransition (const SYSTEMTIME * pstLoc, const SYSTEMTIME * pstTran)
+{
+ FILETIME ftLoc, ftTran ;
+ LARGE_INTEGER liLoc, liTran ;
+ SYSTEMTIME stTranAbs ;
+
+ // Easy case: Just compare the two months
+
+ if (pstLoc->wMonth != pstTran->wMonth)
+ return (pstLoc->wMonth > pstTran->wMonth) ;
+
+ // Well, we're in a transition month. That requires a bit more work.
+
+ // Check if pstDst is in absolute or day-in-month format.
+ // (See documentation of TIME_ZONE_INFORMATION, StandardDate field.)
+
+ if (pstTran->wYear) // absolute format (haven't seen one yet!)
+ {
+ stTranAbs = * pstTran ;
+ }
+ else // day-in-month format
+ {
+ ConvertToAbsolute (pstLoc, pstTran, &stTranAbs) ;
+ }
+
+ // Now convert both date/time structures to large integers & compare
+
+ SystemTimeToFileTime (pstLoc, &ftLoc) ;
+ liLoc = * (LARGE_INTEGER *) (void *) &ftLoc ;
+
+ SystemTimeToFileTime (&stTranAbs, &ftTran) ;
+ liTran = * (LARGE_INTEGER *) (void *) &ftTran ;
+
+ return (liLoc.QuadPart > liTran.QuadPart) ;
+}
+
+BOOL MySystemTimeToTzSpecificLocalTime(LPTIME_ZONE_INFORMATION ptzi, LPSYSTEMTIME pstUtc, LPSYSTEMTIME pstLoc)
+{
+ // st is UTC
+
+ FILETIME ft ;
+ LARGE_INTEGER li ;
+ SYSTEMTIME stDst ;
+
+ if (IsWinVerNT())
+ return SystemTimeToTzSpecificLocalTime(ptzi, pstUtc, pstLoc);
+
+ // Convert time to a LARGE_INTEGER and subtract the bias
+
+ SystemTimeToFileTime (pstUtc, &ft) ;
+ li = * (LARGE_INTEGER *) (void *) &ft;
+ li.QuadPart -= (LONGLONG) 600000000 * ptzi->Bias ;
+
+ // Convert to a local date/time before application of daylight saving time.
+ // The local date/time must be used to determine when the conversion occurs.
+
+ ft = * (FILETIME *) (void *) &li ;
+ FileTimeToSystemTime (&ft, pstLoc) ;
+
+ // Find the time assuming Daylight Saving Time
+
+ li.QuadPart -= (LONGLONG) 600000000 * ptzi->DaylightBias ;
+ ft = * (FILETIME *) (void *) &li ;
+ FileTimeToSystemTime (&ft, &stDst) ;
+
+ // Now put li back the way it was
+
+ li.QuadPart += (LONGLONG) 600000000 * ptzi->DaylightBias ;
+
+ if (ptzi->StandardDate.wMonth) // ie, daylight savings time
+ {
+ // Northern hemisphere
+ if ((ptzi->DaylightDate.wMonth < ptzi->StandardDate.wMonth) &&
+
+ (stDst.wMonth >= pstLoc->wMonth) && // avoid the end of year problem
+
+ LocalGreaterThanTransition (pstLoc, &ptzi->DaylightDate) &&
+ !LocalGreaterThanTransition (&stDst, &ptzi->StandardDate))
+ {
+ li.QuadPart -= (LONGLONG) 600000000 * ptzi->DaylightBias ;
+ }
+ // Southern hemisphere
+
+ else if ((ptzi->StandardDate.wMonth < ptzi->DaylightDate.wMonth) &&
+ (!LocalGreaterThanTransition (&stDst, &ptzi->StandardDate) ||
+ LocalGreaterThanTransition (pstLoc, &ptzi->DaylightDate)))
+ {
+ li.QuadPart -= (LONGLONG) 600000000 * ptzi->DaylightBias ;
+ }
+ else
+ {
+ li.QuadPart -= (LONGLONG) 600000000 * ptzi->StandardBias ;
+ }
+ }
+
+ ft = * (FILETIME *) (void *) &li ;
+ FileTimeToSystemTime (&ft, pstLoc) ;
+ return TRUE ;
+}
+#endif
diff --git a/src/modules/utils/timezones.cpp b/src/modules/utils/timezones.cpp
new file mode 100644
index 0000000000..7d22cbec1e
--- /dev/null
+++ b/src/modules/utils/timezones.cpp
@@ -0,0 +1,662 @@
+/*
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2010 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+implements services to handle location - based timezones, instead of
+simple UTC offsets.
+*/
+
+#include <commonheaders.h>
+
+TIME_API tmi;
+
+#if _MSC_VER < 1500
+ typedef struct _TIME_DYNAMIC_ZONE_INFORMATION_T {
+ LONG Bias;
+ WCHAR StandardName[ 32 ];
+ SYSTEMTIME StandardDate;
+ LONG StandardBias;
+ WCHAR DaylightName[ 32 ];
+ SYSTEMTIME DaylightDate;
+ LONG DaylightBias;
+ WCHAR TimeZoneKeyName[ 128 ];
+ BOOLEAN DynamicDaylightTimeDisabled;
+ } DYNAMIC_TIME_ZONE_INFORMATION;
+#endif
+
+typedef DWORD (WINAPI *pfnGetDynamicTimeZoneInformation_t)(DYNAMIC_TIME_ZONE_INFORMATION *pdtzi);
+static pfnGetDynamicTimeZoneInformation_t pfnGetDynamicTimeZoneInformation;
+
+typedef HRESULT (WINAPI *pfnSHLoadIndirectString_t)(LPCWSTR pszSource, LPWSTR pszOutBuf, UINT cchOutBuf, void **ppvReserved);
+static pfnSHLoadIndirectString_t pfnSHLoadIndirectString;
+
+typedef LANGID (WINAPI *pfnGetUserDefaultUILanguage_t)(void);
+static pfnGetUserDefaultUILanguage_t pfnGetUserDefaultUILanguage;
+
+typedef LANGID (WINAPI *pfnGetSystemDefaultUILanguage_t)(void);
+static pfnGetSystemDefaultUILanguage_t pfnGetSystemDefaultUILanguage;
+
+typedef LPARAM (WINAPI *pfnSendMessageW_t)(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
+static pfnSendMessageW_t pfnSendMessageW;
+
+typedef struct _REG_TZI_FORMAT
+{
+ LONG Bias;
+ LONG StandardBias;
+ LONG DaylightBias;
+ SYSTEMTIME StandardDate;
+ SYSTEMTIME DaylightDate;
+} REG_TZI_FORMAT;
+
+#define MIM_TZ_DISPLAYLEN 128
+
+struct MIM_TIMEZONE
+{
+ unsigned hash;
+ int offset;
+
+ TCHAR tszName[MIM_TZ_NAMELEN]; // windows name for the time zone
+ wchar_t szDisplay[MIM_TZ_DISPLAYLEN]; // more descriptive display name (that's what usually appears in dialogs)
+ // every hour should be sufficient.
+ TIME_ZONE_INFORMATION tzi;
+
+ static int compareBias(const MIM_TIMEZONE* p1, const MIM_TIMEZONE* p2)
+ { return p2->tzi.Bias - p1->tzi.Bias; }
+};
+
+typedef struct
+{
+ DWORD timestamp; // last time updated
+ MIM_TIMEZONE myTZ; // set to my own timezone
+} TZ_INT_INFO;
+
+static TZ_INT_INFO myInfo;
+bool muiInstalled;
+
+static OBJLIST<MIM_TIMEZONE> g_timezones(55, NumericKeySortT);
+static LIST<MIM_TIMEZONE> g_timezonesBias(55, MIM_TIMEZONE::compareBias);
+
+void FormatTime (const SYSTEMTIME *st, const TCHAR *szFormat, TCHAR *szDest, int cbDest);
+void UnixTimeToFileTime(time_t ts, LPFILETIME pft);
+time_t FileTimeToUnixTime(LPFILETIME pft);
+
+#ifdef _UNICODE
+#define fnSystemTimeToTzSpecificLocalTime SystemTimeToTzSpecificLocalTime
+#else
+BOOL MySystemTimeToTzSpecificLocalTime(LPTIME_ZONE_INFORMATION ptzi, LPSYSTEMTIME pstUtc, LPSYSTEMTIME pstLoc);
+#define fnSystemTimeToTzSpecificLocalTime MySystemTimeToTzSpecificLocalTime
+#endif
+
+
+static int timeapiGetTimeZoneTime(HANDLE hTZ, SYSTEMTIME *st)
+{
+ if (st == NULL) return 1;
+
+ MIM_TIMEZONE *tz = (MIM_TIMEZONE*)hTZ;
+ if (tz == UTC_TIME_HANDLE)
+ GetSystemTime(st);
+ else if (tz && tz != &myInfo.myTZ)
+ {
+ SYSTEMTIME sto;
+ GetSystemTime(&sto);
+ return !fnSystemTimeToTzSpecificLocalTime(&tz->tzi, &sto, st);
+ }
+ else
+ GetLocalTime(st);
+
+ return 0;
+}
+
+static LPCTSTR timeapiGetTzName(HANDLE hTZ)
+{
+ MIM_TIMEZONE *tz = (MIM_TIMEZONE*)hTZ;
+ if (tz == NULL)
+ return myInfo.myTZ.tszName;
+ else if (tz == UTC_TIME_HANDLE)
+ return _T("UTC");
+
+ return tz->tszName;
+}
+
+static void CalcTsOffset(MIM_TIMEZONE *tz)
+{
+ SYSTEMTIME st, stl;
+ GetSystemTime(&st);
+
+ FILETIME ft;
+ SystemTimeToFileTime(&st, &ft);
+ time_t ts1 = FileTimeToUnixTime(&ft);
+
+ if (!fnSystemTimeToTzSpecificLocalTime(&tz->tzi, &st, &stl))
+ return;
+
+ SystemTimeToFileTime(&stl, &ft);
+ time_t ts2 = FileTimeToUnixTime(&ft);
+
+ tz->offset = ts2 - ts1;
+}
+
+static bool IsSameTime(MIM_TIMEZONE *tz)
+{
+ SYSTEMTIME st, stl;
+
+ if (tz == &myInfo.myTZ)
+ return true;
+
+ timeapiGetTimeZoneTime(tz, &stl);
+ timeapiGetTimeZoneTime(NULL, &st);
+
+ return st.wHour == stl.wHour && st.wMinute == stl.wMinute;
+}
+
+static HANDLE timeapiGetInfoByName(LPCTSTR tszName, DWORD dwFlags)
+{
+ if (tszName == NULL)
+ return (dwFlags & (TZF_DIFONLY | TZF_KNOWNONLY)) ? NULL : &myInfo.myTZ;
+
+ if (_tcscmp(myInfo.myTZ.tszName, tszName) == 0)
+ return (dwFlags & TZF_DIFONLY) ? NULL : &myInfo.myTZ;
+
+ MIM_TIMEZONE tzsearch;
+ tzsearch.hash = hashstr(tszName);
+
+ MIM_TIMEZONE *tz = g_timezones.find(&tzsearch);
+ if (tz == NULL)
+ return (dwFlags & (TZF_DIFONLY | TZF_KNOWNONLY)) ? NULL : &myInfo.myTZ;
+
+ if (dwFlags & TZF_DIFONLY)
+ return IsSameTime(tz) ? NULL : tz;
+
+ return tz;
+}
+
+static HANDLE timeapiGetInfoByContact(HANDLE hContact, DWORD dwFlags)
+{
+ if (hContact == NULL)
+ return (dwFlags & (TZF_DIFONLY | TZF_KNOWNONLY)) ? NULL : &myInfo.myTZ;
+
+ DBVARIANT dbv;
+ if (!DBGetContactSettingTString(hContact, "UserInfo", "TzName", &dbv))
+ {
+ HANDLE res = timeapiGetInfoByName(dbv.ptszVal, dwFlags);
+ DBFreeVariant(&dbv);
+ if (res) return res;
+ }
+
+ signed char timezone = (signed char)DBGetContactSettingByte(hContact, "UserInfo", "Timezone", -1);
+ if (timezone == -1)
+ {
+ char* szProto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0);
+ if (!DBGetContactSettingTString(hContact, szProto, "TzName", &dbv))
+ {
+ HANDLE res = timeapiGetInfoByName(dbv.ptszVal, dwFlags);
+ DBFreeVariant(&dbv);
+ if (res) return res;
+ }
+ timezone = (signed char)DBGetContactSettingByte(hContact, szProto, "Timezone", -1);
+ }
+
+ if (timezone != -1)
+ {
+ MIM_TIMEZONE tzsearch;
+ tzsearch.tzi.Bias = timezone * 30;
+ if (myInfo.myTZ.tzi.Bias == tzsearch.tzi.Bias)
+ {
+ if (dwFlags & TZF_DIFONLY) return NULL;
+ return &myInfo.myTZ;
+ }
+
+ int i = g_timezonesBias.getIndex(&tzsearch);
+ while (i >= 0 && g_timezonesBias[i]->tzi.Bias == tzsearch.tzi.Bias) --i;
+
+ int delta = LONG_MAX;
+ for (int j = ++i; j < g_timezonesBias.getCount() && g_timezonesBias[j]->tzi.Bias == tzsearch.tzi.Bias; ++j)
+ {
+ int delta1 = abs(g_timezonesBias[j]->tzi.DaylightDate.wMonth - myInfo.myTZ.tzi.DaylightDate.wMonth);
+ if (delta1 <= delta)
+ {
+ delta = delta1;
+ i = j;
+ }
+ }
+
+ if (i >= 0)
+ {
+ MIM_TIMEZONE *tz = g_timezonesBias[i];
+ return ((dwFlags & TZF_DIFONLY) && IsSameTime(tz)) ? NULL : tz;
+ }
+ }
+ return (dwFlags & (TZF_DIFONLY | TZF_KNOWNONLY)) ? NULL : &myInfo.myTZ;
+}
+
+static void timeapiSetInfoByContact(HANDLE hContact, HANDLE hTZ)
+{
+ MIM_TIMEZONE *tz = (MIM_TIMEZONE*)hTZ;
+
+ if (hContact == NULL) return;
+
+ if (tz)
+ {
+ DBWriteContactSettingTString(hContact, "UserInfo", "TzName", tz->tszName);
+ DBWriteContactSettingByte(hContact, "UserInfo", "Timezone", (char)((tz->tzi.Bias + tz->tzi.StandardBias) / 30));
+ }
+ else
+ {
+ DBDeleteContactSetting(hContact, "UserInfo", "TzName");
+ DBDeleteContactSetting(hContact, "UserInfo", "Timezone");
+ }
+}
+
+static int timeapiPrintDateTime(HANDLE hTZ, LPCTSTR szFormat, LPTSTR szDest, int cbDest, DWORD dwFlags)
+{
+ MIM_TIMEZONE *tz = (MIM_TIMEZONE*)hTZ;
+ if (tz == NULL && (dwFlags & (TZF_DIFONLY | TZF_KNOWNONLY)))
+ return 1;
+
+ SYSTEMTIME st;
+ if (timeapiGetTimeZoneTime(tz, &st))
+ return 1;
+
+ FormatTime(&st, szFormat, szDest, cbDest);
+
+ return 0;
+}
+
+static int timeapiPrintTimeStamp(HANDLE hTZ, time_t ts, LPCTSTR szFormat, LPTSTR szDest, int cbDest, DWORD dwFlags)
+{
+ MIM_TIMEZONE *tz = (MIM_TIMEZONE*)hTZ;
+ if (tz == NULL && (dwFlags & (TZF_DIFONLY | TZF_KNOWNONLY)))
+ return 1;
+
+ FILETIME ft;
+
+ if (tz == NULL) tz = &myInfo.myTZ;
+ if (tz == NULL)
+ {
+ FILETIME lft;
+
+ UnixTimeToFileTime(ts, &lft);
+ FileTimeToLocalFileTime(&lft, &ft);
+ }
+ else if (tz == UTC_TIME_HANDLE)
+ UnixTimeToFileTime(ts, &ft);
+ else
+ {
+ if (tz->offset == INT_MIN)
+ CalcTsOffset(tz);
+
+ UnixTimeToFileTime(ts + tz->offset, &ft);
+ }
+
+ SYSTEMTIME st;
+ FileTimeToSystemTime(&ft, &st);
+
+ FormatTime(&st, szFormat, szDest, cbDest);
+
+ return 0;
+}
+
+static LPTIME_ZONE_INFORMATION timeapiGetTzi(HANDLE hTZ)
+{
+ MIM_TIMEZONE *tz = (MIM_TIMEZONE*)hTZ;
+ return tz ? &tz->tzi : &myInfo.myTZ.tzi;
+}
+
+
+static time_t timeapiTimeStampToTimeZoneTimeStamp(HANDLE hTZ, time_t ts)
+{
+ MIM_TIMEZONE *tz = (MIM_TIMEZONE*)hTZ;
+
+ if (tz == NULL) tz = &myInfo.myTZ;
+ if (tz == NULL)
+ {
+ FILETIME ft, lft;
+
+ UnixTimeToFileTime(ts, &ft);
+ FileTimeToLocalFileTime(&ft, &lft);
+ return FileTimeToUnixTime(&lft);
+ }
+ else if (tz == UTC_TIME_HANDLE)
+ return ts;
+
+ if (tz->offset == INT_MIN)
+ CalcTsOffset(tz);
+
+ return ts + tz->offset;
+}
+
+typedef struct
+{
+ UINT addStr, getSel, setSel, getData, setData;
+} ListMessages;
+
+static const ListMessages lbMessages =
+{ LB_ADDSTRING, LB_GETCURSEL, LB_SETCURSEL, LB_GETITEMDATA, LB_SETITEMDATA };
+
+static const ListMessages cbMessages =
+{ CB_ADDSTRING, CB_GETCURSEL, CB_SETCURSEL, CB_GETITEMDATA, CB_SETITEMDATA };
+
+static const ListMessages *GetListMessages(HWND hWnd, DWORD dwFlags)
+{
+ if (!(dwFlags & (TZF_PLF_CB | TZF_PLF_LB)))
+ {
+ TCHAR tszClassName[128];
+ GetClassName(hWnd, tszClassName, SIZEOF(tszClassName));
+ if (!_tcsicmp(tszClassName, _T("COMBOBOX")))
+ dwFlags |= TZF_PLF_CB;
+ else if(!_tcsicmp(tszClassName, _T("LISTBOX")))
+ dwFlags |= TZF_PLF_LB;
+ }
+ if (dwFlags & TZF_PLF_CB)
+ return & cbMessages;
+ else if(dwFlags & TZF_PLF_LB)
+ return & lbMessages;
+ else
+ return NULL;
+}
+
+
+static int timeapiSelectListItem(HANDLE hContact, HWND hWnd, DWORD dwFlags)
+{
+ if (hWnd == NULL) // nothing to do
+ return -1;
+
+ const ListMessages *lstMsg = GetListMessages(hWnd, dwFlags);
+ if (lstMsg == NULL) return -1;
+
+ int iSelection = 0;
+ if (hContact)
+ {
+ DBVARIANT dbv;
+ if (!DBGetContactSettingTString(hContact, "UserInfo", "TzName", &dbv))
+ {
+ unsigned hash = hashstr(dbv.ptszVal);
+ for (int i = 0; i < g_timezonesBias.getCount(); ++i)
+ {
+ if (hash == g_timezonesBias[i]->hash)
+ {
+ iSelection = i + 1;
+ break;
+ }
+ }
+ DBFreeVariant(&dbv);
+ }
+ }
+
+ SendMessage(hWnd, lstMsg->setSel, iSelection, 0);
+ return iSelection;
+}
+
+
+static int timeapiPrepareList(HANDLE hContact, HWND hWnd, DWORD dwFlags)
+{
+ if (hWnd == NULL) // nothing to do
+ return 0;
+
+ const ListMessages *lstMsg = GetListMessages(hWnd, dwFlags);
+ if (lstMsg == NULL) return 0;
+
+ SendMessage(hWnd, lstMsg->addStr, 0, (LPARAM)TranslateT("<unspecified>"));
+
+ for (int i = 0; i < g_timezonesBias.getCount(); ++i)
+ {
+ MIM_TIMEZONE *tz = g_timezonesBias[i];
+
+ if (pfnSendMessageW)
+ pfnSendMessageW(hWnd, lstMsg->addStr, 0, (LPARAM)tz->szDisplay);
+ else
+ SendMessage(hWnd, lstMsg->addStr, 0, (LPARAM)StrConvTu(tz->szDisplay));
+
+ SendMessage(hWnd, lstMsg->setData, i + 1, (LPARAM)tz);
+ }
+
+ return timeapiSelectListItem(hContact, hWnd, dwFlags);
+}
+
+
+static void timeapiStoreListResult(HANDLE hContact, HWND hWnd, DWORD dwFlags)
+{
+ const ListMessages *lstMsg = GetListMessages(hWnd, dwFlags);
+ if (lstMsg == NULL) return;
+
+ LRESULT offset = SendMessage(hWnd, lstMsg->getSel, 0, 0);
+ if (offset > 0)
+ {
+ MIM_TIMEZONE *tz = (MIM_TIMEZONE*)SendMessage(hWnd, lstMsg->getData, offset, 0);
+ if ((INT_PTR)tz != CB_ERR && tz != NULL)
+ timeapiSetInfoByContact(hContact, tz);
+ }
+ else
+ timeapiSetInfoByContact(hContact, NULL);
+}
+
+
+static INT_PTR GetTimeApi( WPARAM, LPARAM lParam )
+{
+ TIME_API* tmi = (TIME_API*)lParam;
+ if (tmi == NULL)
+ return FALSE;
+
+ if (tmi->cbSize != sizeof(TIME_API))
+ return FALSE;
+
+ tmi->createByName = timeapiGetInfoByName;
+ tmi->createByContact = timeapiGetInfoByContact;
+ tmi->storeByContact = timeapiSetInfoByContact;
+
+ tmi->printDateTime = timeapiPrintDateTime;
+ tmi->printTimeStamp = timeapiPrintTimeStamp;
+
+ tmi->prepareList = timeapiPrepareList;
+ tmi->selectListItem = timeapiSelectListItem;
+ tmi->storeListResults = timeapiStoreListResult;
+
+ tmi->getTimeZoneTime = timeapiGetTimeZoneTime;
+ tmi->timeStampToTimeZoneTimeStamp = timeapiTimeStampToTimeZoneTimeStamp;
+ tmi->getTzi = timeapiGetTzi;
+ tmi->getTzName = timeapiGetTzName;
+
+ return TRUE;
+}
+
+static INT_PTR TimestampToLocal(WPARAM wParam, LPARAM)
+{
+ return timeapiTimeStampToTimeZoneTimeStamp(NULL, (time_t)wParam);
+}
+
+static INT_PTR TimestampToStringT(WPARAM wParam, LPARAM lParam)
+{
+ DBTIMETOSTRINGT *tts = (DBTIMETOSTRINGT*)lParam;
+ if (tts == NULL) return 0;
+
+ timeapiPrintTimeStamp(NULL, (time_t)wParam, tts->szFormat, tts->szDest, tts->cbDest, 0);
+ return 0;
+}
+
+#ifdef _UNICODE
+static INT_PTR TimestampToStringA(WPARAM wParam, LPARAM lParam)
+{
+ DBTIMETOSTRING *tts = (DBTIMETOSTRING*)lParam;
+ if (tts == NULL) return 0;
+
+ TCHAR *szDest = (TCHAR*)alloca(tts->cbDest);
+ timeapiPrintTimeStamp(NULL, (time_t)wParam, StrConvT(tts->szFormat), szDest, tts->cbDest, 0);
+ WideCharToMultiByte(CP_ACP, 0, szDest, -1, tts->szDest, tts->cbDest, NULL, NULL);
+ return 0;
+}
+#endif
+
+void GetLocalizedString(HKEY hSubKey, const TCHAR *szName, wchar_t *szBuf, DWORD cbLen)
+{
+ szBuf[0] = 0;
+ if (muiInstalled)
+ {
+ TCHAR tszTempBuf[MIM_TZ_NAMELEN], tszName[30];
+ mir_sntprintf(tszName, SIZEOF(tszName), _T("MUI_%s"), szName);
+ DWORD dwLength = cbLen * sizeof(TCHAR);
+ if (ERROR_SUCCESS == RegQueryValueEx(hSubKey, tszName, NULL, NULL, (unsigned char *)tszTempBuf, &dwLength))
+ {
+ tszTempBuf[min(dwLength / sizeof(TCHAR), cbLen - 1)] = 0;
+ if (pfnSHLoadIndirectString)
+ pfnSHLoadIndirectString(StrConvU(tszTempBuf), szBuf, cbLen, NULL);
+ }
+ }
+ if (szBuf[0] == 0)
+ {
+ DWORD dwLength = cbLen * sizeof(wchar_t);
+
+#ifdef _UNICODE
+ RegQueryValueEx(hSubKey, szName, NULL, NULL, (unsigned char *)szBuf, &dwLength);
+ szBuf[min(dwLength / sizeof(TCHAR), cbLen - 1)] = 0;
+#else
+ char* szBufP = (char*)alloca(dwLength);
+ RegQueryValueEx(hSubKey, szName, NULL, NULL, (unsigned char *)szBufP, &dwLength);
+ szBufP[min(dwLength, cbLen * sizeof(wchar_t) - 1)] = 0;
+ MultiByteToWideChar(CP_ACP, 0, szBufP, -1, szBuf, cbLen);
+#endif
+ }
+}
+
+void RecalculateTime(void)
+{
+ GetTimeZoneInformation(&myInfo.myTZ.tzi);
+ myInfo.timestamp = time(NULL);
+ myInfo.myTZ.offset = INT_MIN;
+
+ bool found = false;
+ DYNAMIC_TIME_ZONE_INFORMATION dtzi;
+
+ if (pfnGetDynamicTimeZoneInformation && pfnGetDynamicTimeZoneInformation(&dtzi) != TIME_ZONE_ID_INVALID)
+ {
+ TCHAR *myTzKey = mir_u2t(dtzi.TimeZoneKeyName);
+ _tcscpy(myInfo.myTZ.tszName, myTzKey);
+ mir_free(myTzKey);
+ found = true;
+ }
+
+ for (int i = 0; i < g_timezones.getCount(); ++i)
+ {
+ MIM_TIMEZONE &tz = g_timezones[i];
+ if (tz.offset != INT_MIN) tz.offset = INT_MIN;
+
+ if (!found)
+ {
+ if (!wcscmp(tz.tzi.StandardName, myInfo.myTZ.tzi.StandardName) ||
+ !wcscmp(tz.tzi.DaylightName, myInfo.myTZ.tzi.DaylightName))
+ {
+ _tcscpy(myInfo.myTZ.tszName, tz.tszName);
+ found = true;
+ }
+ }
+ }
+}
+
+void InitTimeZones(void)
+{
+ REG_TZI_FORMAT tzi;
+ HKEY hKey;
+
+ const TCHAR *tszKey = IsWinVerNT() ?
+ _T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones") :
+ _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Time Zones");
+
+ /*
+ * use GetDynamicTimeZoneInformation() on Vista+ - this will return a structure with
+ * the registry key name, so finding our own time zone later will be MUCH easier for
+ * localized systems or systems with a MUI pack installed
+ */
+ if (IsWinVerVistaPlus())
+ pfnGetDynamicTimeZoneInformation = (pfnGetDynamicTimeZoneInformation_t)GetProcAddress(GetModuleHandle(_T("kernel32")), "GetDynamicTimeZoneInformation");
+
+ if (IsWinVer2000Plus())
+ {
+ pfnSHLoadIndirectString = (pfnSHLoadIndirectString_t)GetProcAddress(GetModuleHandle(_T("shlwapi")), "SHLoadIndirectString");
+ pfnGetSystemDefaultUILanguage = (pfnGetSystemDefaultUILanguage_t)GetProcAddress(GetModuleHandle(_T("kernel32")), "GetSystemDefaultUILanguage");
+ pfnGetUserDefaultUILanguage = (pfnGetUserDefaultUILanguage_t)GetProcAddress(GetModuleHandle(_T("kernel32")), "GetUserDefaultUILanguage");
+ muiInstalled = pfnSHLoadIndirectString && pfnGetSystemDefaultUILanguage() != pfnGetUserDefaultUILanguage();
+ }
+
+ pfnSendMessageW = (pfnSendMessageW_t)GetProcAddress(GetModuleHandle(_T("user32")), "SendMessageW");
+
+ if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, tszKey, 0, KEY_ENUMERATE_SUB_KEYS, &hKey))
+ {
+ DWORD dwIndex = 0;
+ HKEY hSubKey;
+ TCHAR tszName[MIM_TZ_NAMELEN];
+
+ DWORD dwSize = SIZEOF(tszName);
+ while (ERROR_NO_MORE_ITEMS != RegEnumKeyEx(hKey, dwIndex++, tszName, &dwSize, NULL, NULL, 0, NULL))
+ {
+ if (ERROR_SUCCESS == RegOpenKeyEx(hKey, tszName, 0, KEY_QUERY_VALUE, &hSubKey))
+ {
+ dwSize = sizeof(tszName);
+
+ DWORD dwLength = sizeof(tzi);
+ if (ERROR_SUCCESS != RegQueryValueEx(hSubKey, _T("TZI"), NULL, NULL, (unsigned char *)&tzi, &dwLength))
+ continue;
+
+ MIM_TIMEZONE *tz = new MIM_TIMEZONE;
+
+ tz->tzi.Bias = tzi.Bias;
+ tz->tzi.StandardDate = tzi.StandardDate;
+ tz->tzi.StandardBias = tzi.StandardBias;
+ tz->tzi.DaylightDate = tzi.DaylightDate;
+ tz->tzi.DaylightBias = tzi.DaylightBias;
+
+ _tcscpy(tz->tszName, tszName);
+ tz->hash = hashstr(tszName);
+ tz->offset = INT_MIN;
+
+ GetLocalizedString(hSubKey, _T("Display"), tz->szDisplay, SIZEOF(tz->szDisplay));
+ GetLocalizedString(hSubKey, _T("Std"), tz->tzi.StandardName, SIZEOF(tz->tzi.StandardName));
+ GetLocalizedString(hSubKey, _T("Dlt"), tz->tzi.DaylightName, SIZEOF(tz->tzi.DaylightName));
+
+ g_timezones.insert(tz);
+ g_timezonesBias.insert(tz);
+
+ RegCloseKey(hSubKey);
+ }
+ dwSize = SIZEOF(tszName);
+ }
+ RegCloseKey(hKey);
+ }
+
+ RecalculateTime();
+
+ CreateServiceFunction(MS_SYSTEM_GET_TMI, GetTimeApi);
+
+ CreateServiceFunction(MS_DB_TIME_TIMESTAMPTOLOCAL, TimestampToLocal);
+ CreateServiceFunction(MS_DB_TIME_TIMESTAMPTOSTRINGT, TimestampToStringT);
+#ifdef _UNICODE
+ CreateServiceFunction(MS_DB_TIME_TIMESTAMPTOSTRING, TimestampToStringA);
+#else
+ CreateServiceFunction(MS_DB_TIME_TIMESTAMPTOSTRING, TimestampToStringT);
+#endif
+
+
+ tmi.cbSize = sizeof(tmi);
+ GetTimeApi(0, (LPARAM)&tmi);
+}
+
+void UninitTimeZones(void)
+{
+ g_timezonesBias.destroy();
+ g_timezones.destroy();
+}
diff --git a/src/modules/utils/utf.cpp b/src/modules/utils/utf.cpp
new file mode 100644
index 0000000000..ad6683d2ed
--- /dev/null
+++ b/src/modules/utils/utf.cpp
@@ -0,0 +1,413 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2009 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+ Copyright 2000 Alexandre Julliard of Wine project
+ (UTF-8 conversion routines)
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include "commonheaders.h"
+
+/* number of following bytes in sequence based on first byte value (for bytes above 0x7f) */
+static const char utf8_length[128] =
+{
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x80-0x8f */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x90-0x9f */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xa0-0xaf */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xb0-0xbf */
+ 0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 0xc0-0xcf */
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 0xd0-0xdf */
+ 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, /* 0xe0-0xef */
+ 3,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0 /* 0xf0-0xff */
+};
+
+/* first byte mask depending on UTF-8 sequence length */
+static const unsigned char utf8_mask[4] = { 0x7f, 0x1f, 0x0f, 0x07 };
+
+/* minimum Unicode value depending on UTF-8 sequence length */
+static const unsigned int utf8_minval[4] = { 0x0, 0x80, 0x800, 0x10000 };
+
+
+/* get the next char value taking surrogates into account */
+static unsigned int getSurrogateValue(const wchar_t *src, unsigned int srclen)
+{
+ if (src[0] >= 0xd800 && src[0] <= 0xdfff) /* surrogate pair */
+ {
+ if (src[0] > 0xdbff || /* invalid high surrogate */
+ srclen <= 1 || /* missing low surrogate */
+ src[1] < 0xdc00 || src[1] > 0xdfff) /* invalid low surrogate */
+ return 0;
+ return 0x10000 + ((src[0] & 0x3ff) << 10) + (src[1] & 0x3ff);
+ }
+ return src[0];
+}
+
+/* query necessary dst length for src string */
+static int Ucs2toUtf8Len(const wchar_t *src, unsigned int srclen)
+{
+ int len;
+ unsigned int val;
+
+ for (len = 0; srclen; srclen--, src++)
+ {
+ if (*src < 0x80) /* 0x00-0x7f: 1 byte */
+ {
+ len++;
+ continue;
+ }
+ if (*src < 0x800) /* 0x80-0x7ff: 2 bytes */
+ {
+ len += 2;
+ continue;
+ }
+ if (!(val = getSurrogateValue(src, srclen)))
+ {
+ return -2;
+ }
+ if (val < 0x10000) /* 0x800-0xffff: 3 bytes */
+ len += 3;
+ else /* 0x10000-0x10ffff: 4 bytes */
+ {
+ len += 4;
+ src++;
+ srclen--;
+ }
+ }
+ return len;
+}
+
+int Ucs2toUtf8Len(const wchar_t *src)
+{
+ if ( src == 0 )
+ return 0;
+
+ return Ucs2toUtf8Len( src, (int)wcslen( src ));
+}
+
+/* wide char to UTF-8 string conversion */
+/* return -1 on dst buffer overflow, -2 on invalid input char */
+int Ucs2toUtf8(const wchar_t *src, int srclen, char *dst, int dstlen)
+{
+ int len;
+
+ for (len = dstlen; srclen; srclen--, src++)
+ {
+ WCHAR ch = *src;
+ unsigned int val;
+
+ if (ch < 0x80) /* 0x00-0x7f: 1 byte */
+ {
+ if (!len--) return -1; /* overflow */
+ *dst++ = ch;
+ continue;
+ }
+
+ if (ch < 0x800) /* 0x80-0x7ff: 2 bytes */
+ {
+ if ((len -= 2) < 0) return -1; /* overflow */
+ dst[1] = 0x80 | (ch & 0x3f);
+ ch >>= 6;
+ dst[0] = 0xc0 | ch;
+ dst += 2;
+ continue;
+ }
+
+ if (!(val = getSurrogateValue(src, srclen)))
+ {
+ return -2;
+ }
+
+ if (val < 0x10000) /* 0x800-0xffff: 3 bytes */
+ {
+ if ((len -= 3) < 0) return -1; /* overflow */
+ dst[2] = 0x80 | (val & 0x3f);
+ val >>= 6;
+ dst[1] = 0x80 | (val & 0x3f);
+ val >>= 6;
+ dst[0] = 0xe0 | val;
+ dst += 3;
+ }
+ else /* 0x10000-0x10ffff: 4 bytes */
+ {
+ if ((len -= 4) < 0) return -1; /* overflow */
+ dst[3] = 0x80 | (val & 0x3f);
+ val >>= 6;
+ dst[2] = 0x80 | (val & 0x3f);
+ val >>= 6;
+ dst[1] = 0x80 | (val & 0x3f);
+ val >>= 6;
+ dst[0] = 0xf0 | val;
+ dst += 4;
+ src++;
+ srclen--;
+ }
+ }
+ return dstlen - len;
+}
+
+/* helper for the various utf8 mbstowcs functions */
+static unsigned int decodeUtf8Char(unsigned char ch, const char **str, const char *strend)
+{
+ unsigned int len = utf8_length[ch-0x80];
+ unsigned int res = ch & utf8_mask[len];
+ const char *end = *str + len;
+
+ if (end > strend) return ~0;
+ switch(len)
+ {
+ case 3:
+ if ((ch = end[-3] ^ 0x80) >= 0x40) break;
+ res = (res << 6) | ch;
+ (*str)++;
+ case 2:
+ if ((ch = end[-2] ^ 0x80) >= 0x40) break;
+ res = (res << 6) | ch;
+ (*str)++;
+ case 1:
+ if ((ch = end[-1] ^ 0x80) >= 0x40) break;
+ res = (res << 6) | ch;
+ (*str)++;
+ if (res < utf8_minval[len]) break;
+ return res;
+ }
+ return ~0;
+}
+
+/* query necessary dst length for src string */
+static inline int Utf8toUcs2Len(const char *src, int srclen)
+{
+ int ret = 0;
+ unsigned int res;
+ const char *srcend = src + srclen;
+
+ while (src < srcend)
+ {
+ unsigned char ch = *src++;
+ if (ch < 0x80) /* special fast case for 7-bit ASCII */
+ {
+ ret++;
+ continue;
+ }
+ if ((res = decodeUtf8Char(ch, &src, srcend)) <= 0x10ffff)
+ {
+ if (res > 0xffff) ret++;
+ ret++;
+ }
+ else return -2; /* bad char */
+ /* otherwise ignore it */
+ }
+ return ret;
+}
+
+/* UTF-8 to wide char string conversion */
+/* return -1 on dst buffer overflow, -2 on invalid input char */
+int Utf8toUcs2(const char *src, int srclen, wchar_t *dst, int dstlen)
+{
+ unsigned int res;
+ const char *srcend = src + srclen;
+ wchar_t *dstend = dst + dstlen;
+
+ while ((dst < dstend) && (src < srcend))
+ {
+ unsigned char ch = *src++;
+ if (ch < 0x80) /* special fast case for 7-bit ASCII */
+ {
+ *dst++ = ch;
+ continue;
+ }
+ if ((res = decodeUtf8Char(ch, &src, srcend)) <= 0xffff)
+ {
+ *dst++ = res;
+ }
+ else if (res <= 0x10ffff) /* we need surrogates */
+ {
+ if (dst == dstend - 1) return -1; /* overflow */
+ res -= 0x10000;
+ *dst++ = 0xd800 | (res >> 10);
+ *dst++ = 0xdc00 | (res & 0x3ff);
+ }
+ else return -2; /* bad char */
+ /* otherwise ignore it */
+ }
+ if (src < srcend) return -1; /* overflow */
+ return dstlen - (dstend - dst);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Utf8Decode - converts UTF8-encoded string to the UCS2/MBCS format
+
+char* Utf8DecodeCP(char* str, int codepage, wchar_t** ucs2)
+{
+ int len;
+ bool needs_free = false;
+ wchar_t* tempBuf = NULL;
+ if ( ucs2 )
+ *ucs2 = NULL;
+
+ if (str == NULL)
+ return NULL;
+
+ len = (int)strlen(str);
+
+ if (len < 2) {
+ if (ucs2 != NULL) {
+ *ucs2 = tempBuf = (wchar_t*)mir_alloc((len + 1) * sizeof(wchar_t));
+ MultiByteToWideChar(codepage, 0, str, len, tempBuf, len);
+ tempBuf[len] = 0;
+ }
+ return str;
+ }
+
+ int destlen = Utf8toUcs2Len(str, len);
+ if (destlen < 0)
+ return NULL;
+
+ if (ucs2 == NULL) {
+ __try
+ {
+ tempBuf = (wchar_t*)alloca((destlen + 1) * sizeof(wchar_t));
+ }
+ __except(EXCEPTION_EXECUTE_HANDLER)
+ {
+ tempBuf = NULL;
+ needs_free = true;
+ }
+ }
+
+ if ( tempBuf == NULL ) {
+ tempBuf = (wchar_t*)mir_alloc((destlen + 1) * sizeof(wchar_t));
+ if ( tempBuf == NULL )
+ return NULL;
+ }
+
+ Utf8toUcs2(str, len, tempBuf, destlen);
+ tempBuf[destlen] = 0;
+ WideCharToMultiByte(codepage, 0, tempBuf, -1, str, len + 1, "?", NULL);
+
+ if (ucs2)
+ *ucs2 = tempBuf;
+ else if (needs_free)
+ mir_free(tempBuf);
+
+ return str;
+}
+
+char* Utf8Decode(char* str, wchar_t** ucs2)
+{
+ return Utf8DecodeCP(str, LangPackGetDefaultCodePage(), ucs2);
+}
+
+wchar_t* Utf8DecodeUcs2(const char* str)
+{
+ if (str == NULL)
+ return NULL;
+
+ int len = (int)strlen(str);
+
+ int destlen = Utf8toUcs2Len(str, len);
+ if (destlen < 0) return NULL;
+
+ wchar_t* ucs2 = (wchar_t*)mir_alloc((destlen + 1) * sizeof(wchar_t));
+ if (ucs2 == NULL) return NULL;
+
+ if (Utf8toUcs2(str, len, ucs2, destlen) >= 0)
+ {
+ ucs2[destlen] = 0;
+ return ucs2;
+ }
+
+ mir_free(ucs2);
+
+ return NULL;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Utf8Encode - converts MBCS string to the UTF8-encoded format
+
+char* Utf8EncodeCP(const char* src, int codepage)
+{
+ int len;
+ bool needs_free = false;
+ char* result = NULL;
+ wchar_t* tempBuf;
+
+ if (src == NULL)
+ return NULL;
+
+ len = (int)strlen(src);
+
+ __try
+ {
+ tempBuf = (wchar_t*)alloca((len + 1) * sizeof(wchar_t));
+ }
+ __except(EXCEPTION_EXECUTE_HANDLER)
+ {
+ tempBuf = (wchar_t*)mir_alloc((len + 1) * sizeof(wchar_t));
+ if (tempBuf == NULL) return NULL;
+ needs_free = true;
+ }
+
+ len = MultiByteToWideChar(codepage, 0, src, -1, tempBuf, len + 1);
+
+ int destlen = Ucs2toUtf8Len(tempBuf, len);
+ if (destlen >= 0)
+ {
+ result = (char*)mir_alloc(destlen + 1);
+ if (result)
+ {
+ Ucs2toUtf8(tempBuf, len, result, destlen);
+ result[destlen] = 0;
+ }
+ }
+
+ if (needs_free)
+ mir_free(tempBuf);
+
+ return result;
+}
+
+char* Utf8Encode(const char* src)
+{
+ return Utf8EncodeCP(src, LangPackGetDefaultCodePage());
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Utf8Encode - converts UCS2 string to the UTF8-encoded format
+
+char* Utf8EncodeUcs2(const wchar_t* src)
+{
+ if (src == NULL)
+ return NULL;
+
+ int len = (int)wcslen(src);
+
+ int destlen = Ucs2toUtf8Len(src, len);
+ if (destlen < 0) return NULL;
+
+ char* result = (char*)mir_alloc(destlen + 1);
+ if (result == NULL)
+ return NULL;
+
+ Ucs2toUtf8(src, len, result, destlen);
+ result[destlen] = 0;
+
+ return result;
+}
diff --git a/src/modules/utils/utils.cpp b/src/modules/utils/utils.cpp
new file mode 100644
index 0000000000..9e81b3084b
--- /dev/null
+++ b/src/modules/utils/utils.cpp
@@ -0,0 +1,587 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2009 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#include "commonheaders.h"
+
+INT_PTR ResizeDialog(WPARAM wParam,LPARAM lParam);
+int InitOpenUrl(void);
+int InitWindowList(void);
+void FreeWindowList(void);
+int InitHyperlink(void);
+int InitColourPicker(void);
+int InitBitmapFilter(void);
+void InitXmlApi(void);
+void InitTimeZones(void);
+void UninitTimeZones(void);
+
+INT_PTR GetMD5Interface(WPARAM, LPARAM);
+INT_PTR GetSHA1Interface(WPARAM, LPARAM);
+
+static BOOL bModuleInitialized = FALSE;
+
+static struct CountryListEntry countries[]={
+ {0 ,"Unspecified"},
+ {9999,"Other"},
+ {0xFFFF,"Unknown"},
+ {93 ,"Afghanistan"},
+ {355 ,"Albania"},
+ {213 ,"Algeria"},
+ {376 ,"Andorra"},
+ {244 ,"Angola"},
+ {1264,"Anguilla"}, /* change county code to NANP (from 101) */
+ {1268,"Antigua and Barbuda"}, /* change county code to NANP (from 1021) */
+// {5902,"Antilles"}, /* removed: it is not a country, it's a group of islands from diffrent countries (all are included in the list)*/
+ {54 ,"Argentina"},
+ {374 ,"Armenia"},
+ {297 ,"Aruba"},
+ {247 ,"Ascension Island"},
+ {61 ,"Australia"},
+ {6720 ,"Australia, Antarctic Territory"}, /* added country code 672(0)*/
+ {614 ,"Australia, Christmas Island"}, /* rename (from Christmas Island) and change to official county code 61(4) (from 672) */
+ {61891,"Australia, Cocos (Keeling) Islands"}, /* rename and change to official county code 61(891) (from 6102) */
+ {6723 ,"Australia, Norfolk Island"}, /* rename (from Norfolk Island) and change to official county code 672(3) (from 6722) */
+ {43 ,"Austria"},
+ {994 ,"Azerbaijan"},
+ {1242,"Bahamas"}, /* change county code to NANP (from 103) */
+ {973 ,"Bahrain"},
+ {880 ,"Bangladesh"},
+ {1246,"Barbados"}, /* change county code to NANP (from 103) */
+// {120 ,"Barbuda"}, /* removed: it is not a country and no special island, see Antigua and Barbuda*/
+ {375 ,"Belarus"},
+ {32 ,"Belgium"},
+ {501 ,"Belize"},
+ {229 ,"Benin"},
+ {1441,"Bermuda"}, /* change county code to NANP (from 105) */
+ {975 ,"Bhutan"},
+ {591 ,"Bolivia"},
+ {387 ,"Bosnia and Herzegovina"},
+ {267 ,"Botswana"},
+ {55 ,"Brazil"},
+ {673 ,"Brunei"},
+ {359 ,"Bulgaria"},
+ {226 ,"Burkina Faso"},
+ {257 ,"Burundi"},
+ {855 ,"Cambodia"},
+ {237 ,"Cameroon"},
+ {1002,"Canada"}, /* change county code to NANP (from 107 to virtual 1(002) -> reflect NANP*/
+ {238 ,"Cape Verde Islands"},
+ {1345,"Cayman Islands"}, /* change county code to NANP (from 108) */
+ {236 ,"Central African Republic"},
+ {235 ,"Chad"},
+ {56 ,"Chile, Republic of"},
+ {86 ,"China"},
+// {6101,"Cocos-Keeling Islands"}, /* removed (double): see Australia, Cocos (Keeling) Islands */
+ {57 ,"Colombia"},
+ {269 ,"Comoros"}, /* change county code (from 2691) */
+ {243 ,"Congo, Democratic Republic of (Zaire)"},
+ {242 ,"Congo, Republic of the"},
+ {682 ,"Cook Islands"},
+ {506 ,"Costa Rica"},
+ {225 ,"Cote d'Ivoire (Ivory Coast)"},
+ {385 ,"Croatia"},
+ {53 ,"Cuba"},
+ {357 ,"Greek, Republic of South Cyprus"}, /* rename coz Turkey, Republic of Northern Cyprus */
+ {420 ,"Czech Republic"},
+ {45 ,"Denmark"},
+ {246 ,"Diego Garcia"},
+ {253 ,"Djibouti"},
+ {1767,"Dominica"}, /* change county code to NANP (from 109) */
+ {1809,"Dominican Republic"}, /* change county code to NANP 809, 829, 849 (from 110) */
+ {593 ,"Ecuador"},
+ {20 ,"Egypt"},
+ {503 ,"El Salvador"},
+ {240 ,"Equatorial Guinea"},
+ {291 ,"Eritrea"},
+ {372 ,"Estonia"},
+ {251 ,"Ethiopia"},
+ {3883,"Europe"}, /* add county code +388 3 official European Telephony Numbering Space*/
+ {298 ,"Faeroe Islands"},
+ {500 ,"Falkland Islands"},
+ {679 ,"Fiji"},
+ {358 ,"Finland"},
+ {33 ,"France"},
+ {5901,"French Antilles"},
+ {594 ,"French Guiana"},
+ {689 ,"French Polynesia"},
+ {241 ,"Gabon"},
+ {220 ,"Gambia"},
+ {995 ,"Georgia"},
+ {49 ,"Germany"},
+ {233 ,"Ghana"},
+ {350 ,"Gibraltar"},
+ {30 ,"Greece"},
+ {299 ,"Greenland"},
+ {1473,"Grenada"}, /* change county code to NANP (from 111) */
+ {590 ,"Guadeloupe"},
+ {1671,"Guam, US Territory of"}, /* change county code to NANP (from 671) */
+ {502 ,"Guatemala"},
+ {224 ,"Guinea"},
+ {245 ,"Guinea-Bissau"},
+ {592 ,"Guyana"},
+ {509 ,"Haiti"},
+ {504 ,"Honduras"},
+ {852 ,"Hong Kong"},
+ {36 ,"Hungary"},
+ {354 ,"Iceland"},
+ {91 ,"India"},
+ {62 ,"Indonesia"},
+ {98 ,"Iran (Islamic Republic of)"},
+ {964 ,"Iraq"},
+ {353 ,"Ireland"},
+ {972 ,"Israel"},
+ {39 ,"Italy"},
+ {1876,"Jamaica"}, /* change county code to NANP (from 112) */
+ {81 ,"Japan"},
+ {962 ,"Jordan"},
+ {705 ,"Kazakhstan"},
+ {254 ,"Kenya"},
+ {686 ,"Kiribati"},
+ {850 ,"Korea, North"},
+ {82 ,"Korea, South"},
+ {965 ,"Kuwait"},
+ {996 ,"Kyrgyzstan"}, /* change county code (from 706) */
+ {856 ,"Laos"},
+ {371 ,"Latvia"},
+ {961 ,"Lebanon"},
+ {266 ,"Lesotho"},
+ {231 ,"Liberia"},
+ {218 ,"Libyan Arab Jamahiriya"},
+ {423 ,"Liechtenstein"}, /* change county code (from 4101) */
+ {370 ,"Lithuania"},
+ {352 ,"Luxembourg"},
+ {853 ,"Macau"},
+ {389 ,"Macedonia, Republic of"}, /* rename coz war */
+ {261 ,"Madagascar"},
+ {265 ,"Malawi"},
+ {60 ,"Malaysia"},
+ {960 ,"Maldives"},
+ {223 ,"Mali"},
+ {356 ,"Malta"},
+ {692 ,"Marshall Islands"},
+ {596 ,"Martinique"},
+ {222 ,"Mauritania"},
+ {230 ,"Mauritius"},
+ {262 ,"Mayotte Island"}, /* change county code coz bug (from 269) */
+ {52 ,"Mexico"},
+ {691 ,"Micronesia, Federated States of"},
+ {373 ,"Moldova, Republic of"},
+ {377 ,"Monaco"},
+ {976 ,"Mongolia"},
+ {1664,"Montserrat"}, /* change county code to NANP (from 113) */
+ {212 ,"Morocco"},
+ {258 ,"Mozambique"},
+ {95 ,"Myanmar"},
+ {264 ,"Namibia"},
+ {674 ,"Nauru"},
+ {977 ,"Nepal"},
+ {31 ,"Netherlands"},
+ {599 ,"Netherlands Antilles"}, /* dissolved 2010 */
+ {5995 ,"St. Maarten"}, /* add new country in 2010 (from Netherlands Antilles) */
+ {5999 ,"Curacao"}, /* add new country in 2010 (from Netherlands Antilles) */
+ {5997 ,"Netherlands (Bonaire Island)"}, /* add new Part of Netherlands in 2010 (from Netherlands Antilles) */
+ {59946,"Netherlands (Saba Island)"}, /* add new Part of Netherlands in 2010 (from Netherlands Antilles) */
+ {59938,"Netherlands (St. Eustatius Island)"}, /* add new Part of Netherlands in 2010 (from Netherlands Antilles) */
+ // {114 ,"Nevis"}, /* removed: it is not a country, it's part of Saint Kitts and Nevis*/
+ {687 ,"New Caledonia"},
+ {64 ,"New Zealand"},
+ {505 ,"Nicaragua"},
+ {227 ,"Niger"},
+ {234 ,"Nigeria"},
+ {683 ,"Niue"},
+ {1670,"Northern Mariana Islands, US Territory of"}, /* added NANP */
+ {47 ,"Norway"},
+ {968 ,"Oman"},
+ {92 ,"Pakistan"},
+ {680 ,"Palau"},
+ {507 ,"Panama"},
+ {675 ,"Papua New Guinea"},
+ {595 ,"Paraguay"},
+ {51 ,"Peru"},
+ {63 ,"Philippines"},
+ {48 ,"Poland"},
+ {351 ,"Portugal"},
+ {1939,"Puerto Rico"}, /* change county code to NANP 939, 787 (from 121) */
+ {974 ,"Qatar"},
+ {262 ,"Reunion Island"},
+ {40 ,"Romania"},
+// {6701,"Rota Island"}, /* removed: it is not a country it is part of Northern Mariana Islands, US Territory of */
+ {7 ,"Russia"},
+ {250 ,"Rwanda"},
+ {1684,"Samoa (USA)"}, /* rename (from American Samoa) change county code to NANP (from 684) */
+ {685 ,"Samoa, Western"}, /* rename (from Western Samoa) */
+ {290 ,"Saint Helena"},
+// {115 ,"Saint Kitts"}, /* removed: it is not a country it is part of Saint Kitts and Nevis*/
+ {1869,"Saint Kitts and Nevis"}, /* change county code to NANP (from 1141) */
+ {1758,"Saint Lucia"}, /* change county code to NANP (from 122) */
+ {508 ,"Saint Pierre and Miquelon"},
+ {1784,"Saint Vincent and the Grenadines"}, /* change county code to NANP (from 116) */
+// {670 ,"Saipan Island"}, /* removed: it is not a country it is part of Northern Mariana Islands, US Territory of */
+ {378 ,"San Marino"},
+ {239 ,"Sao Tome and Principe"},
+ {966 ,"Saudi Arabia"},
+ {442 ,"Scotland"},
+ {221 ,"Senegal"},
+ {248 ,"Seychelles"},
+ {232 ,"Sierra Leone"},
+ {65 ,"Singapore"},
+ {421 ,"Slovakia"},
+ {386 ,"Slovenia"},
+ {677 ,"Solomon Islands"},
+ {252 ,"Somalia"},
+ {27 ,"South Africa"},
+ {34 ,"Spain"},
+ {3492,"Spain, Canary Islands"}, /*rename and change county code to 34(92) spain + canary code*/
+ {94 ,"Sri Lanka"},
+ {249 ,"Sudan"},
+ {597 ,"Suriname"},
+ {268 ,"Swaziland"},
+ {46 ,"Sweden"},
+ {41 ,"Switzerland"},
+ {963 ,"Syrian Arab Republic"},
+ {886 ,"Taiwan"},
+ {992 ,"Tajikistan"}, /* change county code (from 708) */
+ {255 ,"Tanzania"},
+ {66 ,"Thailand"},
+// {6702,"Tinian Island"}, /* removed: it is not a country it is part of Northern Mariana Islands, US Territory of */
+ {670 ,"Timor, East"}, /* added (is part off Northern Mariana Islands but not US Territory*/
+ {228 ,"Togo"},
+ {690 ,"Tokelau"},
+ {676 ,"Tonga"},
+ {1868,"Trinidad and Tobago"}, /* change county code to NANP (from 1141) */
+ {216 ,"Tunisia"},
+ {90 ,"Turkey"},
+ {90392,"Turkey, Republic of Northern Cyprus"}, /* added (is diffrent from Greek part)*/
+ {993 ,"Turkmenistan"}, /* change county code (from 709) */
+ {1649,"Turks and Caicos Islands"}, /* change county code to NANP (from 118) */
+ {688 ,"Tuvalu"},
+ {256 ,"Uganda"},
+ {380 ,"Ukraine"},
+ {971 ,"United Arab Emirates"},
+ {44 ,"United Kingdom"},
+ {598 ,"Uruguay"},
+ {1 ,"USA"},
+ {998 ,"Uzbekistan"}, /* change county code (from 711) */
+ {678 ,"Vanuatu"},
+ {379 ,"Vatican City"},
+ {58 ,"Venezuela"},
+ {84 ,"Vietnam"},
+ {1284,"Virgin Islands (UK)"}, /* change county code to NANP (from 105) - rename coz Virgin Islands (USA) */
+ {1340,"Virgin Islands (USA)"}, /* change county code to NANP (from 123) */
+ {441 ,"Wales"},
+ {681 ,"Wallis and Futuna Islands"},
+ {967 ,"Yemen"},
+ {38 ,"Yugoslavia"}, /* added for old values like birth-country */
+ {381 ,"Serbia, Republic of"}, /* rename need (from Yugoslavia)*/
+ {383 ,"Kosovo, Republic of"}, /*change country code (from 3811), rename need (from Yugoslavia - Serbia) */
+ {382 ,"Montenegro, Republic of"}, /* rename need (from Yugoslavia - Montenegro) */
+ {260 ,"Zambia"},
+ {263 ,"Zimbabwe"},
+};
+
+static INT_PTR GetCountryByNumber(WPARAM wParam, LPARAM)
+{
+ int i;
+
+ for(i=0; i < SIZEOF(countries); i++ )
+ if((int)wParam==countries[i].id) return (INT_PTR)countries[i].szName;
+ return (INT_PTR)NULL;
+}
+
+static INT_PTR GetCountryList(WPARAM wParam,LPARAM lParam)
+{
+ *(int*)wParam = SIZEOF(countries);
+ *(struct CountryListEntry**)lParam=countries;
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static INT_PTR SaveWindowPosition(WPARAM, LPARAM lParam)
+{
+ SAVEWINDOWPOS *swp=(SAVEWINDOWPOS*)lParam;
+ WINDOWPLACEMENT wp;
+ char szSettingName[64];
+
+ wp.length=sizeof(wp);
+ GetWindowPlacement(swp->hwnd,&wp);
+ mir_snprintf(szSettingName, SIZEOF(szSettingName), "%sx", swp->szNamePrefix);
+ DBWriteContactSettingDword(swp->hContact,swp->szModule,szSettingName,wp.rcNormalPosition.left);
+ mir_snprintf(szSettingName, SIZEOF(szSettingName), "%sy", swp->szNamePrefix);
+ DBWriteContactSettingDword(swp->hContact,swp->szModule,szSettingName,wp.rcNormalPosition.top);
+ mir_snprintf(szSettingName, SIZEOF(szSettingName), "%swidth", swp->szNamePrefix);
+ DBWriteContactSettingDword(swp->hContact,swp->szModule,szSettingName,wp.rcNormalPosition.right-wp.rcNormalPosition.left);
+ mir_snprintf(szSettingName, SIZEOF(szSettingName), "%sheight", swp->szNamePrefix);
+ DBWriteContactSettingDword(swp->hContact,swp->szModule,szSettingName,wp.rcNormalPosition.bottom-wp.rcNormalPosition.top);
+ return 0;
+}
+
+
+static INT_PTR AssertInsideScreen(WPARAM wParam, LPARAM lParam)
+{
+ LPRECT rc = (LPRECT) wParam;
+ if (rc == NULL)
+ return -1;
+
+ RECT rcScreen;
+ SystemParametersInfo(SPI_GETWORKAREA, 0, &rcScreen, FALSE);
+
+ if (MyMonitorFromWindow)
+ {
+ if (MyMonitorFromRect(rc, MONITOR_DEFAULTTONULL))
+ return 0;
+
+ MONITORINFO mi = {0};
+ HMONITOR hMonitor = MyMonitorFromRect(rc, MONITOR_DEFAULTTONEAREST);
+ mi.cbSize = sizeof(mi);
+ if (MyGetMonitorInfo(hMonitor, &mi))
+ rcScreen = mi.rcWork;
+ }
+ else
+ {
+ RECT rcDest;
+ if (IntersectRect(&rcDest, &rcScreen, rc))
+ return 0;
+ }
+
+ if (rc->top >= rcScreen.bottom)
+ OffsetRect(rc, 0, rcScreen.bottom - rc->bottom);
+ else if (rc->bottom <= rcScreen.top)
+ OffsetRect(rc, 0, rcScreen.top - rc->top);
+ if (rc->left >= rcScreen.right)
+ OffsetRect(rc, rcScreen.right - rc->right, 0);
+ else if (rc->right <= rcScreen.left)
+ OffsetRect(rc, rcScreen.left - rc->left, 0);
+
+ return 1;
+}
+
+
+static INT_PTR RestoreWindowPosition(WPARAM wParam,LPARAM lParam)
+{
+ SAVEWINDOWPOS *swp=(SAVEWINDOWPOS*)lParam;
+ WINDOWPLACEMENT wp;
+ char szSettingName[64];
+ int x,y;
+
+ wp.length=sizeof(wp);
+ GetWindowPlacement(swp->hwnd,&wp);
+ mir_snprintf(szSettingName, SIZEOF(szSettingName), "%sx", swp->szNamePrefix);
+ x=DBGetContactSettingDword(swp->hContact,swp->szModule,szSettingName,-1);
+ mir_snprintf(szSettingName, SIZEOF(szSettingName), "%sy", swp->szNamePrefix);
+ y=(int)DBGetContactSettingDword(swp->hContact,swp->szModule,szSettingName,-1);
+ if(x==-1) return 1;
+ if(wParam&RWPF_NOSIZE) {
+ OffsetRect(&wp.rcNormalPosition,x-wp.rcNormalPosition.left,y-wp.rcNormalPosition.top);
+ }
+ else {
+ wp.rcNormalPosition.left=x;
+ wp.rcNormalPosition.top=y;
+ mir_snprintf(szSettingName, SIZEOF(szSettingName), "%swidth", swp->szNamePrefix);
+ wp.rcNormalPosition.right=wp.rcNormalPosition.left+DBGetContactSettingDword(swp->hContact,swp->szModule,szSettingName,-1);
+ mir_snprintf(szSettingName, SIZEOF(szSettingName), "%sheight", swp->szNamePrefix);
+ wp.rcNormalPosition.bottom=wp.rcNormalPosition.top+DBGetContactSettingDword(swp->hContact,swp->szModule,szSettingName,-1);
+ }
+ wp.flags=0;
+ if (wParam & RWPF_HIDDEN)
+ wp.showCmd = SW_HIDE;
+ if (wParam & RWPF_NOACTIVATE)
+ wp.showCmd = SW_SHOWNOACTIVATE;
+
+ if (!(wParam & RWPF_NOMOVE))
+ AssertInsideScreen((WPARAM) &wp.rcNormalPosition, 0);
+
+ SetWindowPlacement(swp->hwnd,&wp);
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static INT_PTR RestartMiranda(WPARAM, LPARAM)
+{
+ TCHAR mirandaPath[ MAX_PATH ], cmdLine[ 100 ];
+ PROCESS_INFORMATION pi;
+ STARTUPINFO si = { 0 };
+ si.cb = sizeof(si);
+ GetModuleFileName( NULL, mirandaPath, SIZEOF(mirandaPath));
+ mir_sntprintf( cmdLine, SIZEOF( cmdLine ), _T("/restart:%d"), GetCurrentProcessId());
+ CreateProcess( mirandaPath, cmdLine, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi );
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+typedef BOOL (APIENTRY *PGENRANDOM)( PVOID, ULONG );
+
+static INT_PTR GenerateRandom(WPARAM wParam, LPARAM lParam)
+{
+ if (wParam == 0 || lParam == 0) return 0;
+
+ PGENRANDOM pfnRtlGenRandom = NULL;
+ HMODULE hModule = GetModuleHandleA("advapi32");
+ if (hModule)
+ {
+ pfnRtlGenRandom = (PGENRANDOM)GetProcAddress(hModule, "SystemFunction036");
+ if (pfnRtlGenRandom)
+ {
+ if (!pfnRtlGenRandom((PVOID)lParam, wParam))
+ pfnRtlGenRandom = NULL;
+ }
+ }
+ if (pfnRtlGenRandom == NULL)
+ {
+ srand(GetTickCount());
+ unsigned short* buf = (unsigned short*)lParam;
+ for ( ; (long)(wParam-=2) >= 0; )
+ *(buf++) = (unsigned short)rand();
+ if (lParam < 0)
+ *(char*)buf = (char)(rand() & 0xFF);
+ }
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+#if defined( _UNICODE )
+char* __fastcall rtrim(char* str)
+{
+ if (str == NULL) return NULL;
+ char* p = strchr(str, 0);
+ while (--p >= str)
+ {
+ switch (*p)
+ {
+ case ' ': case '\t': case '\n': case '\r':
+ *p = 0; break;
+ default:
+ return str;
+ }
+ }
+ return str;
+}
+#endif
+
+TCHAR* __fastcall rtrim(TCHAR *str)
+{
+ if (str == NULL) return NULL;
+ TCHAR* p = _tcschr(str, 0);
+ while (--p >= str)
+ {
+ switch (*p)
+ {
+ case ' ': case '\t': case '\n': case '\r':
+ *p = 0; break;
+ default:
+ return str;
+ }
+ }
+ return str;
+}
+
+char* __fastcall ltrim(char* str)
+{
+ if (str == NULL) return NULL;
+ char* p = str;
+
+ for (;;)
+ {
+ switch (*p)
+ {
+ case ' ': case '\t': case '\n': case '\r':
+ ++p; break;
+ default:
+ memmove(str, p, strlen(p) + 1);
+ return str;
+ }
+ }
+}
+
+char* __fastcall ltrimp(char* str)
+{
+ if (str == NULL) return NULL;
+ char* p = str;
+
+ for (;;)
+ {
+ switch (*p)
+ {
+ case ' ': case '\t': case '\n': case '\r':
+ ++p; break;
+ default:
+ return p;
+ }
+ }
+}
+
+bool __fastcall wildcmp(char * name, char * mask)
+{
+ char * last='\0';
+ for(;; mask++, name++)
+ {
+ if(*mask != '?' && *mask != *name) break;
+ if(*name == '\0') return ((BOOL)!*mask);
+ }
+ if(*mask != '*') return FALSE;
+ for(;; mask++, name++)
+ {
+ while(*mask == '*')
+ {
+ last = mask++;
+ if(*mask == '\0') return ((BOOL)!*mask); /* true */
+ }
+ if(*name == '\0') return ((BOOL)!*mask); /* *mask == EOS */
+ if(*mask != '?' && *mask != *name) name -= (size_t)(mask - last) - 1, mask = last;
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+int LoadUtilsModule(void)
+{
+ bModuleInitialized = TRUE;
+
+ CreateServiceFunction(MS_UTILS_RESIZEDIALOG,ResizeDialog);
+ CreateServiceFunction(MS_UTILS_SAVEWINDOWPOSITION,SaveWindowPosition);
+ CreateServiceFunction(MS_UTILS_RESTOREWINDOWPOSITION,RestoreWindowPosition);
+ CreateServiceFunction(MS_UTILS_ASSERTINSIDESCREEN,AssertInsideScreen);
+ CreateServiceFunction(MS_UTILS_GETCOUNTRYBYNUMBER,GetCountryByNumber);
+ CreateServiceFunction(MS_UTILS_GETCOUNTRYLIST,GetCountryList);
+ CreateServiceFunction(MS_UTILS_GETRANDOM,GenerateRandom);
+ CreateServiceFunction(MS_SYSTEM_RESTART,RestartMiranda);
+ CreateServiceFunction(MS_SYSTEM_GET_MD5I,GetMD5Interface);
+ CreateServiceFunction(MS_SYSTEM_GET_SHA1I,GetSHA1Interface);
+ InitOpenUrl();
+ InitWindowList();
+ InitHyperlink();
+ InitColourPicker();
+ InitBitmapFilter();
+ InitXmlApi();
+ InitTimeZones();
+ return 0;
+}
+
+void UnloadUtilsModule(void)
+{
+ if ( !bModuleInitialized ) return;
+
+ FreeWindowList();
+ UninitTimeZones();
+}
diff --git a/src/modules/utils/windowlist.cpp b/src/modules/utils/windowlist.cpp
new file mode 100644
index 0000000000..b7ea59eb58
--- /dev/null
+++ b/src/modules/utils/windowlist.cpp
@@ -0,0 +1,101 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2009 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#include "commonheaders.h"
+
+static WINDOWLISTENTRY *windowList=NULL;
+static int windowListCount=0;
+static int nextWindowListId=1;
+
+static INT_PTR AllocWindowList(WPARAM, LPARAM)
+{
+ return nextWindowListId++;
+}
+
+static INT_PTR AddToWindowList(WPARAM, LPARAM lParam)
+{
+ windowList=(WINDOWLISTENTRY*)mir_realloc(windowList,sizeof(WINDOWLISTENTRY)*(windowListCount+1));
+ windowList[windowListCount++]=*(WINDOWLISTENTRY*)lParam;
+ return 0;
+}
+
+static INT_PTR RemoveFromWindowList(WPARAM wParam,LPARAM lParam)
+{
+ int i;
+ for(i=0;i<windowListCount;i++)
+ if(windowList[i].hwnd==(HWND)lParam && windowList[i].hList==(HANDLE)wParam) {
+ MoveMemory(&windowList[i],&windowList[i+1],sizeof(WINDOWLISTENTRY)*(windowListCount-i-1));
+ windowListCount--;
+ return 0;
+ }
+ return 1;
+}
+
+static INT_PTR FindInWindowList(WPARAM wParam,LPARAM lParam)
+{
+ int i;
+ for(i=0;i<windowListCount;i++)
+ if(windowList[i].hContact==(HANDLE)lParam && windowList[i].hList==(HANDLE)wParam)
+ return (INT_PTR)windowList[i].hwnd;
+ return (INT_PTR)(HWND)NULL;
+}
+
+static INT_PTR BroadcastToWindowList(WPARAM wParam,LPARAM lParam)
+{
+ int i;
+ MSG *msg=(MSG*)lParam;
+ for(i=0;i<windowListCount;i++)
+ if(windowList[i].hList==(HANDLE)wParam)
+ SendMessage(windowList[i].hwnd,msg->message,msg->wParam,msg->lParam);
+ return 0;
+}
+
+static INT_PTR BroadcastToWindowListAsync(WPARAM wParam,LPARAM lParam)
+{
+ int i;
+ MSG *msg=(MSG*)lParam;
+ for(i=0;i<windowListCount;i++)
+ if(windowList[i].hList==(HANDLE)wParam)
+ PostMessage(windowList[i].hwnd,msg->message,msg->wParam,msg->lParam);
+ return 0;
+}
+
+int InitWindowList(void)
+{
+ CreateServiceFunction(MS_UTILS_ALLOCWINDOWLIST,AllocWindowList);
+ CreateServiceFunction(MS_UTILS_ADDTOWINDOWLIST,AddToWindowList);
+ CreateServiceFunction(MS_UTILS_REMOVEFROMWINDOWLIST,RemoveFromWindowList);
+ CreateServiceFunction(MS_UTILS_BROADCASTTOWINDOWLIST,BroadcastToWindowList);
+ CreateServiceFunction(MS_UTILS_BROADCASTTOWINDOWLIST_ASYNC,BroadcastToWindowListAsync);
+ CreateServiceFunction(MS_UTILS_FINDWINDOWINLIST,FindInWindowList);
+ return 0;
+}
+
+void FreeWindowList(void)
+{
+ if ( windowList ) {
+ mir_free(windowList);
+ windowList = NULL;
+ }
+ windowListCount=0;
+ nextWindowListId=1;
+}