14
14
#include " FNVHash.h"
15
15
#include " StringUtils.h"
16
16
#include " Translations.h"
17
+ #include " json.hpp"
17
18
#include < wininet.h>
18
19
#include < softpub.h>
19
20
@@ -141,30 +142,9 @@ LRESULT CProgressDlg::OnCancel( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL&
141
142
142
143
static bool g_bCheckingVersion;
143
144
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
-
164
145
enum TDownloadResult
165
146
{
166
147
DOWNLOAD_OK,
167
- DOWNLOAD_SAMETIME,
168
148
DOWNLOAD_CANCEL,
169
149
170
150
// errors
@@ -176,8 +156,7 @@ enum TDownloadResult
176
156
177
157
// Downloads a file
178
158
// 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 )
181
160
{
182
161
const wchar_t *compName=L" Open-Shell" ;
183
162
switch (component)
@@ -264,7 +243,7 @@ static TDownloadResult DownloadFile( const wchar_t *url, std::vector<char> &buf,
264
243
if (fileSize==0 )
265
244
pProgress->SetProgress (-1 );
266
245
}
267
- int CHUNK_SIZE=timestamp? 1024 : 32768 ; // start with small chunk to verify the timestamp
246
+ int CHUNK_SIZE=32768 ;
268
247
DWORD size=0 ;
269
248
buf.reserve (fileSize+CHUNK_SIZE);
270
249
while (1 )
@@ -286,25 +265,6 @@ static TDownloadResult DownloadFile( const wchar_t *url, std::vector<char> &buf,
286
265
size+=dwSize;
287
266
if (pProgress && fileSize)
288
267
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
- }
308
268
}
309
269
buf.resize (size);
310
270
}
@@ -377,80 +337,17 @@ static DWORD WINAPI ThreadVersionCheck( void *param )
377
337
return 0 ;
378
338
}
379
339
DWORD curVersion=GetVersionEx (g_Instance);
380
- regKey.SetDWORDValue (L" LastUpdateVersion" ,curVersion);
381
340
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 ;
390
342
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
+
407
344
{
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 ();
426
346
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);
454
351
}
455
352
456
353
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
583
480
}
584
481
else
585
482
{
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
-
601
483
ULONGLONG curTimeL;
602
484
GetSystemTimeAsFileTime ((FILETIME*)&curTimeL);
603
485
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
606
486
607
487
CRegKey regKey;
608
488
if (regKey.Open (HKEY_CURRENT_USER,L" Software\\ OpenShell\\ OpenShell" )!=ERROR_SUCCESS)
609
489
regKey.Create (HKEY_CURRENT_USER,L" Software\\ OpenShell\\ OpenShell" );
610
490
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
622
496
623
497
// check the Update setting (uses the current value in the registry, not the one from memory
624
498
{
@@ -848,6 +722,94 @@ void VersionData::Swap( VersionData &data )
848
722
std::swap (languages,data.languages );
849
723
}
850
724
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
+
851
813
VersionData::TLoadResult VersionData::Load ( const wchar_t *fname, bool bLoadFlags )
852
814
{
853
815
Clear ();
@@ -937,7 +899,7 @@ static DWORD WINAPI ThreadDownloadFile( void *param )
937
899
params.saveRes =0 ;
938
900
939
901
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 );
941
903
if (params.downloadRes ==DOWNLOAD_CANCEL || params.downloadRes >=DOWNLOAD_FIRST_ERROR)
942
904
return 0 ;
943
905
@@ -971,6 +933,7 @@ static DWORD WINAPI ThreadDownloadFile( void *param )
971
933
return 0 ;
972
934
973
935
// validate signer
936
+ /*
974
937
if (params.signer)
975
938
{
976
939
if (params.progress)
@@ -982,7 +945,7 @@ static DWORD WINAPI ThreadDownloadFile( void *param )
982
945
return 0;
983
946
}
984
947
}
985
-
948
+ */
986
949
return 0 ;
987
950
}
988
951
@@ -1089,6 +1052,12 @@ DWORD DownloadNewVersion( HWND owner, TSettingsComponent component, const wchar_
1089
1052
params.bAcceptCached =true ;
1090
1053
params.component =component;
1091
1054
1055
+ {
1056
+ const wchar_t * name = wcsrchr (url, ' /' );
1057
+ if (name && name[1 ])
1058
+ params.fname .Append (name+1 );
1059
+ }
1060
+
1092
1061
HANDLE hThread=CreateThread (NULL ,0 ,ThreadDownloadFile,¶ms,0 ,NULL );
1093
1062
1094
1063
while (1 )
0 commit comments