1414#include " FNVHash.h"
1515#include " StringUtils.h"
1616#include " Translations.h"
17+ #include " json.hpp"
1718#include < wininet.h>
1819#include < softpub.h>
1920
@@ -141,30 +142,9 @@ LRESULT CProgressDlg::OnCancel( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL&
141142
142143static bool g_bCheckingVersion;
143144
144- static DWORD GetTimeStamp ( const wchar_t *fname )
145- {
146- HANDLE h=CreateFile (fname,GENERIC_READ,FILE_SHARE_READ,NULL ,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL );
147- if (h==INVALID_HANDLE_VALUE)
148- return 0 ;
149- DWORD res=0 ;
150- DWORD q;
151- IMAGE_DOS_HEADER header;
152- if (ReadFile (h,&header,sizeof (header),&q,NULL ) && q==sizeof (header))
153- {
154- if (SetFilePointer (h,header.e_lfanew +8 ,NULL ,FILE_BEGIN)!=INVALID_SET_FILE_POINTER)
155- {
156- if (!ReadFile (h,&res,4 ,&q,NULL ) || q!=4 )
157- res=0 ;
158- }
159- }
160- CloseHandle (h);
161- return res;
162- }
163-
164145enum TDownloadResult
165146{
166147 DOWNLOAD_OK,
167- DOWNLOAD_SAMETIME,
168148 DOWNLOAD_CANCEL,
169149
170150 // errors
@@ -176,8 +156,7 @@ enum TDownloadResult
176156
177157// Downloads a file
178158// filename - returns the name of the downloaded file
179- // timestamp - if not zero, it is compared to the timestamp of the file and returns DOWNLOAD_SAMETIME if the same (and buf will be empty)
180- static TDownloadResult DownloadFile ( const wchar_t *url, std::vector<char > &buf, CString *pFilename, DWORD timestamp, bool bAcceptCached, CProgressDlg *pProgress, TSettingsComponent component )
159+ static TDownloadResult DownloadFile ( const wchar_t *url, std::vector<char > &buf, CString *pFilename, bool bAcceptCached, CProgressDlg *pProgress, TSettingsComponent component )
181160{
182161 const wchar_t *compName=L" Open-Shell" ;
183162 switch (component)
@@ -264,7 +243,7 @@ static TDownloadResult DownloadFile( const wchar_t *url, std::vector<char> &buf,
264243 if (fileSize==0 )
265244 pProgress->SetProgress (-1 );
266245 }
267- int CHUNK_SIZE=timestamp? 1024 : 32768 ; // start with small chunk to verify the timestamp
246+ int CHUNK_SIZE=32768 ;
268247 DWORD size=0 ;
269248 buf.reserve (fileSize+CHUNK_SIZE);
270249 while (1 )
@@ -286,25 +265,6 @@ static TDownloadResult DownloadFile( const wchar_t *url, std::vector<char> &buf,
286265 size+=dwSize;
287266 if (pProgress && fileSize)
288267 pProgress->SetProgress (size*100 /fileSize);
289- if (timestamp && (size<sizeof (IMAGE_DOS_HEADER) || buf[0 ]!=' M' || buf[1 ]!=' Z' ))
290- {
291- res=DOWNLOAD_FAIL;
292- break ;
293- }
294- if (timestamp && size>=sizeof (IMAGE_DOS_HEADER))
295- {
296- DWORD pos=((IMAGE_DOS_HEADER*)&buf[0 ])->e_lfanew +8 ;
297- if (size>=pos+4 )
298- {
299- if (timestamp==*(DWORD*)&buf[pos])
300- {
301- res=DOWNLOAD_SAMETIME;
302- break ;
303- }
304- timestamp=0 ;
305- CHUNK_SIZE=32768 ;
306- }
307- }
308268 }
309269 buf.resize (size);
310270 }
@@ -377,80 +337,17 @@ static DWORD WINAPI ThreadVersionCheck( void *param )
377337 return 0 ;
378338 }
379339 DWORD curVersion=GetVersionEx (g_Instance);
380- regKey.SetDWORDValue (L" LastUpdateVersion" ,curVersion);
381340
382- // download file
383- wchar_t fname[_MAX_PATH]=L" %ALLUSERSPROFILE%\\ OpenShell" ;
384- DoEnvironmentSubst (fname,_countof (fname));
385- SHCreateDirectory (NULL ,fname);
386- PathAppend (fname,L" update.ver" );
387-
388- bool res=false ;
389- CString urlBase=LoadStringEx (IDS_VERSION_URL);
341+ bool res = false ;
390342 VersionData data;
391- data.Clear ();
392- if (data.Load (fname,false )==VersionData::LOAD_OK)
393- {
394- if (!data.altUrl .IsEmpty ())
395- urlBase=data.altUrl ;
396- WIN32_FILE_ATTRIBUTE_DATA attr;
397- if (GetFileAttributesEx (fname,GetFileExInfoStandard,&attr))
398- {
399- DWORD writeTime=(DWORD)(((((ULONGLONG)attr.ftLastWriteTime .dwHighDateTime )<<32 )|attr.ftLastWriteTime .dwLowDateTime )/TIME_DIVISOR);
400- if (curTime>writeTime && (curTime-writeTime)<TIME_PRECISION)
401- {
402- res=true ; // the file is valid and less than an hour old, don't download again
403- }
404- }
405- }
406- if (!res)
343+
407344 {
408- data.Clear ();
409- CString url;
410- url.Format (L" %s%d.%d.%d.ver" ,urlBase,curVersion>>24 ,(curVersion>>16 )&0xFF ,curVersion&0xFFFF );
411-
412- #ifdef UPDATE_LOG
413- LogToFile (UPDATE_LOG,L" URL: %s" ,url);
414- #endif
415-
416- std::vector<char > buf;
417- TDownloadResult download=DownloadFile (url,buf,NULL ,GetTimeStamp (fname),false ,params.progress ,params.component );
418- #ifdef UPDATE_LOG
419- LogToFile (UPDATE_LOG,L" Download result: %d" ,download);
420- #endif
421- if (download==DOWNLOAD_CANCEL)
422- {
423- g_bCheckingVersion=false ;
424- return 2 ;
425- }
345+ auto load = data.Load ();
426346
427- if (download<DOWNLOAD_FIRST_ERROR)
428- {
429- if (download==DOWNLOAD_SAMETIME || SaveFile (fname,buf)==0 )
430- {
431- if (download==DOWNLOAD_SAMETIME)
432- {
433- HANDLE h=CreateFile (fname,GENERIC_WRITE,0 ,NULL ,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL );
434- if (h!=INVALID_HANDLE_VALUE)
435- {
436- SetFileTime (h,NULL ,NULL ,(FILETIME*)&curTimeL);
437- CloseHandle (h);
438- }
439- }
440- if (params.progress )
441- {
442- params.progress ->SetText (LoadStringEx (IDS_PROGRESS_VERIFY));
443- params.progress ->SetProgress (-1 );
444- }
445- VersionData::TLoadResult load=data.Load (fname,false );
446- #ifdef UPDATE_LOG
447- LogToFile (UPDATE_LOG,L" Load result: %d" ,load);
448- #endif
449- if (load==VersionData::LOAD_BAD_FILE)
450- DeleteFile (fname);
451- res=(load==VersionData::LOAD_OK);
452- }
453- }
347+ #ifdef UPDATE_LOG
348+ LogToFile (UPDATE_LOG, L" Load result: %d" , load);
349+ #endif
350+ res = (load == VersionData::LOAD_OK);
454351 }
455352
456353 curTime+=(rand ()*TIME_PRECISION)/(RAND_MAX+1 )-(TIME_PRECISION/2 ); // add between -30 and 30 minutes to randomize access
@@ -583,42 +480,19 @@ DWORD CheckForNewVersion( HWND owner, TSettingsComponent component, TVersionChec
583480 }
584481 else
585482 {
586- DWORD buildTime=0 ;
587- {
588- // skip the update if the update component is not found
589- wchar_t path[_MAX_PATH];
590- GetModuleFileName (_AtlBaseModule.GetModuleInstance (),path,_countof (path));
591- PathRemoveFileSpec (path);
592- PathAppend (path,L" Update.exe" );
593-
594- WIN32_FILE_ATTRIBUTE_DATA attr;
595- if (!GetFileAttributesEx (path,GetFileExInfoStandard,&attr))
596- return 0 ;
597-
598- buildTime=(DWORD)(((((ULONGLONG)attr.ftCreationTime .dwHighDateTime )<<32 )|attr.ftCreationTime .dwLowDateTime )/TIME_DIVISOR); // in 0.01 hours
599- }
600-
601483 ULONGLONG curTimeL;
602484 GetSystemTimeAsFileTime ((FILETIME*)&curTimeL);
603485 DWORD curTime=(DWORD)(curTimeL/TIME_DIVISOR); // in 0.01 hours
604- if (curTime-buildTime>24 *365 *TIME_PRECISION)
605- return 0 ; // the build is more than a year old, don't do automatic updates
606486
607487 CRegKey regKey;
608488 if (regKey.Open (HKEY_CURRENT_USER,L" Software\\ OpenShell\\ OpenShell" )!=ERROR_SUCCESS)
609489 regKey.Create (HKEY_CURRENT_USER,L" Software\\ OpenShell\\ OpenShell" );
610490
611- DWORD lastVersion;
612- if (regKey.QueryDWORDValue (L" LastUpdateVersion" ,lastVersion)!=ERROR_SUCCESS)
613- lastVersion=0 ;
614- if (lastVersion==GetVersionEx (g_Instance))
615- {
616- DWORD lastTime;
617- if (regKey.QueryDWORDValue (L" LastUpdateTime" ,lastTime)!=ERROR_SUCCESS)
618- lastTime=0 ;
619- if ((int )(curTime-lastTime)<168 *TIME_PRECISION)
620- return 0 ; // check weekly
621- }
491+ DWORD lastTime;
492+ if (regKey.QueryDWORDValue (L" LastUpdateTime" ,lastTime)!=ERROR_SUCCESS)
493+ lastTime=0 ;
494+ if ((int )(curTime-lastTime)<168 *TIME_PRECISION)
495+ return 0 ; // check weekly
622496
623497 // check the Update setting (uses the current value in the registry, not the one from memory
624498 {
@@ -848,6 +722,94 @@ void VersionData::Swap( VersionData &data )
848722 std::swap (languages,data.languages );
849723}
850724
725+ std::vector<char > DownloadUrl (const wchar_t * url)
726+ {
727+ #ifdef UPDATE_LOG
728+ LogToFile (UPDATE_LOG, L" URL: %s" , url);
729+ #endif
730+
731+ std::vector<char > buffer;
732+ TDownloadResult download = DownloadFile (url, buffer, nullptr , false , nullptr , COMPONENT_UPDATE);
733+
734+ #ifdef UPDATE_LOG
735+ LogToFile (UPDATE_LOG, L" Download result: %d" , download);
736+ #endif
737+
738+ if (download != DOWNLOAD_OK)
739+ buffer.clear ();
740+
741+ return buffer;
742+ }
743+
744+ using namespace nlohmann ;
745+
746+ VersionData::TLoadResult VersionData::Load ()
747+ {
748+ Clear ();
749+
750+ auto buf = DownloadUrl (L" https://api.github.com/repos/Open-Shell/Open-Shell-Menu/releases/latest" );
751+ if (buf.empty ())
752+ return LOAD_ERROR;
753+
754+ try
755+ {
756+ auto data = json::parse (buf.begin (), buf.end ());
757+
758+ // skip prerelease versions
759+ if (data[" prerelease" ].get <bool >())
760+ return LOAD_BAD_VERSION;
761+
762+ // get version from tag name
763+ auto tag = data[" tag_name" ].get <std::string>();
764+ if (tag.empty ())
765+ return LOAD_BAD_FILE;
766+
767+ int v1, v2, v3;
768+ if (sscanf_s (tag.c_str (), " v%d.%d.%d" , &v1, &v2, &v3) != 3 )
769+ return LOAD_BAD_FILE;
770+
771+ newVersion = (v1 << 24 ) | (v2 << 16 ) | v3;
772+
773+ // installer url
774+ std::string url;
775+ for (const auto & asset : data[" assets" ])
776+ {
777+ if (asset[" name" ].get <std::string>().find (" OpenShellSetup" ) == 0 )
778+ {
779+ url = asset[" browser_download_url" ].get <std::string>();
780+ break ;
781+ }
782+ }
783+
784+ if (url.empty ())
785+ return LOAD_BAD_FILE;
786+
787+ downloadUrl.Append (CA2T (url.c_str ()));
788+
789+ // changelog
790+ auto body = data[" body" ].get <std::string>();
791+ if (!body.empty ())
792+ {
793+ auto name = data[" name" ].get <std::string>();
794+ if (!name.empty ())
795+ {
796+ news.Append (CA2T (name.c_str ()));
797+ news.Append (L" \r\n\r\n " );
798+ }
799+
800+ news.Append (CA2T (body.c_str ()));
801+ news.Replace (L" \\ n" , L" \n " );
802+ news.Replace (L" \\ r" , L" \r " );
803+ }
804+
805+ return LOAD_OK;
806+ }
807+ catch (...)
808+ {
809+ return LOAD_BAD_FILE;
810+ }
811+ }
812+
851813VersionData::TLoadResult VersionData::Load ( const wchar_t *fname, bool bLoadFlags )
852814{
853815 Clear ();
@@ -937,7 +899,7 @@ static DWORD WINAPI ThreadDownloadFile( void *param )
937899 params.saveRes =0 ;
938900
939901 std::vector<char > buf;
940- params.downloadRes =DownloadFile (params.url ,buf,params.fname .IsEmpty ()?¶ms.fname :NULL ,0 , params.bAcceptCached ,params.progress ,params.component );
902+ params.downloadRes =DownloadFile (params.url ,buf,params.fname .IsEmpty ()?¶ms.fname :NULL ,params.bAcceptCached ,params.progress ,params.component );
941903 if (params.downloadRes ==DOWNLOAD_CANCEL || params.downloadRes >=DOWNLOAD_FIRST_ERROR)
942904 return 0 ;
943905
@@ -971,6 +933,7 @@ static DWORD WINAPI ThreadDownloadFile( void *param )
971933 return 0 ;
972934
973935 // validate signer
936+ /*
974937 if (params.signer)
975938 {
976939 if (params.progress)
@@ -982,7 +945,7 @@ static DWORD WINAPI ThreadDownloadFile( void *param )
982945 return 0;
983946 }
984947 }
985-
948+ */
986949 return 0 ;
987950}
988951
@@ -1089,6 +1052,12 @@ DWORD DownloadNewVersion( HWND owner, TSettingsComponent component, const wchar_
10891052 params.bAcceptCached =true ;
10901053 params.component =component;
10911054
1055+ {
1056+ const wchar_t * name = wcsrchr (url, ' /' );
1057+ if (name && name[1 ])
1058+ params.fname .Append (name+1 );
1059+ }
1060+
10921061 HANDLE hThread=CreateThread (NULL ,0 ,ThreadDownloadFile,¶ms,0 ,NULL );
10931062
10941063 while (1 )
0 commit comments