1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2013 - TortoiseGit
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software Foundation,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include "GravatarPictureBox.h"
22 #include "MessageBox.h"
23 #include "UnicodeUtils.h"
25 #include "LoglistCommonResource.h"
28 static CString
CalcMD5(CString text
)
31 if (!CryptAcquireContext(&hProv
, nullptr, nullptr, PROV_RSA_FULL
, CRYPT_VERIFYCONTEXT
))
35 if (!CryptCreateHash(hProv
, CALG_MD5
, 0, 0, &hHash
))
37 CryptReleaseContext(hProv
, 0);
41 CStringA textA
= CUnicodeUtils::GetUTF8(text
);
42 if (!CryptHashData(hHash
, (LPBYTE
)textA
.GetBuffer(), textA
.GetLength(), 0))
44 CryptReleaseContext(hProv
, 0);
45 CryptDestroyHash(hHash
);
51 DWORD cbHash
= _countof(rgbHash
);
52 if (!CryptGetHashParam(hHash
, HP_HASHVAL
, rgbHash
, &cbHash
, 0))
54 for (DWORD i
= 0; i
< cbHash
; i
++)
56 BYTE hi
= rgbHash
[i
] >> 4;
57 BYTE lo
= rgbHash
[i
] & 0xf;
58 hash
.AppendChar(hi
+ (hi
> 9 ? 87 : 48));
59 hash
.AppendChar(lo
+ (lo
> 9 ? 87 : 48));
62 CryptDestroyHash(hHash
);
63 CryptReleaseContext(hProv
, 0);
67 BEGIN_MESSAGE_MAP(CGravatar
, CStatic
)
71 CGravatar::CGravatar()
73 , m_gravatarEvent(INVALID_HANDLE_VALUE
)
74 , m_gravatarThread(nullptr)
75 , m_gravatarExit(false)
76 , m_bEnableGravatar(false)
78 m_gravatarLock
.Init();
81 CGravatar::~CGravatar()
83 SafeTerminateGravatarThread();
84 m_gravatarLock
.Term();
86 CloseHandle(m_gravatarEvent
);
89 void CGravatar::Init()
91 if (m_bEnableGravatar
)
93 if (m_gravatarEvent
== INVALID_HANDLE_VALUE
)
94 m_gravatarEvent
= ::CreateEvent(nullptr, FALSE
, TRUE
, nullptr);
95 if (m_gravatarThread
== nullptr)
97 m_gravatarThread
= AfxBeginThread([] (LPVOID lpVoid
) -> UINT
{ ((CGravatar
*)lpVoid
)->GravatarThread(); return 0; }, this, THREAD_PRIORITY_BELOW_NORMAL
);
98 if (m_gravatarThread
== nullptr)
100 CMessageBox::Show(nullptr, IDS_ERR_THREADSTARTFAILED
, IDS_APPNAME
, MB_OK
| MB_ICONERROR
);
107 void CGravatar::LoadGravatar(CString email
)
109 if (m_gravatarThread
== nullptr)
114 m_gravatarLock
.Lock();
115 if (!m_filename
.IsEmpty())
118 m_gravatarLock
.Unlock();
122 m_gravatarLock
.Unlock();
126 m_gravatarLock
.Lock();
127 bool diff
= m_email
!= email
;
129 m_gravatarLock
.Unlock();
131 ::SetEvent(m_gravatarEvent
);
134 void CGravatar::GravatarThread()
136 CString gravatarBaseUrl
= CRegString(_T("Software\\TortoiseGit\\GravatarUrl"), _T("http://www.gravatar.com/avatar/%HASH%"));
137 CoInitialize(nullptr);
138 while (!m_gravatarExit
)
140 ::WaitForSingleObject(m_gravatarEvent
, INFINITE
);
141 while (!m_gravatarExit
)
143 m_gravatarLock
.Lock();
144 CString email
= m_email
;
145 m_gravatarLock
.Unlock();
150 m_gravatarLock
.Lock();
151 bool diff
= email
!= m_email
;
152 m_gravatarLock
.Unlock();
156 CString md5
= CalcMD5(email
);
160 CString gravatarUrl
= gravatarBaseUrl
;
161 gravatarUrl
.Replace(_T("%HASH%"), md5
);
163 GetTempPath(tempFile
);
165 if (PathFileExists(tempFile
))
167 m_filename
= tempFile
;
172 HRESULT res
= URLDownloadToFile(nullptr, gravatarUrl
, tempFile
, 0, nullptr);
173 m_gravatarLock
.Lock();
174 if (m_email
== email
&& res
== S_OK
)
176 HANDLE hFile
= CreateFile(tempFile
, FILE_READ_ATTRIBUTES
| FILE_WRITE_ATTRIBUTES
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
);
177 FILETIME creationTime
= {};
178 GetFileTime(hFile
, &creationTime
, nullptr, nullptr);
179 uint64_t delta
= 7 * 24 * 60 * 60 * 10000000LL;
180 DWORD low
= creationTime
.dwLowDateTime
;
181 creationTime
.dwLowDateTime
+= delta
& 0xffffffff;
182 creationTime
.dwHighDateTime
+= delta
>> 32;
183 if (creationTime
.dwLowDateTime
< low
)
184 creationTime
.dwHighDateTime
++;
185 SetFileTime(hFile
, &creationTime
, nullptr, nullptr);
187 m_filename
= tempFile
;
193 m_gravatarLock
.Unlock();
200 void CGravatar::SafeTerminateGravatarThread()
202 if (m_gravatarThread
)
204 ::SetEvent(m_gravatarEvent
);
205 m_gravatarThread
= nullptr;
209 void CGravatar::OnPaint()
213 GetClientRect(&rect
);
214 dc
.FillSolidRect(&rect
, GetSysColor(COLOR_BTNFACE
));
215 m_gravatarLock
.Lock();
216 CString filename
= m_filename
;
217 m_gravatarLock
.Unlock();
218 if (filename
.IsEmpty()) return;
220 picture
.Load(filename
.GetString());
221 picture
.Show(dc
, rect
);