Jelajahi Sumber

- show clip properties at bottom of the description window
- click on image to toggle real size and fit to screen
- maintain image aspect ratio when sizing images
- validate file transfers using md5

ScottBrogden 8 tahun lalu
induk
melakukan
82b6516a9e
20 mengubah file dengan 650 tambahan dan 52 penghapusan
  1. 10 0
      CP_Main.rc
  2. 8 0
      CP_Main.vcxproj
  3. 8 0
      CP_Main.vcxproj.filters
  4. 5 1
      Client.cpp
  5. 54 13
      FileRecieve.cpp
  6. 2 1
      FileRecieve.h
  7. 20 0
      FileSend.cpp
  8. 67 5
      ImageViewer.cpp
  9. 5 0
      ImageViewer.h
  10. 348 0
      Md5.cpp
  11. 34 0
      Md5.h
  12. 10 0
      Options.cpp
  13. 3 0
      Options.h
  14. 48 0
      QListCtrl.cpp
  15. 5 1
      Resource.h
  16. 2 1
      ServerDefines.h
  17. 12 6
      ToolTipEx.cpp
  18. 9 24
      ToolTipEx.h
  19. TEMPAT SAMPAH
      res/cursor2.cur
  20. TEMPAT SAMPAH
      res/cursor_zoom_in.cur

+ 10 - 0
CP_Main.rc

@@ -1433,6 +1433,16 @@ END
 IDR_CP_MAIN             REGISTRY                "CP_Main.rgs"
 
 
+/////////////////////////////////////////////////////////////////////////////
+//
+// Cursor
+//
+
+IDC_CURSOR_ZOOM_IN      CURSOR                  "res\\cursor_zoom_in.cur"
+
+IDC_CURSOR_ZOOM_OUT     CURSOR                  "res\\cursor2.cur"
+
+
 /////////////////////////////////////////////////////////////////////////////
 //
 // String Table

+ 8 - 0
CP_Main.vcxproj

@@ -593,6 +593,7 @@
     <ClCompile Include="HotKeys.cpp" />
     <ClCompile Include="ImageViewer.cpp" />
     <ClCompile Include="MainFrmThread.cpp" />
+    <ClCompile Include="Md5.cpp" />
     <ClCompile Include="MessagePumpThread.cpp" />
     <ClCompile Include="MyDropTarget.cpp" />
     <ClCompile Include="NTray.cpp" />
@@ -1891,6 +1892,7 @@
     <ClInclude Include="HotKeys.h" />
     <ClInclude Include="ImageViewer.h" />
     <ClInclude Include="MainFrmThread.h" />
+    <ClInclude Include="Md5.h" />
     <ClInclude Include="memdc.h" />
     <ClInclude Include="MessagePumpThread.h" />
     <ClInclude Include="MyDropTarget.h" />
@@ -2078,6 +2080,9 @@
     <None Include="res\CP_Main.ico" />
     <None Include="res\CP_Main.rc2" />
     <None Include="res\CP_MainDoc.ico" />
+    <None Include="res\cursor1.cur" />
+    <None Include="res\cursor2.cur" />
+    <None Include="res\cursor_zoom_in.cur" />
     <None Include="res\Ditto.ico" />
     <None Include="res\Ditto2_NoCopyCb.ico" />
     <None Include="res\DittoNew.ico" />
@@ -2223,6 +2228,9 @@
       <TypeLibraryName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(IntDir)$(ProjectName).tlb</TypeLibraryName>
     </Midl>
   </ItemGroup>
+  <ItemGroup>
+    <Image Include="res\icon3.ico" />
+  </ItemGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">
   </ImportGroup>

+ 8 - 0
CP_Main.vcxproj.filters

@@ -427,6 +427,7 @@
     <ClCompile Include="SymbolEdit.cpp">
       <Filter>source</Filter>
     </ClCompile>
+    <ClCompile Include="Md5.cpp" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="sqlite\CppSQLite3.h">
@@ -894,6 +895,7 @@
     <ClInclude Include="SymbolEdit.h">
       <Filter>header</Filter>
     </ClInclude>
+    <ClInclude Include="Md5.h" />
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="CP_Main.rc">
@@ -1357,6 +1359,9 @@
     <None Include="res\cog_28.png">
       <Filter>res</Filter>
     </None>
+    <None Include="res\cursor1.cur" />
+    <None Include="res\cursor_zoom_in.cur" />
+    <None Include="res\cursor2.cur" />
   </ItemGroup>
   <ItemGroup>
     <Filter Include="sqlite">
@@ -1389,4 +1394,7 @@
   <ItemGroup>
     <Midl Include="CP_Main.idl" />
   </ItemGroup>
+  <ItemGroup>
+    <Image Include="res\icon3.ico" />
+  </ItemGroup>
 </Project>

+ 5 - 1
Client.cpp

