Use a new 4096 bit RSA public key for update signing
[TortoiseGit.git] / src / TortoiseProc / CheckForUpdatesDlg.cpp
blobe7a35bf4587c39a8c4b59071aaec7a83b051e4e6
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2003-2008 - TortoiseSVN
4 // Copyright (C) 2008-2014 - TortoiseGit
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software Foundation,
18 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include "stdafx.h"
21 #include "TortoiseProc.h"
22 #include "LoglistCommonResource.h"
23 #include "..\version.h"
24 #include "MessageBox.h"
25 #include "CheckForUpdatesDlg.h"
26 #include "registry.h"
27 #include "AppUtils.h"
28 #include "TempFile.h"
29 #include "SmartHandle.h"
30 #include "SysInfo.h"
31 #include "PathUtils.h"
32 #include "DirFileEnum.h"
33 #include "UnicodeUtils.h"
34 #include "UpdateCrypto.h"
35 #include "Win7.h"
37 #define SIGNATURE_FILE_ENDING _T(".rsa.asc")
39 #define WM_USER_DISPLAYSTATUS (WM_USER + 1)
40 #define WM_USER_ENDDOWNLOAD (WM_USER + 2)
41 #define WM_USER_FILLCHANGELOG (WM_USER + 3)
43 IMPLEMENT_DYNAMIC(CCheckForUpdatesDlg, CStandAloneDialog)
44 CCheckForUpdatesDlg::CCheckForUpdatesDlg(CWnd* pParent /*=NULL*/)
45 : CStandAloneDialog(CCheckForUpdatesDlg::IDD, pParent)
46 , m_bShowInfo(FALSE)
47 , m_bForce(FALSE)
48 , m_bVisible(FALSE)
49 , m_pDownloadThread(NULL)
50 , m_bThreadRunning(FALSE)
51 , m_updateDownloader(nullptr)
53 m_sUpdateDownloadLink = _T("http://redir.tortoisegit.org/download");
56 CCheckForUpdatesDlg::~CCheckForUpdatesDlg()
60 void CCheckForUpdatesDlg::DoDataExchange(CDataExchange* pDX)
62 CStandAloneDialog::DoDataExchange(pDX);
63 DDX_Control(pDX, IDC_LINK, m_link);
64 DDX_Control(pDX, IDC_PROGRESSBAR, m_progress);
65 DDX_Control(pDX, IDC_LIST_DOWNLOADS, m_ctrlFiles);
66 DDX_Control(pDX, IDC_BUTTON_UPDATE, m_ctrlUpdate);
67 DDX_Control(pDX, IDC_LOGMESSAGE, m_cLogMessage);
70 BEGIN_MESSAGE_MAP(CCheckForUpdatesDlg, CStandAloneDialog)
71 ON_WM_TIMER()
72 ON_WM_WINDOWPOSCHANGING()
73 ON_WM_SETCURSOR()
74 ON_WM_DESTROY()
75 ON_BN_CLICKED(IDC_BUTTON_UPDATE, OnBnClickedButtonUpdate)
76 ON_MESSAGE(WM_USER_DISPLAYSTATUS, OnDisplayStatus)
77 ON_MESSAGE(WM_USER_ENDDOWNLOAD, OnEndDownload)
78 ON_MESSAGE(WM_USER_FILLCHANGELOG, OnFillChangelog)
79 ON_REGISTERED_MESSAGE(WM_TASKBARBTNCREATED, OnTaskbarBtnCreated)
80 END_MESSAGE_MAP()
82 BOOL CCheckForUpdatesDlg::OnInitDialog()
84 CStandAloneDialog::OnInitDialog();
85 CAppUtils::MarkWindowAsUnpinnable(m_hWnd);
87 CString temp;
88 temp.Format(IDS_CHECKNEWER_YOURVERSION, TGIT_VERMAJOR, TGIT_VERMINOR, TGIT_VERMICRO, TGIT_VERBUILD);
89 SetDlgItemText(IDC_YOURVERSION, temp);
91 DialogEnableWindow(IDOK, FALSE);
93 m_pTaskbarList.Release();
94 if (FAILED(m_pTaskbarList.CoCreateInstance(CLSID_TaskbarList)))
95 m_pTaskbarList = nullptr;
97 // hide download controls
98 m_ctrlFiles.ShowWindow(SW_HIDE);
99 GetDlgItem(IDC_GROUP_DOWNLOADS)->ShowWindow(SW_HIDE);
100 RECT rectWindow, rectGroupDownloads, rectOKButton;
101 GetWindowRect(&rectWindow);
102 GetDlgItem(IDC_GROUP_DOWNLOADS)->GetWindowRect(&rectGroupDownloads);
103 GetDlgItem(IDOK)->GetWindowRect(&rectOKButton);
104 LONG bottomDistance = rectWindow.bottom - rectOKButton.bottom;
105 OffsetRect(&rectOKButton, 0, rectGroupDownloads.top - rectOKButton.top);
106 rectWindow.bottom = rectOKButton.bottom + bottomDistance;
107 MoveWindow(&rectWindow);
108 ::MapWindowPoints(NULL, GetSafeHwnd(), (LPPOINT)&rectOKButton, 2);
109 GetDlgItem(IDOK)->MoveWindow(&rectOKButton);
111 temp.LoadString(IDS_STATUSLIST_COLFILE);
112 m_ctrlFiles.InsertColumn(0, temp, 0, -1);
113 m_ctrlFiles.InsertColumn(1, temp, 0, -1);
114 m_ctrlFiles.SetExtendedStyle(LVS_EX_DOUBLEBUFFER | LVS_EX_CHECKBOXES);
115 m_ctrlFiles.SetColumnWidth(0, 350);
116 m_ctrlFiles.SetColumnWidth(1, 200);
118 ProjectProperties pp;
119 pp.SetCheckRe(_T("[Ii]ssues?:?(\\s*(,|and)?\\s*#?\\d+)+"));
120 pp.SetBugIDRe(_T("(\\d+)"));
121 pp.lProjectLanguage = -1;
122 pp.sUrl = _T("http://code.google.com/p/tortoisegit/issues/detail?id=%BUGID%");
123 m_cLogMessage.Init(pp);
124 m_cLogMessage.SetFont((CString)CRegString(_T("Software\\TortoiseGit\\LogFontName"), _T("Courier New")), (DWORD)CRegDWORD(_T("Software\\TortoiseGit\\LogFontSize"), 8));
125 m_cLogMessage.Call(SCI_SETREADONLY, TRUE);
127 m_updateDownloader = new CUpdateDownloader(GetSafeHwnd(), m_bForce == TRUE, WM_USER_DISPLAYSTATUS, &m_eventStop);
129 if (AfxBeginThread(CheckThreadEntry, this)==NULL)
131 CMessageBox::Show(NULL, IDS_ERR_THREADSTARTFAILED, IDS_APPNAME, MB_OK | MB_ICONERROR);
134 SetTimer(100, 1000, NULL);
135 return TRUE;
138 void CCheckForUpdatesDlg::OnDestroy()
140 for (int i = 0; i < m_ctrlFiles.GetItemCount(); ++i)
141 delete (CUpdateListCtrl::Entry *)m_ctrlFiles.GetItemData(i);
143 if (m_updateDownloader)
144 delete m_updateDownloader;
146 CStandAloneDialog::OnDestroy();
149 void CCheckForUpdatesDlg::OnOK()
151 if (m_bThreadRunning || m_pDownloadThread != NULL)
152 return; // Don't exit while downloading
154 CStandAloneDialog::OnOK();
157 void CCheckForUpdatesDlg::OnCancel()
159 if (m_bThreadRunning || m_pDownloadThread != NULL)
160 return; // Don't exit while downloading
161 CStandAloneDialog::OnCancel();
164 UINT CCheckForUpdatesDlg::CheckThreadEntry(LPVOID pVoid)
166 return ((CCheckForUpdatesDlg*)pVoid)->CheckThread();
169 UINT CCheckForUpdatesDlg::CheckThread()
171 m_bThreadRunning = TRUE;
173 CString temp;
174 CString tempfile = CTempFiles::Instance().GetTempFilePath(true).GetWinPathString();
176 bool official = false;
178 CRegString checkurluser = CRegString(_T("Software\\TortoiseGit\\UpdateCheckURL"), _T(""));
179 CRegString checkurlmachine = CRegString(_T("Software\\TortoiseGit\\UpdateCheckURL"), _T(""), FALSE, HKEY_LOCAL_MACHINE);
180 CString sCheckURL = checkurluser;
181 if (sCheckURL.IsEmpty())
183 sCheckURL = checkurlmachine;
184 if (sCheckURL.IsEmpty())
186 official = true;
187 bool checkPreview = false;
188 #if PREVIEW
189 checkPreview = true;
190 #else
191 CRegStdDWORD regCheckPreview(L"Software\\TortoiseGit\\VersionCheckPreview", FALSE);
192 if (DWORD(regCheckPreview))
193 checkPreview = true;
194 #endif
195 if (checkPreview)
197 sCheckURL = _T("http://version.tortoisegit.googlecode.com/git/version-preview.txt");
198 SetDlgItemText(IDC_SOURCE, _T("Using preview release channel"));
200 else
201 sCheckURL = _T("http://version.tortoisegit.googlecode.com/git/version.txt");
205 if (!official)
206 SetDlgItemText(IDC_SOURCE, _T("Using (unofficial) release channel: ") + sCheckURL);
208 CString errorText;
209 BOOL ret = m_updateDownloader->DownloadFile(sCheckURL, tempfile, false);
210 if (!ret && official)
212 CString signatureTempfile = CTempFiles::Instance().GetTempFilePath(true).GetWinPathString();
213 ret = m_updateDownloader->DownloadFile(sCheckURL + SIGNATURE_FILE_ENDING, signatureTempfile, false);
214 if (!ret && VerifyIntegrity(tempfile, signatureTempfile, m_updateDownloader))
216 SetDlgItemText(IDC_CHECKRESULT, _T("Could not verify digital signature."));
217 DeleteUrlCacheEntry(sCheckURL);
218 DeleteUrlCacheEntry(sCheckURL + SIGNATURE_FILE_ENDING);
219 goto finish;
222 else if (ret)
224 DeleteUrlCacheEntry(sCheckURL);
225 if (CRegDWORD(_T("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\GlobalUserOffline"), 0))
226 errorText.LoadString(IDS_OFFLINEMODE); // offline mode enabled
227 else
228 errorText.Format(IDS_CHECKNEWER_NETERROR_FORMAT, ret);
230 if (!ret)
234 CStdioFile file(tempfile, CFile::modeRead | CFile::shareDenyWrite);
235 CString ver;
236 unsigned int major,minor,micro,build;
237 major=minor=micro=build=0;
238 unsigned __int64 version=0;
240 if (file.ReadString(ver))
242 CString vertemp = ver;
243 // another versionstring for the filename can be provided after a semicolon
244 // this is needed for preview releases
245 int differentFilenamePos = vertemp.Find(_T(";"));
246 if (differentFilenamePos > 0)
248 vertemp = vertemp.Left(differentFilenamePos);
249 ver = ver.Mid(differentFilenamePos + 1);
252 major = _ttoi(vertemp);
253 vertemp = vertemp.Mid(vertemp.Find('.')+1);
254 minor = _ttoi(vertemp);
255 vertemp = vertemp.Mid(vertemp.Find('.')+1);
256 micro = _ttoi(vertemp);
257 vertemp = vertemp.Mid(vertemp.Find('.')+1);
258 build = _ttoi(vertemp);
259 version = major;
260 version <<= 16;
261 version += minor;
262 version <<= 16;
263 version += micro;
264 version <<= 16;
265 version += build;
269 BOOL bNewer = FALSE;
270 if (m_bForce)
271 bNewer = TRUE;
272 if (major > TGIT_VERMAJOR)
273 bNewer = TRUE;
274 else if ((minor > TGIT_VERMINOR)&&(major == TGIT_VERMAJOR))
275 bNewer = TRUE;
276 else if ((micro > TGIT_VERMICRO)&&(minor == TGIT_VERMINOR)&&(major == TGIT_VERMAJOR))
277 bNewer = TRUE;
278 else if ((build > TGIT_VERBUILD)&&(micro == TGIT_VERMICRO)&&(minor == TGIT_VERMINOR)&&(major == TGIT_VERMAJOR))
279 bNewer = TRUE;
281 if (version != 0)
283 CString version;
284 version.Format(_T("%u.%u.%u.%u"),major,minor,micro,build);
285 if (version != ver)
286 version += _T(" (") + ver + _T(")");
287 temp.Format(IDS_CHECKNEWER_CURRENTVERSION, (LPCTSTR)version);
288 SetDlgItemText(IDC_CURRENTVERSION, temp);
291 if (version == 0)
293 temp.LoadString(IDS_CHECKNEWER_NETERROR);
294 SetDlgItemText(IDC_CHECKRESULT, temp);
296 else if (bNewer)
298 if(file.ReadString(temp) && !temp.IsEmpty())
299 { // Read the next line, it could contain a message for the user
300 CString tempLink;
301 if(file.ReadString(tempLink) && !tempLink.IsEmpty())
302 { // Read another line to find out the download link-URL, if any
303 m_sUpdateDownloadLink = tempLink;
306 else
308 temp.LoadString(IDS_CHECKNEWER_NEWERVERSIONAVAILABLE);
309 CString tempLink;
310 file.ReadString(tempLink);
312 SetDlgItemText(IDC_CHECKRESULT, temp);
313 m_bShowInfo = TRUE;
315 FillChangelog(file);
316 FillDownloads(file, ver);
318 // Show download controls
319 RECT rectWindow, rectProgress, rectGroupDownloads, rectOKButton;
320 GetWindowRect(&rectWindow);
321 m_progress.GetWindowRect(&rectProgress);
322 GetDlgItem(IDC_GROUP_DOWNLOADS)->GetWindowRect(&rectGroupDownloads);
323 GetDlgItem(IDOK)->GetWindowRect(&rectOKButton);
324 LONG bottomDistance = rectWindow.bottom - rectOKButton.bottom;
325 OffsetRect(&rectOKButton, 0, (rectGroupDownloads.bottom + (rectGroupDownloads.bottom - rectProgress.bottom)) - rectOKButton.top);
326 rectWindow.bottom = rectOKButton.bottom + bottomDistance;
327 MoveWindow(&rectWindow);
328 ::MapWindowPoints(NULL, GetSafeHwnd(), (LPPOINT)&rectOKButton, 2);
329 GetDlgItem(IDOK)->MoveWindow(&rectOKButton);
330 m_ctrlFiles.ShowWindow(SW_SHOW);
331 GetDlgItem(IDC_GROUP_DOWNLOADS)->ShowWindow(SW_SHOW);
332 CenterWindow();
334 else
336 temp.LoadString(IDS_CHECKNEWER_YOURUPTODATE);
337 SetDlgItemText(IDC_CHECKRESULT, temp);
338 file.ReadString(temp);
339 file.ReadString(temp);
340 FillChangelog(file);
344 catch (CException * e)
346 e->Delete();
347 temp.LoadString(IDS_CHECKNEWER_NETERROR);
348 SetDlgItemText(IDC_CHECKRESULT, temp);
351 else
353 SetDlgItemText(IDC_CHECKRESULT, errorText);
355 if (!m_sUpdateDownloadLink.IsEmpty())
357 m_link.ShowWindow(SW_SHOW);
358 m_link.SetURL(m_sUpdateDownloadLink);
361 finish:
362 m_bThreadRunning = FALSE;
363 DialogEnableWindow(IDOK, TRUE);
364 return 0;
367 void CCheckForUpdatesDlg::FillDownloads(CStdioFile &file, CString version)
369 #if WIN64
370 const CString x86x64 = _T("64");
371 #else
372 const CString x86x64 = _T("32");
373 #endif
375 if (!file.ReadString(m_sFilesURL) || m_sFilesURL.IsEmpty())
376 m_sFilesURL.Format(_T("http://updater.download.tortoisegit.org/tgit/%s/"), version);
378 m_ctrlFiles.InsertItem(0, _T("TortoiseGit"));
379 CString filename;
380 filename.Format(_T("TortoiseGit-%s-%sbit.msi"), version, x86x64);
381 m_ctrlFiles.SetItemData(0, (DWORD_PTR)(new CUpdateListCtrl::Entry(filename, CUpdateListCtrl::STATUS_NONE)));
382 m_ctrlFiles.SetCheck(0 , TRUE);
384 std::vector<DWORD> m_installedLangs;
386 // set up the language selecting combobox
387 CString path = CPathUtils::GetAppParentDirectory();
388 path = path + _T("Languages\\");
389 CSimpleFileFind finder(path, _T("*.dll"));
390 while (finder.FindNextFileNoDirectories())
392 CString file = finder.GetFilePath();
393 CString filename = finder.GetFileName();
394 if (filename.Left(12).CompareNoCase(_T("TortoiseProc")) == 0)
396 CString sVer = _T(STRPRODUCTVER);
397 sVer = sVer.Left(sVer.ReverseFind('.'));
398 CString sFileVer = CPathUtils::GetVersionFromFile(file);
399 sFileVer = sFileVer.Left(sFileVer.ReverseFind('.'));
400 CString sLoc = filename.Mid(12);
401 sLoc = sLoc.Left(sLoc.GetLength() - 4); // cut off ".dll"
402 if ((sLoc.Left(2) == L"32") && (sLoc.GetLength() > 5))
403 continue;
404 DWORD loc = _tstoi(filename.Mid(12));
405 m_installedLangs.push_back(loc);
410 struct LangPack
412 CString m_PackName;
413 CString m_LangName;
414 DWORD m_LocaleID;
415 CString m_LangCode;
416 bool m_Installed;
418 std::vector<LangPack> availableLangs;
419 CString langs;
420 while (file.ReadString(langs) && !langs.IsEmpty())
422 CString sLang = _T("TortoiseGit Language Pack ") + langs.Mid(5);
424 DWORD loc = _tstoi(langs.Mid(0, 4));
425 TCHAR buf[MAX_PATH] = {0};
426 GetLocaleInfo(loc, LOCALE_SNATIVELANGNAME, buf, _countof(buf));
427 CString sLang2(buf);
428 GetLocaleInfo(loc, LOCALE_SNATIVECTRYNAME, buf, _countof(buf));
429 if (buf[0])
431 sLang2 += _T(" (");
432 sLang2 += buf;
433 sLang2 += _T(")");
436 bool installed = std::find(m_installedLangs.begin(), m_installedLangs.end(), loc) != m_installedLangs.end();
437 LangPack pack = { sLang, sLang2, loc, langs.Mid(5), installed };
438 availableLangs.push_back(pack);
440 std::sort(availableLangs.begin(), availableLangs.end(), [&](const LangPack& a, const LangPack& b) -> int
442 return (a.m_Installed && !b.m_Installed) ? 1 : (!a.m_Installed && b.m_Installed) ? 0 : (a.m_PackName.Compare(b.m_PackName) < 0);
444 for (auto langs : availableLangs)
446 int pos = m_ctrlFiles.InsertItem(m_ctrlFiles.GetItemCount(), langs.m_PackName);
447 m_ctrlFiles.SetItemText(pos, 1, langs.m_LangName);
449 CString filename;
450 filename.Format(_T("TortoiseGit-LanguagePack-%s-%sbit-%s.msi"), version, x86x64, langs.m_LangCode);
451 m_ctrlFiles.SetItemData(pos, (DWORD_PTR)(new CUpdateListCtrl::Entry(filename, CUpdateListCtrl::STATUS_NONE)));
453 if (langs.m_Installed)
454 m_ctrlFiles.SetCheck(pos , TRUE);
456 DialogEnableWindow(IDC_BUTTON_UPDATE, TRUE);
459 void CCheckForUpdatesDlg::FillChangelog(CStdioFile &file)
461 CString sChangelogURL;
462 if (!file.ReadString(sChangelogURL) || sChangelogURL.IsEmpty())
463 sChangelogURL = _T("http://tortoisegit.googlecode.com/git/src/Changelog.txt");
465 CString tempchangelogfile = CTempFiles::Instance().GetTempFilePath(true).GetWinPathString();
466 if (!m_updateDownloader->DownloadFile(sChangelogURL, tempchangelogfile, false))
468 CString temp;
469 CStdioFile file;
470 if (file.Open(tempchangelogfile, CFile::modeRead | CFile::typeBinary))
472 std::unique_ptr<BYTE[]> buf(new BYTE[(UINT)file.GetLength()]);
473 UINT read = file.Read(buf.get(), (UINT)file.GetLength());
474 bool skipBom = read >= 3 && buf[0] == 0xEF && buf[1] == 0xBB && buf[2] == 0xBF;
475 g_Git.StringAppend(&temp, buf.get() + (skipBom ? 3 : 0), CP_UTF8, read - (skipBom ? 3 : 0));
477 ::SendMessage(m_hWnd, WM_USER_FILLCHANGELOG, 0, reinterpret_cast<LPARAM>((LPCTSTR)temp));
479 else
480 ::SendMessage(m_hWnd, WM_USER_FILLCHANGELOG, 0, reinterpret_cast<LPARAM>(_T("Could not load changelog.")));
483 void CCheckForUpdatesDlg::OnTimer(UINT_PTR nIDEvent)
485 if (nIDEvent == 100)
487 if (m_bThreadRunning == FALSE)
489 if (m_bShowInfo)
491 m_bVisible = TRUE;
492 ShowWindow(SW_SHOWNORMAL);
494 else
496 EndDialog(0);
500 CStandAloneDialog::OnTimer(nIDEvent);
503 void CCheckForUpdatesDlg::OnWindowPosChanging(WINDOWPOS* lpwndpos)
505 CStandAloneDialog::OnWindowPosChanging(lpwndpos);
506 if (m_bVisible == FALSE)
507 lpwndpos->flags &= ~SWP_SHOWWINDOW;
510 BOOL CCheckForUpdatesDlg::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
512 HCURSOR hCur = LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW));
513 SetCursor(hCur);
514 return CStandAloneDialogTmpl<CDialog>::OnSetCursor(pWnd, nHitTest, message);
517 void CCheckForUpdatesDlg::OnBnClickedButtonUpdate()
519 CString title;
520 m_ctrlUpdate.GetWindowText(title);
521 if (m_pDownloadThread == NULL && title == CString(MAKEINTRESOURCE(IDS_PROC_DOWNLOAD)))
523 bool isOneSelected = false;
524 for (int i = 0; i < (int)m_ctrlFiles.GetItemCount(); ++i)
526 if (m_ctrlFiles.GetCheck(i))
528 isOneSelected = true;
529 break;
532 if (!isOneSelected)
533 return;
535 m_eventStop.ResetEvent();
537 m_pDownloadThread = ::AfxBeginThread(DownloadThreadEntry, this, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);
538 if (m_pDownloadThread != NULL)
540 m_pDownloadThread->m_bAutoDelete = FALSE;
541 m_pDownloadThread->ResumeThread();
543 GetDlgItem(IDC_BUTTON_UPDATE)->SetWindowText(CString(MAKEINTRESOURCE(IDS_ABORTBUTTON)));
545 else
547 CMessageBox::Show(NULL, IDS_ERR_THREADSTARTFAILED, IDS_APPNAME, MB_OK | MB_ICONERROR);
550 else if (title == CString(MAKEINTRESOURCE(IDS_ABORTBUTTON)))
552 // Abort
553 m_eventStop.SetEvent();
555 else
557 CString folder = GetDownloadsDirectory();
558 if (m_ctrlUpdate.GetCurrentEntry() == 0)
560 for (int i = 0; i < (int)m_ctrlFiles.GetItemCount(); ++i)
562 CUpdateListCtrl::Entry *data = (CUpdateListCtrl::Entry *)m_ctrlFiles.GetItemData(i);
563 if (m_ctrlFiles.GetCheck(i) == TRUE)
564 ShellExecute(NULL, _T("open"), folder + data->m_filename, NULL, NULL, SW_SHOWNORMAL);
566 CStandAloneDialog::OnOK();
568 else if (m_ctrlUpdate.GetCurrentEntry() == 1)
570 ShellExecute(NULL, _T("open"), folder, NULL, NULL, SW_SHOWNORMAL);
573 m_ctrlUpdate.SetCurrentEntry(0);
577 UINT CCheckForUpdatesDlg::DownloadThreadEntry(LPVOID pVoid)
579 return ((CCheckForUpdatesDlg*)pVoid)->DownloadThread();
582 bool CCheckForUpdatesDlg::Download(CString filename)
584 CString url = m_sFilesURL + filename;
585 CString destFilename = GetDownloadsDirectory() + filename;
586 if (PathFileExists(destFilename) && PathFileExists(destFilename + SIGNATURE_FILE_ENDING))
588 if (VerifyIntegrity(destFilename, destFilename + SIGNATURE_FILE_ENDING, m_updateDownloader) == 0)
589 return true;
590 else
592 DeleteFile(destFilename);
593 DeleteFile(destFilename + SIGNATURE_FILE_ENDING);
594 DeleteUrlCacheEntry(url);
595 DeleteUrlCacheEntry(url + SIGNATURE_FILE_ENDING);
599 m_progress.SetRange32(0, 1);
600 m_progress.SetPos(0);
601 m_progress.ShowWindow(SW_SHOW);
602 if (m_pTaskbarList)
604 m_pTaskbarList->SetProgressState(m_hWnd, TBPF_NORMAL);
605 m_pTaskbarList->SetProgressValue(m_hWnd, 0, 1);
608 CString tempfile = CTempFiles::Instance().GetTempFilePath(true).GetWinPathString();
609 CString signatureTempfile = CTempFiles::Instance().GetTempFilePath(true).GetWinPathString();
610 BOOL ret = m_updateDownloader->DownloadFile(url, tempfile, true);
611 if (!ret)
613 ret = m_updateDownloader->DownloadFile(url + SIGNATURE_FILE_ENDING, signatureTempfile, true);
614 m_progress.SetPos(m_progress.GetPos() + 1);
615 if (m_pTaskbarList)
617 m_pTaskbarList->SetProgressState(m_hWnd, TBPF_NORMAL);
618 int minValue, maxValue;
619 m_progress.GetRange(minValue, maxValue);
620 m_pTaskbarList->SetProgressValue(m_hWnd, m_progress.GetPos(), maxValue);
623 if (!ret)
625 if (VerifyIntegrity(tempfile, signatureTempfile, m_updateDownloader) == 0)
627 DeleteFile(destFilename);
628 DeleteFile(destFilename + SIGNATURE_FILE_ENDING);
629 MoveFile(tempfile, destFilename);
630 MoveFile(signatureTempfile, destFilename + SIGNATURE_FILE_ENDING);
631 return true;
633 DeleteUrlCacheEntry(url);
634 DeleteUrlCacheEntry(url + SIGNATURE_FILE_ENDING);
636 return false;
639 UINT CCheckForUpdatesDlg::DownloadThread()
641 m_ctrlFiles.SetExtendedStyle(m_ctrlFiles.GetExtendedStyle() & ~LVS_EX_CHECKBOXES);
643 BOOL result = TRUE;
644 for (int i = 0; i < (int)m_ctrlFiles.GetItemCount(); ++i)
646 m_ctrlFiles.EnsureVisible(i, FALSE);
647 CRect rect;
648 m_ctrlFiles.GetItemRect(i, &rect, LVIR_BOUNDS);
649 CUpdateListCtrl::Entry *data = (CUpdateListCtrl::Entry *)m_ctrlFiles.GetItemData(i);
650 if (m_ctrlFiles.GetCheck(i) == TRUE)
652 data->m_status = CUpdateListCtrl::STATUS_DOWNLOADING;
653 m_ctrlFiles.InvalidateRect(rect);
654 if (Download(data->m_filename))
655 data->m_status = CUpdateListCtrl::STATUS_SUCCESS;
656 else
658 data->m_status = CUpdateListCtrl::STATUS_FAIL;
659 result = FALSE;
662 else
663 data->m_status = CUpdateListCtrl::STATUS_IGNORE;
664 m_ctrlFiles.InvalidateRect(rect);
667 ::PostMessage(GetSafeHwnd(), WM_USER_ENDDOWNLOAD, 0, 0);
669 return result;
672 LRESULT CCheckForUpdatesDlg::OnEndDownload(WPARAM, LPARAM)
674 ASSERT(m_pDownloadThread != NULL);
676 // wait until the thread terminates
677 DWORD dwExitCode;
678 if (::GetExitCodeThread(m_pDownloadThread->m_hThread, &dwExitCode) && dwExitCode == STILL_ACTIVE)
679 ::WaitForSingleObject(m_pDownloadThread->m_hThread, INFINITE);
681 // make sure we always have the correct exit code
682 ::GetExitCodeThread(m_pDownloadThread->m_hThread, &dwExitCode);
684 delete m_pDownloadThread;
685 m_pDownloadThread = NULL;
687 m_progress.ShowWindow(SW_HIDE);
689 if (dwExitCode == TRUE)
691 m_ctrlUpdate.AddEntry(CString(MAKEINTRESOURCE(IDS_PROC_INSTALL)));
692 m_ctrlUpdate.AddEntry(CString(MAKEINTRESOURCE(IDS_CHECKUPDATE_DESTFOLDER)));
693 m_ctrlUpdate.Invalidate();
694 if (m_pTaskbarList)
695 m_pTaskbarList->SetProgressState(m_hWnd, TBPF_NOPROGRESS);
697 else
699 m_ctrlUpdate.SetWindowText(CString(MAKEINTRESOURCE(IDS_PROC_DOWNLOAD)));
700 if (m_pTaskbarList)
701 m_pTaskbarList->SetProgressState(m_hWnd, TBPF_ERROR);
702 CMessageBox::Show(NULL, IDS_ERR_FAILEDUPDATEDOWNLOAD, IDS_APPNAME, MB_ICONERROR);
703 if (m_pTaskbarList)
704 m_pTaskbarList->SetProgressState(m_hWnd, TBPF_NOPROGRESS);
707 return 0;
710 LRESULT CCheckForUpdatesDlg::OnFillChangelog(WPARAM, LPARAM lParam)
712 ASSERT(lParam != NULL);
714 LPCTSTR changelog = reinterpret_cast<LPCTSTR>(lParam);
715 m_cLogMessage.Call(SCI_SETREADONLY, FALSE);
716 m_cLogMessage.SetText(changelog);
717 m_cLogMessage.Call(SCI_SETREADONLY, TRUE);
718 m_cLogMessage.Call(SCI_GOTOPOS, 0);
720 return 0;
723 CString CCheckForUpdatesDlg::GetDownloadsDirectory()
725 CString folder;
727 if (SysInfo::Instance().IsVistaOrLater())
729 CAutoLibrary hShell = AtlLoadSystemLibraryUsingFullPath(_T("shell32.dll"));
730 if (hShell)
732 typedef HRESULT STDAPICALLTYPE SHGetKnownFolderPathFN(__in REFKNOWNFOLDERID rfid, __in DWORD dwFlags, __in_opt HANDLE hToken, __deref_out PWSTR *ppszPath);
733 SHGetKnownFolderPathFN *pfnSHGetKnownFolderPath = (SHGetKnownFolderPathFN*)GetProcAddress(hShell, "SHGetKnownFolderPath");
734 if (pfnSHGetKnownFolderPath)
736 wchar_t * wcharPtr = 0;
737 HRESULT hr = pfnSHGetKnownFolderPath(FOLDERID_Downloads, KF_FLAG_CREATE, NULL, &wcharPtr);
738 if (SUCCEEDED(hr))
740 folder = wcharPtr;
741 CoTaskMemFree(static_cast<void*>(wcharPtr));
742 return folder.TrimRight(_T("\\")) + _T("\\");
748 TCHAR szPath[MAX_PATH] = {0};
749 if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PERSONAL | CSIDL_FLAG_CREATE, NULL, SHGFP_TYPE_CURRENT, szPath)))
750 folder = szPath;
751 CString downloads = folder.TrimRight(_T("\\")) + _T("\\Downloads\\");
752 if ((PathFileExists(downloads) && PathIsDirectory(downloads)) || (!PathFileExists(downloads) && CreateDirectory(downloads, NULL)))
753 return downloads;
755 return folder;
758 LRESULT CCheckForUpdatesDlg::OnDisplayStatus(WPARAM, LPARAM lParam)
760 const CUpdateDownloader::DOWNLOADSTATUS *const pDownloadStatus = reinterpret_cast<CUpdateDownloader::DOWNLOADSTATUS *>(lParam);
761 if (pDownloadStatus != NULL)
763 ASSERT(::AfxIsValidAddress(pDownloadStatus, sizeof(CUpdateDownloader::DOWNLOADSTATUS)));
765 m_progress.SetRange32(0, pDownloadStatus->ulProgressMax);
766 m_progress.SetPos(pDownloadStatus->ulProgress);
767 if (m_pTaskbarList)
769 m_pTaskbarList->SetProgressState(m_hWnd, TBPF_NORMAL);
770 m_pTaskbarList->SetProgressValue(m_hWnd, pDownloadStatus->ulProgress, pDownloadStatus->ulProgressMax);
774 return 0;
777 LRESULT CCheckForUpdatesDlg::OnTaskbarBtnCreated(WPARAM /*wParam*/, LPARAM /*lParam*/)
779 m_pTaskbarList.Release();
780 m_pTaskbarList.CoCreateInstance(CLSID_TaskbarList);
781 return 0;