From 48540940b6c28bb4378abfeb500ec45a625b37b6 Mon Sep 17 00:00:00 2001 From: Vadim Dashevskiy Date: Tue, 15 May 2012 10:38:20 +0000 Subject: initial commit git-svn-id: http://svn.miranda-ng.org/main/trunk@2 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- src/modules/utils/bmpfilter.cpp | 242 ++++++++++++++ src/modules/utils/colourpicker.cpp | 107 ++++++ src/modules/utils/hyperlink.cpp | 274 +++++++++++++++ src/modules/utils/imgconv.cpp | 152 +++++++++ src/modules/utils/md5.cpp | 374 +++++++++++++++++++++ src/modules/utils/openurl.cpp | 228 +++++++++++++ src/modules/utils/path.cpp | 600 +++++++++++++++++++++++++++++++++ src/modules/utils/resizer.cpp | 152 +++++++++ src/modules/utils/sha1.cpp | 175 ++++++++++ src/modules/utils/timeutils.cpp | 277 ++++++++++++++++ src/modules/utils/timezones.cpp | 662 +++++++++++++++++++++++++++++++++++++ src/modules/utils/utf.cpp | 413 +++++++++++++++++++++++ src/modules/utils/utils.cpp | 587 ++++++++++++++++++++++++++++++++ src/modules/utils/windowlist.cpp | 101 ++++++ 14 files changed, 4344 insertions(+) create mode 100644 src/modules/utils/bmpfilter.cpp create mode 100644 src/modules/utils/colourpicker.cpp create mode 100644 src/modules/utils/hyperlink.cpp create mode 100644 src/modules/utils/imgconv.cpp create mode 100644 src/modules/utils/md5.cpp create mode 100644 src/modules/utils/openurl.cpp create mode 100644 src/modules/utils/path.cpp create mode 100644 src/modules/utils/resizer.cpp create mode 100644 src/modules/utils/sha1.cpp create mode 100644 src/modules/utils/timeutils.cpp create mode 100644 src/modules/utils/timezones.cpp create mode 100644 src/modules/utils/utf.cpp create mode 100644 src/modules/utils/utils.cpp create mode 100644 src/modules/utils/windowlist.cpp (limited to 'src/modules/utils') 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 + +#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 )¶m )) { + 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 + . 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 + 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 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 + +#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 +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 +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 +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 *)wParam, data); + +#ifdef _UNICODE + return (INT_PTR)ReplaceVariables((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;iid; + 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 + +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 g_timezones(55, NumericKeySortT); +static LIST 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("")); + + 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;imessage,msg->wParam,msg->lParam); + return 0; +} + +static INT_PTR BroadcastToWindowListAsync(WPARAM wParam,LPARAM lParam) +{ + int i; + MSG *msg=(MSG*)lParam; + for(i=0;imessage,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; +} -- cgit v1.2.3