@@ -348,7 +348,7 @@ HGLOBAL CClient::RequestCopiedFiles(CClipFormat &HDropFormat, CString csIP, CStr
 		{
 			hReturn = Recieve.CreateCF_HDROPBuffer();
 		}
-		else if(lRet == FALSE)
+		else if(lRet == FALSE || lRet == MD5_MISMATCH)
 		{
 			if(pProgress != NULL && pProgress->Cancelled())
 			{
@@ -357,6 +357,10 @@ HGLOBAL CClient::RequestCopiedFiles(CClipFormat &HDropFormat, CString csIP, CStr
 			else	
 			{
 				csErrorString = _T("Error recieving files.");
+				if (lRet == MD5_MISMATCH)
+				{
+					csErrorString += _T(" MD5 Match Error.");
+				}
 			}
 		}
 

+ 54 - 13
FileRecieve.cpp

@@ -1,7 +1,3 @@
-// FileRecieve.cpp: implementation of the CFileRecieve class.
-//
-//////////////////////////////////////////////////////////////////////
-
 #include "stdafx.h"
 #include "cp_main.h"
 #include "FileRecieve.h"
@@ -9,6 +5,7 @@
 #include "shared/TextConvert.h"
 #include "Path.h"
 #include "UnicodeMacros.h"
+#include "Md5.h"
 
 
 #ifdef _DEBUG
@@ -33,6 +30,7 @@ long CFileRecieve::RecieveFiles(SOCKET sock, CString csIP, CFileTransferProgress
 	BOOL lRet = FALSE;
 	int nNumFiles = 0;
 	int nFilesRecieved = 0;
+	CString lastMd5;
 
 	m_pProgress = pProgress;
 	m_csRecievingFromIP = csIP;
@@ -78,7 +76,7 @@ long CFileRecieve::RecieveFiles(SOCKET sock, CString csIP, CFileTransferProgress
 
 			LogSendRecieveInfo(StrF(_T("START of recieving the file %s, size: %d, File %d of %d"), csFileName, lFileSize, nFilesRecieved, nNumFiles));
 
-			long lRecieveRet = RecieveFileData(lFileSize, csFileName);
+			long lRecieveRet = RecieveFileData(lFileSize, csFileName, lastMd5);
 			if(lRecieveRet == USER_CANCELED)
 			{
 				lRet = USER_CANCELED;
@@ -103,19 +101,51 @@ long CFileRecieve::RecieveFiles(SOCKET sock, CString csIP, CFileTransferProgress
 				Info.m_lParameter2 != 0 &&
 				m_RecievedFiles.GetCount() > 0)
 			{
-				FILETIME lastWriteTime;
-				lastWriteTime.dwLowDateTime = Info.m_lParameter1;
-				lastWriteTime.dwHighDateTime = Info.m_lParameter2;
+				bool md5Error = false;
+				CString fileName = m_RecievedFiles[m_RecievedFiles.GetCount() - 1];
 
-				HANDLE filename = CreateFile(m_RecievedFiles[m_RecievedFiles.GetCount() - 1], FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);				
-				if(filename != NULL)
+				if (strlen(Info.m_md5) > 0 &&
+					CGetSetOptions::GetCheckMd5OnFileTransfers())
+				{
+					CMd5 md5;
+					CStringA localMd5 = lastMd5;
+					CStringA remoteMd5 = Info.m_md5;
+
+					if (localMd5 != remoteMd5)
+					{
+						lRet = MD5_MISMATCH;
+						bBreak = true;
+						md5Error = true;
+						::DeleteFile(fileName);
+
+						LogSendRecieveInfo(StrF(_T("MD5 ERROR Receiving data_end for file: %s, local md5: %s remote md5: %s"), fileName, CTextConvert::MultiByteToUnicodeString(localMd5), CTextConvert::MultiByteToUnicodeString(remoteMd5)));
+					}
+					else
+					{
+						LogSendRecieveInfo(StrF(_T("Receiving data_end for file: %s, MD5 MATCH local md5: %s remote md5: %s"), fileName, CTextConvert::MultiByteToUnicodeString(localMd5), CTextConvert::MultiByteToUnicodeString(remoteMd5)));
+					}
+				}
+				else
 				{
-					SetFileTime(filename, NULL, NULL, &lastWriteTime);
+					LogSendRecieveInfo(StrF(_T("Not checking mdf on file transfer, either setting is off or md5 is not sent, md5 Passed In: %s, setting to check: %d"), CTextConvert::MultiByteToUnicodeString(Info.m_md5), CGetSetOptions::GetCheckMd5OnFileTransfers()));
+				}
+
+				if (md5Error == false)
+				{
+					FILETIME lastWriteTime;
+					lastWriteTime.dwLowDateTime = Info.m_lParameter1;
+					lastWriteTime.dwHighDateTime = Info.m_lParameter2;
+
+					HANDLE filename = CreateFile(fileName, FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+					if (filename != NULL)
+					{
+						SetFileTime(filename, NULL, NULL, &lastWriteTime);
+					}
 				}
 			}
 		}
 
-			break;
+		break;
 
 		case MyEnums::END:
 			bBreak = true;
@@ -133,7 +163,7 @@ long CFileRecieve::RecieveFiles(SOCKET sock, CString csIP, CFileTransferProgress
 	return lRet;
 }
 
-long CFileRecieve::RecieveFileData(ULONG lFileSize, CString csFileName)
+long CFileRecieve::RecieveFileData(ULONG lFileSize, CString csFileName, CString &md5String)
 {
 	CString csFile = CGetSetOptions::GetPath(PATH_REMOTE_FILES);
 	CreateDirectory(csFile, NULL);
@@ -158,6 +188,8 @@ long CFileRecieve::RecieveFileData(ULONG lFileSize, CString csFileName)
 	long lBytesNeeded = 0;
 	int nPercent = 0;
 	int nPrevPercent = 0;
+	CMd5 md5;
+	md5.MD5Init();
 
 	char *pBuffer = new char[CHUNK_WRITE_SIZE];
 	if(pBuffer == NULL)
@@ -166,6 +198,8 @@ long CFileRecieve::RecieveFileData(ULONG lFileSize, CString csFileName)
 		return FALSE;
 	}
 
+	BOOL calcMd5 = CGetSetOptions::GetCheckMd5OnFileTransfers();
+
 	BOOL bRet = FALSE;
 	while(true)
 	{
@@ -180,6 +214,11 @@ long CFileRecieve::RecieveFileData(ULONG lFileSize, CString csFileName)
 		
 		File.Write(pBuffer, lBytesNeeded);
 
+		if (calcMd5)
+		{
+			md5.MD5Update((unsigned char*)pBuffer, lBytesNeeded);
+		}
+
 		lBytesRead += lBytesNeeded;
 
 		if(lBytesRead >= lFileSize)
@@ -209,6 +248,8 @@ long CFileRecieve::RecieveFileData(ULONG lFileSize, CString csFileName)
 
 	File.Close();
 
+	md5String = md5.MD5FinalToString();
+
 	if(bRet)
 	{
 		m_RecievedFiles.Add(csFile);

+ 2 - 1
FileRecieve.h

@@ -4,6 +4,7 @@
 #include "FileTransferProgressDlg.h"
 
 #define USER_CANCELED -2
+#define MD5_MISMATCH -3
 
 class CFileRecieve
 {
@@ -20,7 +21,7 @@ public:
 	void AddFile(CString csFile)	{ m_RecievedFiles.Add(csFile); }
 
 protected:
-	long RecieveFileData(ULONG lFileSize, CString csFileName);
+	long RecieveFileData(ULONG lFileSize, CString csFileName, CString &md5String);
 
 protected:
 	CRecieveSocket m_Sock;

+ 20 - 0
FileSend.cpp

@@ -7,6 +7,7 @@
 #include "FileSend.h"
 #include "Server.h"
 #include "shared/TextConvert.h"
+#include "Md5.h"
 
 #include <shlwapi.h>
 
@@ -135,6 +136,12 @@ BOOL CFileSend::SendFile(CString csFile)
 			{
 				long lReadBytes = 0;
 				BOOL bError = FALSE;
+				CMd5 md5;
+				md5.MD5Init();
+
+				BOOL calcMd5 = CGetSetOptions::GetCheckMd5OnFileTransfers();
+
+				DWORD d = GetTickCount();
 				
 				do
 				{
@@ -146,9 +153,16 @@ BOOL CFileSend::SendFile(CString csFile)
 						bError = TRUE;
 						break;
 					}
+
+					if (calcMd5)
+					{
+						//md5.MD5Update((unsigned char *)pBuffer, lReadBytes);
+					}
 					
 				}while(lReadBytes >= CHUNK_WRITE_SIZE);
 				
+				DWORD end = GetTickCount() - d;
+
 				if(bError == FALSE)
 				{
 					Info.m_lParameter1 = 0;
@@ -164,6 +178,12 @@ BOOL CFileSend::SendFile(CString csFile)
 						Info.m_lParameter2 = lastWriteTime.dwHighDateTime;
 					}
 
+					
+					CStringA csMd5 = md5.MD5FinalToString();
+					strncpy(Info.m_md5, csMd5, sizeof(Info.m_md5));
+
+					LogSendRecieveInfo(StrF(_T("Sending data_end for file: %s, md5: %s"), csFile, CTextConvert::MultiByteToUnicodeString(csMd5)));
+
 					if(m_Send.SendCSendData(Info, MyEnums::DATA_END))
 						bRet = TRUE;
 				}

+ 67 - 5
ImageViewer.cpp

@@ -15,6 +15,7 @@ CImageViewer::CImageViewer()
 {
 	m_pBitmap = NULL;
 	m_scrollHelper.AttachWnd(this);
+	m_hoveringOverImage = false;
 }
 
 CImageViewer::~CImageViewer()
@@ -28,6 +29,8 @@ BEGIN_MESSAGE_MAP(CImageViewer, CWnd)
 	ON_WM_MOUSEWHEEL()
 	ON_WM_PAINT()
 	ON_WM_SIZE()
+	ON_WM_SETCURSOR()
+	ON_WM_LBUTTONUP()
 END_MESSAGE_MAP()
 
 BOOL CImageViewer::Create(CWnd* pParent)
@@ -105,25 +108,46 @@ void CImageViewer::OnPaint()
 
 		CBitmap *oldBitmap = MemDc.SelectObject(m_pBitmap);
 
-		int nWidth = CBitmapHelper::GetCBitmapWidth(*m_pBitmap);
-		int nHeight = CBitmapHelper::GetCBitmapHeight(*m_pBitmap);
+		int width = CBitmapHelper::GetCBitmapWidth(*m_pBitmap);
+		int height = CBitmapHelper::GetCBitmapHeight(*m_pBitmap);
 
 		if (CGetSetOptions::GetScaleImagesToDescWindow())
 		{
-			dc.StretchBlt(rect.left, rect.top, rect.Width(), rect.Height(), &MemDc, 0, 0, nWidth, nHeight, SRCCOPY);
+			double newWidth = rect.Width();
+			double newHeight = rect.Height();
+
+			if (width > 0 &&
+				height > 0 &&
+				rect.Width() > 0 &&
+				rect.Height() > 0)
+			{
+				float origAspect = (width / (float)height);
+				float newAspect = (rect.Width() / (float)rect.Height());
+
+				if (origAspect > newAspect)
+				{
+					newHeight = (rect.Width() * height) / width;
+				}
+				else
+				{
+					newWidth = (rect.Height() * width) / height;
+				}
+			}
+			
+			dc.StretchBlt(rect.left, rect.top, newWidth, newHeight, &MemDc, 0, 0, width, height, SRCCOPY);
 			//OutputDebugString(StrF(_T("scaling image, window size %d/%d, image %d/%d\n"), min(nWidth, rect.Width()), min(nHeight, rect.Height()), nWidth, nHeight));
 		}
 		else
 		{
 			CSize s = m_scrollHelper.GetScrollPos();
-			dc.BitBlt(rect.left, rect.top, nWidth, nHeight, &MemDc, s.cx, s.cy, SRCCOPY);
+			dc.BitBlt(rect.left, rect.top, width, height, &MemDc, s.cx, s.cy, SRCCOPY);
 		}
 
 		//dc.StretchBlt(rect.left, rect.top, rect.Width(), rect.Height(), &MemDc, 0, 0, nWidth, nHeight, SRCCOPY);
 
 		MemDc.SelectObject(oldBitmap);
 
-		rect.top += nHeight;
+		rect.top += height;
 	}
 	
 	// Cleanup
@@ -153,4 +177,42 @@ void CImageViewer::OnSize(UINT nType, int cx, int cy)
 	m_scrollHelper.OnSize(nType, cx, cy);
 }
 
+BOOL CImageViewer::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
+{
+	if (this->m_pBitmap &&
+		pWnd->m_hWnd == this->m_hWnd &&
+		nHitTest == HTCLIENT)
+	{
+		if (CGetSetOptions::GetScaleImagesToDescWindow())
+		{
+			::SetCursor(AfxGetApp()->LoadCursor(IDC_CURSOR_ZOOM_IN));
+		}
+		else
+		{
+			::SetCursor(AfxGetApp()->LoadCursor(IDC_CURSOR_ZOOM_OUT));
+		}
+
+		m_hoveringOverImage = true;
+
+		return TRUE;
+	}
+
+	m_hoveringOverImage = false;
+
+	return CWnd::OnSetCursor(pWnd, nHitTest, message);
+}
+
 
+void CImageViewer::OnLButtonUp(UINT nFlags, CPoint point)
+{
+	if (this->m_pBitmap &&
+		m_hoveringOverImage)
+	{
+		CGetSetOptions::SetScaleImagesToDescWindow(!CGetSetOptions::GetScaleImagesToDescWindow());
+		this->UpdateBitmapSize();
+		Invalidate();
+		return;
+	}
+
+	CWnd::OnLButtonUp(nFlags, point);
+}

+ 5 - 0
ImageViewer.h

@@ -19,6 +19,8 @@ public:
 
 	BOOL Create(CWnd* pParent);
 
+	bool m_hoveringOverImage;
+
 protected:
 	DECLARE_MESSAGE_MAP()
 
@@ -27,6 +29,9 @@ protected:
 	afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt);
 	afx_msg void OnSize(UINT nType, int cx, int cy);
 	afx_msg void OnPaint();
+public:
+	afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);
+	afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
 };
 
 

+ 348 - 0
Md5.cpp

@@ -0,0 +1,348 @@
+#include "Stdafx.h"
+#include ".\md5.h"
+
+CMd5::CMd5()
+{
+	// don't alloc buffer here, only on request
+	mp_s8ReadBuffer = 0;
+}
+
+CMd5::~CMd5()
+{
+	FreeBuffer();
+}
+
+void CMd5::FreeBuffer()
+{
+	if(mp_s8ReadBuffer) 
+		delete mp_s8ReadBuffer;
+}
+
+/*********************************************************************
+//
+//         calculate MD5 from a file of any size (also size = 0)
+//         returns "" on file error
+//
+/********************************************************************/
+
+char* CMd5::CalcMD5FromFile(const TCHAR *s8_Path)
+{
+	if(!mp_s8ReadBuffer) 
+	{
+		mp_s8ReadBuffer = new char[_ReadBufSize];
+	}
+
+	MD5Init();
+
+	// ++++++++++++ Read file block by block +++++++++++
+
+	HANDLE h_File = CreateFile(s8_Path, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
+
+	if (h_File == INVALID_HANDLE_VALUE)
+		return "";
+
+	int s32_Size = GetFileSize(h_File, 0);
+
+	while (s32_Size > 0)
+	{
+		unsigned long u32_Read = 0;
+		if (!ReadFile(h_File, mp_s8ReadBuffer, _ReadBufSize, &u32_Read, 0))
+		{
+			CloseHandle(h_File);
+			return "";
+		}
+
+		MD5Update((unsigned char*)mp_s8ReadBuffer, u32_Read);
+
+		s32_Size -= u32_Read;
+	};
+
+	CloseHandle(h_File);
+
+	// ++++++++++++ Signature --> String +++++++++++
+
+	return MD5FinalToString();
+}
+
+
+/*********************************************************************
+//
+//                calculate MD5 from a string
+//
+/********************************************************************/
+char* CMd5::CalcMD5FromString(const char *s8_Input)
+{
+	MD5Init();
+	MD5Update((unsigned char*)s8_Input, strlen(s8_Input));
+
+	return MD5FinalToString();
+}
+
+
+/*********************************************************************
+//
+//                           Calculation functions
+//
+/*********************************************************************
+/*
+* Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
+* initialization constants.
+*/
+void CMd5::MD5Init()
+{
+	ctx.buf[0] = 0x67452301;
+	ctx.buf[1] = 0xefcdab89;
+	ctx.buf[2] = 0x98badcfe;
+	ctx.buf[3] = 0x10325476;
+
+	ctx.bits[0] = 0;
+	ctx.bits[1] = 0;
+}
+
+/*
+* Update context to reflect the concatenation of another buffer full
+* of bytes.
+*/
+void CMd5::MD5Update(unsigned char *buf, unsigned len)
+{
+	unsigned long t;
+
+	/* Update bitcount */
+
+	t = ctx.bits[0];
+	if ((ctx.bits[0] = t + ((unsigned long) len << 3)) < t)
+		ctx.bits[1]++;  /* Carry from low to high */
+	ctx.bits[1] += len >> 29;
+
+	t = (t >> 3) & 0x3f;    /* Bytes already in shsInfo->data */
+
+	/* Handle any leading odd-sized chunks */
+
+	if (t) 
+	{
+		unsigned char *p = (unsigned char *) ctx.in + t;
+
+		t = 64 - t;
+		if (len < t) {
+			memcpy(p, buf, len);
+			return;
+		}
+		memcpy(p, buf, t);
+		CMd5::byteReverse(ctx.in, 16);
+		MD5Transform(ctx.buf, (unsigned long *) ctx.in);
+		buf += t;
+		len -= t;
+	}
+	/* Process data in 64-byte chunks */
+
+	while (len >= 64) 
+	{
+		memcpy(ctx.in, buf, 64);
+		CMd5::byteReverse(ctx.in, 16);
+		MD5Transform(ctx.buf, (unsigned long *) ctx.in);
+		buf += 64;
+		len -= 64;
+	}
+
+	/* Handle any remaining bytes of data. */
+
+	memcpy(ctx.in, buf, len);
+}
+
+/*
+* Convert signature to CString
+*/
+char* CMd5::MD5FinalToString()
+{
+	unsigned char signature[16];
+	MD5Final(signature);
+
+	ms8_MD5[0] = 0;
+	char s8_Temp[5];
+	for (int i=0; i<16; i++) 
+	{
+		sprintf(s8_Temp, "%02X", signature[i]);
+		strcat(ms8_MD5, s8_Temp);
+	}
+
+	return ms8_MD5;
+}
+
+
+/*
+* Final wrapup - pad to 64-byte boundary with the bit pattern 
+* 1 0* (64-bit count of bits processed, MSB-first)
+*/
+void CMd5::MD5Final(unsigned char digest[16])
+{
+	unsigned count;
+	unsigned char *p;
+
+	/* Compute number of bytes mod 64 */
+	count = (ctx.bits[0] >> 3) & 0x3F;
+
+	/* Set the first char of padding to 0x80.  This is safe since there is
+	always at least one byte free */
+	p = ctx.in + count;
+	*p++ = 0x80;
+
+	/* Bytes of padding needed to make 64 bytes */
+	count = 64 - 1 - count;
+
+	/* Pad out to 56 mod 64 */
+	if(count < 8) 
+	{
+		/* Two lots of padding:  Pad the first block to 64 bytes */
+		memset(p, 0, count);
+		CMd5::byteReverse(ctx.in, 16);
+		MD5Transform(ctx.buf, (unsigned long *) ctx.in);
+
+		/* Now fill the next block with 56 bytes */
+		memset(ctx.in, 0, 56);
+	} 
+	else 
+	{
+		/* Pad block to 56 bytes */
+		memset(p, 0, count - 8);
+	}
+	CMd5::byteReverse(ctx.in, 14);
+
+	/* Append length in bits and transform */
+	((unsigned long *) ctx.in)[14] = ctx.bits[0];
+	((unsigned long *) ctx.in)[15] = ctx.bits[1];
+
+	MD5Transform(ctx.buf, (unsigned long *) ctx.in);
+	CMd5::byteReverse((unsigned char *) ctx.buf, 4);
+	memcpy(digest, ctx.buf, 16);
+	memset(&ctx, 0, sizeof(MD5Context));        /* In case it's sensitive */
+}
+
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f, w, x, y, z, data, s) \
+	( w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x )
+
+/*
+* The core of the MD5 algorithm, this alters an existing MD5 hash to
+* reflect the addition of 16 longwords of new data.  MD5Update blocks
+* the data and converts bytes into longwords for this routine.
+*/
+void CMd5::MD5Transform(unsigned long buf[4], unsigned long in[16])
+{
+	register unsigned long a, b, c, d;
+
+	a = buf[0];
+	b = buf[1];
+	c = buf[2];
+	d = buf[3];
+
+	MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+	MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+	MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+	MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+	MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+	MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+	MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+	MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+	MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+	MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+	MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+	MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+	MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+	MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+	MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+	MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+	MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+	MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+	MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+	MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+	MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+	MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+	MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+	MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+	MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+	MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+	MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+	MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+	MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+	MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+	MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+	MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+	MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+	MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+	MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+	MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+	MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+	MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+	MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+	MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+	MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+	MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+	MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+	MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+	MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+	MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+	MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+	MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+	MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+	MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+	MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+	MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+	MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+	MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+	MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+	MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+	MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+	MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+	MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+	MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+	MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+	MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+	MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+	MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+	buf[0] += a;
+	buf[1] += b;
+	buf[2] += c;
+	buf[3] += d;
+}
+
+#ifdef sgi
+#define HIGHFIRST
+#endif
+
+#ifdef sun
+#define HIGHFIRST
+#endif
+
+
+#ifndef HIGHFIRST
+void CMd5::byteReverse(unsigned char *buf, unsigned longs)  
+{
+	// Nothing
+}
+#else
+// Note: this code is harmless on little-endian machines.
+void CMd5::byteReverse(unsigned char *buf, unsigned longs)
+{
+	unsigned long t;
+	do 
+	{
+		t = (unsigned long) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
+			((unsigned) buf[1] << 8 | buf[0]);
+		*(unsigned long *) buf = t;
+		buf += 4;
+	} while (--longs);
+}
+#endif

+ 34 - 0
Md5.h

@@ -0,0 +1,34 @@
+#pragma once
+
+#define _ReadBufSize 1000000
+
+class CMd5  
+{
+public:
+	char* CalcMD5FromString(const char *s8_Input);
+	char* CalcMD5FromFile(const TCHAR *s8_Path);
+
+	void MD5Init();
+	void MD5Update(unsigned char *buf, unsigned len);
+	char* MD5FinalToString();
+
+	void FreeBuffer();
+	CMd5();
+	virtual ~CMd5();
+
+private:
+	struct MD5Context 
+	{
+		unsigned long buf[4];
+		unsigned long bits[2];
+		unsigned char in[64];
+	};
+		
+	void MD5Final (unsigned char digest[16]);
+	void MD5Transform(unsigned long buf[4], unsigned long in[16]);
+	void byteReverse (unsigned char *buf, unsigned longs);
+
+	char *mp_s8ReadBuffer;
+	MD5Context ctx;
+	char   ms8_MD5[40]; // Output buffer
+};

+ 10 - 0
Options.cpp

@@ -2392,4 +2392,14 @@ BOOL CGetSetOptions::GetAdjustClipsForCRC()
 void CGetSetOptions::SetAdjustClipsForCRC(int val)
 {
 	SetProfileLong(_T("AdjustClipsForCRC"), val);
+}
+
+BOOL CGetSetOptions::GetCheckMd5OnFileTransfers()
+{
+	return GetProfileLong(_T("CheckMd5OnFileTransfers"), TRUE);
+}
+
+void CGetSetOptions::SetCheckMd5OnFileTransfers(int val)
+{
+	SetProfileLong(_T("CheckMd5OnFileTransfers"), val);
 }

+ 3 - 0
Options.h

@@ -540,6 +540,9 @@ public:
 
 	static BOOL GetAdjustClipsForCRC();
 	static void SetAdjustClipsForCRC(int val);
+
+	static BOOL GetCheckMd5OnFileTransfers();
+	static void SetCheckMd5OnFileTransfers(int val);
 };
 
 // global for easy access and for initialization of fast access variables

+ 48 - 0
QListCtrl.cpp

@@ -972,10 +972,58 @@ bool CQListCtrl::ShowFullDescription(bool bFromAuto, bool fromNextPrev)
 		m_pToolTip->SetClipId(clipId);
 		m_pToolTip->SetSearchText(m_searchText);
 
+		m_pToolTip->SetClipData(_T(""));
 		m_pToolTip->SetToolTipText(_T(""));  
 		m_pToolTip->SetRTFText("    ");
 		bool bSetPlainText = false;
 		CClipFormat Clip;
+
+
+		try
+		{
+			CppSQLite3Query q = theApp.m_db.execQueryEx(_T("SELECT lID, lDate, lastPasteDate, lDontAutoDelete, QuickPasteText, lShortCut, globalShortCut FROM Main WHERE lID = %d"), clipId);
+			if (q.eof() == false)
+			{
+				CString clipData;
+				COleDateTime time((time_t)q.getIntField(_T("lDate")));
+				clipData += "Added: " + time.Format();
+
+				COleDateTime modified((time_t)q.getIntField(_T("lastPasteDate")));
+				clipData += _T(" | Last Used: ") + modified.Format();
+
+				if (q.getIntField(_T("lDontAutoDelete")) > 0)
+				{
+					clipData += _T(" | Never Auto Delete");
+				}
+
+				CString csQuickPaste = q.getStringField(_T("QuickPasteText"));
+				if (csQuickPaste.IsEmpty() == FALSE)
+				{
+					clipData += _T(" | Quick Paste = ");
+					clipData += csQuickPaste;
+				}
+
+				int shortCut = q.getIntField(_T("lShortCut"));
+				if (shortCut > 0)
+				{
+					clipData += _T(" | ");
+					clipData += CHotKey::GetHotKeyDisplayStatic(shortCut);
+
+					BOOL globalShortCut = q.getIntField(_T("globalShortCut"));
+					if (globalShortCut)
+					{
+						clipData += _T(" - Global Shortcut Key");
+					}
+				}
+
+				m_pToolTip->SetClipData(clipData);
+			}
+		}
+		CATCH_SQLITE_EXCEPTION
+
+
+
+
 		
 		Clip.m_cfType = CF_UNICODETEXT;
 		if(GetClipData(nItem, Clip) && Clip.m_hgData)

+ 5 - 1
Resource.h

@@ -175,6 +175,10 @@
 #define cog_28                          316
 #define IDB_PNG13                       317
 #define Search_28                       317
+#define IDC_CURSOR1                     322
+#define IDC_CURSOR_ZOOM_IN              322
+#define IDC_CURSOR2                     323
+#define IDC_CURSOR_ZOOM_OUT             323
 #define IDC_PATH                        1000
 #define IDC_GET_PATH                    1001
 #define IDC_SELECT_SOUND                1002
@@ -666,7 +670,7 @@
 #ifdef APSTUDIO_INVOKED
 #ifndef APSTUDIO_READONLY_SYMBOLS
 #define _APS_3D_CONTROLS                     1
-#define _APS_NEXT_RESOURCE_VALUE        318
+#define _APS_NEXT_RESOURCE_VALUE        324
 #define _APS_NEXT_COMMAND_VALUE         32938
 #define _APS_NEXT_CONTROL_VALUE         2150
 #define _APS_NEXT_SYMED_VALUE           104

+ 2 - 1
ServerDefines.h

@@ -28,7 +28,8 @@ public:
 	CHAR				m_cDesc[250];
 	long				m_lParameter1;
 	long				m_lParameter2;
-	char				m_cExtra[50];
+	CHAR				m_md5[32];
+	char				m_cExtra[18];
 };
 
 class CDittoCF_HDROP

+ 12 - 6
ToolTipEx.cpp

@@ -32,11 +32,10 @@ CToolTipEx::CToolTipEx(): m_dwTextStyle(DT_EXPANDTABS | DT_EXTERNALLEADING |
 CToolTipEx::~CToolTipEx()
 {
     DELETE_BITMAP 
-
     m_Font.DeleteObject();
+	m_clipDataFont.DeleteObject();
 }
 
-
 BEGIN_MESSAGE_MAP(CToolTipEx, CWnd)
 //{{AFX_MSG_MAP(CToolTipEx)
 ON_WM_PAINT()
@@ -51,16 +50,12 @@ ON_WM_NCLBUTTONDOWN()
 ON_WM_NCMOUSEMOVE()
 ON_WM_NCLBUTTONUP()
 ON_WM_ERASEBKGND()
-
 ON_COMMAND(ID_FIRST_REMEMBERWINDOWPOSITION, &CToolTipEx::OnRememberwindowposition)
 ON_COMMAND(ID_FIRST_SIZEWINDOWTOCONTENT, &CToolTipEx::OnSizewindowtocontent)
 ON_COMMAND(ID_FIRST_SCALEIMAGESTOFITWINDOW, &CToolTipEx::OnScaleimagestofitwindow)
 ON_COMMAND(2, OnOptions)
 ON_WM_RBUTTONDOWN()
 ON_WM_SETFOCUS()
-
-
-
 ON_COMMAND(ID_FIRST_HIDEDESCRIPTIONWINDOWONM, &CToolTipEx::OnFirstHidedescriptionwindowonm)
 ON_COMMAND(ID_FIRST_WRAPTEXT, &CToolTipEx::OnFirstWraptext)
 ON_WM_WINDOWPOSCHANGING()
@@ -113,6 +108,13 @@ BOOL CToolTipEx::Create(CWnd *pParentWnd)
 	m_optionsButton.SetToolTipText(theApp.m_Language.GetString(_T("DescriptionOptionsTooltip"), _T("Description Options")));
 	m_optionsButton.ShowWindow(SW_SHOW);
 
+	m_clipDataStatic.Create(_T("some text"), WS_CHILD | WS_VISIBLE, CRect(0, 0, 0, 0), this, 3);
+
+	m_clipDataFont.CreateFont(-theApp.m_metrics.PointsToPixels(8), 0, 0, 0, 400, 0, 0, 0, DEFAULT_CHARSET, 3, 2, 1, 34, _T("Segoe UI"));
+	m_clipDataStatic.SetFont(&m_clipDataFont);
+	m_clipDataStatic.SetBkColor(g_Opt.m_Theme.DescriptionWindowBG());
+	m_clipDataStatic.SetTextColor(RGB(127, 127, 127));
+
 	m_saveWindowLockout = false;
 
     return TRUE;
@@ -222,6 +224,8 @@ BOOL CToolTipEx::Show(CPoint point)
 		}
 	}
 
+	m_clipDataStatic.SetWindowText(m_clipData);
+
 	m_saveWindowLockout = true;
 	MoveWindow(rect);
 	ShowWindow(SW_SHOWNA);
@@ -591,6 +595,8 @@ void CToolTipEx::OnSize(UINT nType, int cx, int cy)
 
 	m_optionsButton.MoveWindow(cr.left, cr.bottom + theApp.m_metrics.ScaleY(2), theApp.m_metrics.ScaleX(17), theApp.m_metrics.ScaleY(17));
 
+	m_clipDataStatic.MoveWindow(cr.left + theApp.m_metrics.ScaleX(19), cr.bottom + theApp.m_metrics.ScaleY(2), cr.Width() - cr.left + theApp.m_metrics.ScaleX(19), theApp.m_metrics.ScaleY(17));
+
 	this->Invalidate();
 	m_DittoWindow.DoSetRegion(this);
 

+ 9 - 24
ToolTipEx.h

@@ -1,19 +1,11 @@
-#if !defined(AFX_ToolTipEx_H__5796127D_8817_493F_ACA7_8741A6759DD3__INCLUDED_)
-#define AFX_ToolTipEx_H__5796127D_8817_493F_ACA7_8741A6759DD3__INCLUDED_
-
-#if _MSC_VER > 1000
 #pragma once
-#endif // _MSC_VER > 1000
-// ToolTipEx.h : header file
-//
+
 #include "RichEditCtrlEx.h"
 #include "WndEx.h"
 #include "DittoWindow.h"
 #include "GdipButton.h"
 #include "ImageViewer.h"
-/////////////////////////////////////////////////////////////////////////////
-// CToolTipEx window
-
+#include "GroupStatic.h"
 
 class CToolTipEx : public CWnd
 {
@@ -31,7 +23,6 @@ public:
 	BOOL Show(CPoint point);
 	BOOL Hide();
 	void SetToolTipText(const CString &csText);
-//	void SetRTFText(const CString &csRTF);
 	void SetRTFText(const char *pRTF);
 	void SetBitmap(CBitmap *pBitmap);
 	void SetNotifyWnd(CWnd *pNotify)		{ m_pNotifyWnd = pNotify;	}
@@ -42,6 +33,8 @@ public:
 	int GetClipId() { return m_clipId; }
 	void SetSearchText(CString text) { m_searchText = text; }
 
+	void SetClipData(CString data) { m_clipData = data; }
+
 // Overrides
 	// ClassWizard generated virtual function overrides
 	//{{AFX_VIRTUAL(CToolTipEx)
@@ -70,11 +63,11 @@ protected:
 	CScrollBar m_hScroll;
 	CDittoWindow m_DittoWindow;
 	CImageViewer m_imageViewer;
-
+	CGroupStatic m_clipDataStatic;
+	CString m_clipData;
+	CFont m_clipDataFont;
 	bool m_saveWindowLockout;
 
-	
-
 protected:
 	CString GetFieldFromString(CString ref, int nIndex, TCHAR ch);
 	BOOL SetLogFont(LPLOGFONT lpLogFont, BOOL bRedraw /*=TRUE*/);
@@ -107,15 +100,7 @@ public:
 	afx_msg void OnScaleimagestofitwindow();
 	afx_msg void OnRButtonDown(UINT nFlags, CPoint point);
 	afx_msg void OnSetFocus(CWnd* pOldWnd);
-	afx_msg void OnPaint();
-	
+	afx_msg void OnPaint();	
 	afx_msg void OnFirstHidedescriptionwindowonm();
 	afx_msg void OnFirstWraptext();
-};
-
-/////////////////////////////////////////////////////////////////////////////
-
-//{{AFX_INSERT_LOCATION}}
-// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
-
-#endif // !defined(AFX_ToolTipEx_H__5796127D_8817_493F_ACA7_8741A6759DD3__INCLUDED_)
+};

TEMPAT SAMPAH
res/cursor2.cur


TEMPAT SAMPAH
res/cursor_zoom_in.cur