From d5dcb9ad42a7d40acff67ae41d27a6e36c234bae Mon Sep 17 00:00:00 2001 From: LoRd_MuldeR Date: Sun, 17 Nov 2013 21:53:28 +0100 Subject: [PATCH] Refactored update checks into a separate thread, for better code reusability. --- LameXP_VS2013.vcxproj | 13 + LameXP_VS2013.vcxproj.filters | 9 + etc/Translation/Blank.ts | 61 ++- etc/Translation/LameXP_DE.ts | 14 +- etc/Translation/LameXP_ES.ts | 8 +- etc/Translation/LameXP_FR.ts | 8 +- etc/Translation/LameXP_IT.ts | 8 +- etc/Translation/LameXP_KR.ts | 8 +- etc/Translation/LameXP_PL.ts | 61 ++- etc/Translation/LameXP_RU.ts | 8 +- etc/Translation/LameXP_SV.ts | 61 ++- etc/Translation/LameXP_TW.ts | 8 +- etc/Translation/LameXP_UK.ts | 8 +- etc/Translation/LameXP_ZH.ts | 8 +- res/localization/LameXP_DE.qm | Bin 86383 -> 86518 bytes res/localization/LameXP_ES.qm | Bin 88699 -> 88519 bytes res/localization/LameXP_FR.qm | Bin 90031 -> 89865 bytes res/localization/LameXP_IT.qm | Bin 35639 -> 35493 bytes res/localization/LameXP_KR.qm | Bin 65738 -> 65666 bytes res/localization/LameXP_PL.qm | Bin 87293 -> 87153 bytes res/localization/LameXP_RU.qm | Bin 66365 -> 66273 bytes res/localization/LameXP_SV.qm | Bin 81769 -> 81627 bytes res/localization/LameXP_TW.qm | Bin 59332 -> 59270 bytes res/localization/LameXP_UK.qm | Bin 90236 -> 90096 bytes res/localization/LameXP_ZH.qm | Bin 59434 -> 59372 bytes src/Config.h | 2 +- src/Dialog_Update.cpp | 899 ++++++---------------------------- src/Dialog_Update.h | 23 +- src/Thread_CheckUpdate.cpp | 710 +++++++++++++++++++++++++++ src/Thread_CheckUpdate.h | 108 ++++ 30 files changed, 1131 insertions(+), 894 deletions(-) create mode 100644 src/Thread_CheckUpdate.cpp create mode 100644 src/Thread_CheckUpdate.h diff --git a/LameXP_VS2013.vcxproj b/LameXP_VS2013.vcxproj index 7e3f6528..c992b772 100644 --- a/LameXP_VS2013.vcxproj +++ b/LameXP_VS2013.vcxproj @@ -348,6 +348,7 @@ del "$(TargetDir)imageformats\q???d4.dll" + @@ -393,6 +394,7 @@ del "$(TargetDir)imageformats\q???d4.dll" + @@ -569,6 +571,17 @@ del "$(TargetDir)imageformats\q???d4.dll" $(SolutionDir)tmp\MOC_%(Filename).cpp;%(Outputs) + + "$(QTDIR)\bin\moc.exe" -o "$(SolutionDir)tmp\MOC_%(Filename).cpp" "%(FullPath)" + "$(QTDIR)\bin\moc.exe" -o "$(SolutionDir)tmp\MOC_%(Filename).cpp" "%(FullPath)" + "$(QTDIR)\bin\moc.exe" -o "$(SolutionDir)tmp\MOC_%(Filename).cpp" "%(FullPath)" + MOC "$(SolutionDir)tmp\MOC_%(Filename).cpp" + MOC "$(SolutionDir)tmp\MOC_%(Filename).cpp" + MOC "$(SolutionDir)tmp\MOC_%(Filename).cpp" + $(SolutionDir)tmp\MOC_%(Filename).cpp;%(Outputs) + $(SolutionDir)tmp\MOC_%(Filename).cpp;%(Outputs) + $(SolutionDir)tmp\MOC_%(Filename).cpp;%(Outputs) + "$(QTDIR)\bin\moc.exe" -o "$(SolutionDir)tmp\MOC_%(Filename).cpp" "%(FullPath)" diff --git a/LameXP_VS2013.vcxproj.filters b/LameXP_VS2013.vcxproj.filters index 863d7a9d..1bd46623 100644 --- a/LameXP_VS2013.vcxproj.filters +++ b/LameXP_VS2013.vcxproj.filters @@ -415,6 +415,12 @@ Source Files + + Source Files\Threads + + + Generated Files\MOC + @@ -549,6 +555,9 @@ Header Files\Misc\3rd Party + + Header Files\Threads + diff --git a/etc/Translation/Blank.ts b/etc/Translation/Blank.ts index a4162abe..56893d71 100644 --- a/etc/Translation/Blank.ts +++ b/etc/Translation/Blank.ts @@ -3300,22 +3300,22 @@ QApplication - + Executable '%1' doesn't support Windows compatibility mode. - + Executable '%1' requires Qt v%2, but found Qt v%3. - + Executable '%1' was built for Qt '%2', but found Qt '%3'. - + Executable '%1' requires Windows XP or later. @@ -3384,105 +3384,104 @@ - - + + Build - + Unknown - + Testing your internet connection, please wait... - - + It appears that the computer currently is offline! - - + + Please make sure your computer is connected to the internet and try again. - + Network connectivity test has failed! - - Please make sure your internet connection is working properly and try again. - - - - + Checking for new updates online, please wait... - + Failed to fetch update information from server! - + Sorry, the update server might be busy at this time. Plase try again later. - + More information available at: - + A new version of LameXP is available! - + + Initializing, please wait... + + + + We highly recommend all users to install this update as soon as possible. - + No new updates available at this time. - + Your version of LameXP is still up-to-date. Please check for updates regularly! - + Your version appears to be newer than the latest release. - + This usually indicates your are currently using a pre-release version of LameXP. - + Update is being downloaded, please be patient... - + Update ready to install. Applicaion will quit... - + Update failed. Please try again or download manually! diff --git a/etc/Translation/LameXP_DE.ts b/etc/Translation/LameXP_DE.ts index b3fce7e3..6178b630 100644 --- a/etc/Translation/LameXP_DE.ts +++ b/etc/Translation/LameXP_DE.ts @@ -293,11 +293,11 @@ BerliOS Developer - + CodePlex - + @@ -2600,7 +2600,7 @@ Executable '%1' requires Windows XP or later. - + Programm '%1' benötigt Windows XP oder neuer. @@ -2667,10 +2667,6 @@ Network connectivity test has failed! Test der Netzwerkverbindung fehlgeschlagen! - - Please make sure your internet connection is working properly and try again. - Bitte prüfen Sie Ihre Internetverbindung und versuchen Sie es dann noch einmal. - Checking for new updates online, please wait... Suche online nach neuen Updates, bitte warten... @@ -2735,5 +2731,9 @@ Please make sure your computer is connected to the internet and try again. Aktivieren Sie Ihre Internetverbindung und versuchen Sie es dann noch einmal. + + Initializing, please wait... + Initialisiere, bitte warten... + diff --git a/etc/Translation/LameXP_ES.ts b/etc/Translation/LameXP_ES.ts index 8b7cc290..da50506b 100644 --- a/etc/Translation/LameXP_ES.ts +++ b/etc/Translation/LameXP_ES.ts @@ -2670,10 +2670,6 @@ Network connectivity test has failed! ¡La prueba de conexión a internet ha fallado! - - Please make sure your internet connection is working properly and try again. - Por favor, asegúrese de que su conexión a internet funciona correctamente y vuelva a intentarlo. - Checking for new updates online, please wait... Comprobando en busca de nuevas actualizaciones, espere por favor... @@ -2734,5 +2730,9 @@ Please make sure your computer is connected to the internet and try again. Por favor, asegurese de que tiene conexión a internet y vuelva a intentarlo. + + Initializing, please wait... + Iniciando, espere por favor... + diff --git a/etc/Translation/LameXP_FR.ts b/etc/Translation/LameXP_FR.ts index b0f44424..6bc38741 100644 --- a/etc/Translation/LameXP_FR.ts +++ b/etc/Translation/LameXP_FR.ts @@ -2681,10 +2681,6 @@ Ouvrir le dossier récursivement... Network connectivity test has failed! Le test de connectivité réseau a échoué! - - Please make sure your internet connection is working properly and try again. - Assurez-vous que votre connexion internet fonctionne correctement et essayez à nouveau. - Checking for new updates online, please wait... Vérification des nouvelles mises à jour en ligne, patientez... @@ -2745,5 +2741,9 @@ Ouvrir le dossier récursivement... Please make sure your computer is connected to the internet and try again. Veuillez vous assurer que votre ordinateur est connecté à internet et essayez à nouveau. + + Initializing, please wait... + Initialisation, patientez... + diff --git a/etc/Translation/LameXP_IT.ts b/etc/Translation/LameXP_IT.ts index 0f9aa9c2..bcb6e570 100644 --- a/etc/Translation/LameXP_IT.ts +++ b/etc/Translation/LameXP_IT.ts @@ -2667,10 +2667,6 @@ Network connectivity test has failed! Il test di connessione di rete è fallito! - - Please make sure your internet connection is working properly and try again. - Per favore assicurati che la tua connessione internet sia funzionante e prova ancora. - Checking for new updates online, please wait... Ricerca di nuovi aggiornamenti in rete, attendere prego... @@ -2735,5 +2731,9 @@ Please make sure your computer is connected to the internet and try again. + + Initializing, please wait... + Inizializzazione, attendere prego... + diff --git a/etc/Translation/LameXP_KR.ts b/etc/Translation/LameXP_KR.ts index 9fa32696..b014b020 100644 --- a/etc/Translation/LameXP_KR.ts +++ b/etc/Translation/LameXP_KR.ts @@ -2653,10 +2653,6 @@ Network connectivity test has failed! 네트워크 연결 테스트가 실패되었습니다! - - Please make sure your internet connection is working properly and try again. - 인터넷에 연결되어 있는지 확인하고 다시 시도하시기 바랍니다. - Checking for new updates online, please wait... 새로운 업데이트 점검중, 잠시만 기다려 주십시오... @@ -2717,5 +2713,9 @@ Please make sure your computer is connected to the internet and try again. 인터넷 연결을 확인하고 다시 시도하시기 바랍니다. + + Initializing, please wait... + 초기화중, 잠시만 기다려 주십시오... + diff --git a/etc/Translation/LameXP_PL.ts b/etc/Translation/LameXP_PL.ts index 05a90c64..5102610f 100644 --- a/etc/Translation/LameXP_PL.ts +++ b/etc/Translation/LameXP_PL.ts @@ -3337,22 +3337,22 @@ QApplication - + Executable '%1' doesn't support Windows compatibility mode. Plik wykonywalny '%1' nie działa w trybie kompatybilności z Windows. - + Executable '%1' requires Qt v%2, but found Qt v%3. Plik wykonywalny '%1' wymaga Qt v%2, znaleziono jednak Qt v%3. - + Executable '%1' was built for Qt '%2', but found Qt '%3'. Plik wykonywalny "%1" został skompilowany dla Qt "%2", znaleziono "%3". - + Executable '%1' requires Windows XP or later. @@ -3421,105 +3421,104 @@ Zamknij - - + + Build Build - + Unknown Nieznana - + Testing your internet connection, please wait... Testowanie połączenia internetowego, prosze czekać... - - + It appears that the computer currently is offline! LameXP wykrył brak dostępu do internetu! - - + + Please make sure your computer is connected to the internet and try again. Upewnij się że komputer jest podłączony do internetu i spróbuj ponownie. - + Network connectivity test has failed! Test połączenia internetowego zakończony niepowodzeniem! - - Please make sure your internet connection is working properly and try again. - Upewnij się że połączenie internetowe działa prawidłowo i spróbuj ponownie. - - - + Checking for new updates online, please wait... Sprawdzanie aktualizacji online, prosze czekać... - + Failed to fetch update information from server! Pobieranie informacji z serwera zakończone niepowodzeniem! - + Sorry, the update server might be busy at this time. Plase try again later. Serwer aktualizacji wydaje się nie odpowiadać w tej chwili. Prosze spróbować później. - + More information available at: Więcej informacji tutaj: - + A new version of LameXP is available! Dostępna nowa wersja LameXP! - + + Initializing, please wait... + Inicjowanie, prosze czekać... + + + We highly recommend all users to install this update as soon as possible. Jest wysoce zalecane aby zainstalować tę aktualizację jak najszybciej. - + No new updates available at this time. Nie ma nowych aktualizacji w tej chwili. - + Your version of LameXP is still up-to-date. Please check for updates regularly! Posiadasz najnowszą wersję LameXP. Sprawdzaj aktualizacje regularnie! - + Your version appears to be newer than the latest release. Posiadasz nowszą wersję LameXP niż ostatnie wydanie. - + This usually indicates your are currently using a pre-release version of LameXP. To wskazuje na to, że posiadasz wersję alfa LameXP. - + Update is being downloaded, please be patient... Pobieranie aktualizacji w toku, prosze czekać... - + Update ready to install. Applicaion will quit... Aktualizacja gotowa do instalacji. Teraz program zostanie zamknięty... - + Update failed. Please try again or download manually! Aktualizacja zakończona niepowodzeniem. Prosze spróbować ponownie lub zainstalować ręcznie! diff --git a/etc/Translation/LameXP_RU.ts b/etc/Translation/LameXP_RU.ts index f1c19354..a8870dca 100644 --- a/etc/Translation/LameXP_RU.ts +++ b/etc/Translation/LameXP_RU.ts @@ -2695,10 +2695,6 @@ Network connectivity test has failed! Нет соединения с сетью! - - Please make sure your internet connection is working properly and try again. - Проверьте доступность интернет соединения и попробуйте снова. - Checking for new updates online, please wait... Проверяю обновления, пожалуйста, подождите... @@ -2760,5 +2756,9 @@ Please make sure your computer is connected to the internet and try again. Пожалуйста, проверьте, что ваш компьютер подключен к интернету и попробуйте снова. + + Initializing, please wait... + Инициализация, пожалуйста, подождите... + diff --git a/etc/Translation/LameXP_SV.ts b/etc/Translation/LameXP_SV.ts index 82346cd3..9da779ed 100644 --- a/etc/Translation/LameXP_SV.ts +++ b/etc/Translation/LameXP_SV.ts @@ -3320,22 +3320,22 @@ QApplication - + Executable '%1' doesn't support Windows compatibility mode. EXE-filen '%1' stöder inte Windows kompatibilitetsläge. - + Executable '%1' requires Qt v%2, but found Qt v%3. EXE-filen '%1' kräver Qt v%2, du har Qt v%3. - + Executable '%1' was built for Qt '%2', but found Qt '%3'. EXE-filen '%1' är byggd för Qt '%2', du har Qt '%3'. - + Executable '%1' requires Windows XP or later. @@ -3404,105 +3404,104 @@ Stäng - - + + Build Build - + Unknown Okänd - + Testing your internet connection, please wait... Kontrollerar iInternetanslutningen, vänta... - - + It appears that the computer currently is offline! Datorn verkar inte vara ansluten till Internet! - - + + Please make sure your computer is connected to the internet and try again. Tillse att datorn är ansluten till Internet och försök igen. - + Network connectivity test has failed! Anslutningskontrollen misslyckades! - - Please make sure your internet connection is working properly and try again. - Tillse att Internetuppkopplingen fungerar korrekt och försök igen. - - - + Checking for new updates online, please wait... Söker nya uppdateringar, vänta... - + Failed to fetch update information from server! Kunde inte hämta uppdateringsinformation från servern! - + Sorry, the update server might be busy at this time. Plase try again later. Uppdateringsservern kan vara upptagen. Försök senare. - + More information available at: Mer information hittas på: - + A new version of LameXP is available! En ny version av LameXP finns tillgänglig! - + + Initializing, please wait... + Initierar, vänta... + + + We highly recommend all users to install this update as soon as possible. Vi rekommenderar alla användare att installera denna uppdatering så snart som möjligt. - + No new updates available at this time. Det finns inga nya uppdateringar. - + Your version of LameXP is still up-to-date. Please check for updates regularly! Din version av LameXP är uppdaterad. Kontrollera regelbundet! - + Your version appears to be newer than the latest release. Din version verkar vara nyare än senaste 'Release'. - + This usually indicates your are currently using a pre-release version of LameXP. Det innebär normalt att du använder en beta-version av LameXP. - + Update is being downloaded, please be patient... Uppdatering laddas ner, vänta... - + Update ready to install. Applicaion will quit... Uppdatering klar att installeras. Programmet kommer att avslutas... - + Update failed. Please try again or download manually! Uppdateringen misslyckades. Försök igen, eller ladda ner manuellt! diff --git a/etc/Translation/LameXP_TW.ts b/etc/Translation/LameXP_TW.ts index 71945bd4..30b41515 100644 --- a/etc/Translation/LameXP_TW.ts +++ b/etc/Translation/LameXP_TW.ts @@ -2652,10 +2652,6 @@ Network connectivity test has failed! 網絡連接測試失敗 ! - - Please make sure your internet connection is working properly and try again. - 請確保您的網絡連接正常工作,然后再試. - Checking for new updates online, please wait... 在線更新檢查新的版本,請稍候... @@ -2716,5 +2712,9 @@ Please make sure your computer is connected to the internet and try again. 請確保您的計算機連接到 Internet,然后重試. + + Initializing, please wait... + 正在初始化,請稍候... + diff --git a/etc/Translation/LameXP_UK.ts b/etc/Translation/LameXP_UK.ts index 7b50ffb0..5cd002ec 100644 --- a/etc/Translation/LameXP_UK.ts +++ b/etc/Translation/LameXP_UK.ts @@ -2689,10 +2689,6 @@ Network connectivity test has failed! Збій перевірки мережевого з'єднання! - - Please make sure your internet connection is working properly and try again. - Будь ласка, впевніться, що ваше інтернет-з'єднання працює коректно і спробуйте знову. - Checking for new updates online, please wait... Йде перевірка оновлень онлайн, будь ласка, зачекайте... @@ -2753,5 +2749,9 @@ Update failed. Please try again or download manually! Збій оновлення. Будь ласка, спробуйте ще раз або завантажте оновлення самостійно! + + Initializing, please wait... + Ініціалізація, будь ласка, зачекайте... + diff --git a/etc/Translation/LameXP_ZH.ts b/etc/Translation/LameXP_ZH.ts index 63bb0996..6b7ab122 100644 --- a/etc/Translation/LameXP_ZH.ts +++ b/etc/Translation/LameXP_ZH.ts @@ -2652,10 +2652,6 @@ Network connectivity test has failed! 网络连接测试失败 ! - - Please make sure your internet connection is working properly and try again. - 请确保您的网络连接正常工作,然后再试。 - Checking for new updates online, please wait... 在线检查新的版本,请稍候... @@ -2716,5 +2712,9 @@ Please make sure your computer is connected to the internet and try again. 请确保您的计算机连接到 Internet,然后重试。 + + Initializing, please wait... + 正在初始化,请稍候... + diff --git a/res/localization/LameXP_DE.qm b/res/localization/LameXP_DE.qm index b82fdbe86830e9dff9df72dd4be05fc604b1cd29..a36efa1cd8757b3e254639c7a91e4e8061330386 100644 GIT binary patch delta 5489 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 NqK>q0Y8O$Y|34zSc|iaG delta 5391 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 diff --git a/res/localization/LameXP_ES.qm b/res/localization/LameXP_ES.qm index 4efe025f88e639759ea5c8f4dded0bd7c07b07d6..908286f2686bd43717df899c35c721c450260ae6 100644 GIT binary patch delta 226 zcmV<803HAPv<1hr1+atx0TYvj0bT+?a00B1xlO+uw z0lAY!4Q2vEUX!g2)&e}LlZ6hp0zKZdJr5QE0za;kRS>2EL6Nil5Uv6OLSB=t6E6{! z4``VX002`B4{2D(00BHrlkF3B7CXET=yZty0E%B}00Bi#0{{R3C;(HEHztFh6t|xg c0o*p1VKxC}mwrhB61RCv0YC(|=1>8Z39HIS&;S4c delta 335 zcmV-V0kHnZvjzLK1+atx0mqYt0bT+@n6u>pRsjM)pp!iVwgNv>v-Jb70RaV*r3Iz} zIEs@^1}6dXvvmds0RaQEeFrfD4`E-900BEg27#^800B3WleGz+0y(9#RSL-hlO_!w z0YH;Q4Q2vF5|gbB)&f0VlZ6hp0zQ(nJr5QE0zhJuRS>2ELPfLv5Uv6OLlTp%6E6`Q z4``VX002`B4{2D(00BJ#lkF3B7Cdkd=yZty0E%B}00Bk<0{{R3C;(HEHztFh6t|xg z0o*pX^h*Ig1OdR4p>!7sVE}UgWdLUY`j=2o0U4KWQUMs3hfe_(4`u*$0B!(d0BHbk z0B!(blaS#Zmzz%kHa<*HY-M3{Wgu-~Yh@sFb#i4Od2e-cAZc!NWpZw1bRc7IZf<2` hbZKvHAZc?TcW-iQX>MmAaB^>OWpZqJw+&DMx(U;+Yl#2= diff --git a/res/localization/LameXP_FR.qm b/res/localization/LameXP_FR.qm index 60cad1536eb1d8015adab5b634a14df6301af747..3495c24f347b25cea036f6070bdd518ab7a3f709 100644 GIT binary patch delta 216 zcmV;}04M*izXgfD1+aqw0zl7`g#lgyMS`>C0agJ5M2eF=1GfP^v-Jb60Rlc2lcfcx z0gsbS1||YYY_oL+2LS=nvwa6C0tbPu(f|QGos+c*p8>41RSL-h2ZA>a00BE)lN}8n z0zX@mJq>08NN|&-4b}odXp?;owgN(svo#MF0RdE#O%SF6Mq9J>5U&COK$E2tE)qQ* z4``VX002@M4{2D(00BW6ljRe34?uPg=yZty0E#zh00ByvgK8AFY7_xsJD0~f0b`dx SSOF5Z%TEEM1hxO1VCdbmrt&DL@ZW^1PGKMiSxf)EiW!}#Cc=K20b&O253nwpSUCt;q z*_Ta?$xCQ+DH}T@W9;Tyc1m<`;IbK;N zyJwSadDECY#U?N1y~gCkH@TK?8bD~M#f*0eFc^=xifD5DzKi3@!901!g@kB zEBG^J3NSDPN%Ch#9A{v3+&}rLa2da&4F8LgP6mc9^GpUtZ@cC!k?mO`jEUCU9Re7a zurRKhtQe?1EtZjEx=c8uimn1f8bdxq9z!xi2}35BmB*0EpaA6OGZX<~Dp)3!As5KX zo9+|BXfEgzkdvBNoT`wUn4PLnTw0VmJtv$|QbZxMSfM<>C_6JRU7?^TzaX_Jr*ixL I5JoR90BVU|W&i*H diff --git a/res/localization/LameXP_IT.qm b/res/localization/LameXP_IT.qm index 9da67cef3e8048a428f167a63888d547a3d04338..3006badf87d68b3bdb048bed5ac74f6cea661968 100644 GIT binary patch delta 187 zcmV;s07U<{mI9@f0+7=JdfSoJ&jC}Dr2(D-c{h_q0!JCH1Xg`~004Fg1Z*2l001a004J4lf4Bt0)N_*^#xx6 zOp{dxZUTIilf?#Z0)BF{H3u#MB7U$BRTpyr06TmSS6bcx0BZmbXKg9~0C+qPX;{Yq p0DBLUg$O1GdWdNN0DY6nwW{KCBKA3DIV;2r8J$U?C_9;s+u&QLzcjxt?n-dtvV`F<&N8f}I!^ zEdv&51e;uu&Q5FuL9tEePq25B_ZWsZGjF;NsQ-xWzfmRE{`u5?WmoH<%bwgsTk(1Q zuvP^qjO+HyKEP5(7k(R{xgB&-Q!_~B4xl_1ZoYg06qn_qzNYO4IekZyub~ub*zzxw z(FQUd=BSpCZ;I-AkcuR=+4_c&j=2CURpaPn0FVX4$}OmtzQK;)0V+?j6-`7c(+uGH zD(FR5ih*c+AnjSMpT{N%xM~@g;DZ1H9xypb#pOk7u8v0z0Ssr#<(uL1!Mlcf_b660A9XqgZI z06$(2X;{Yq0Oj+O=?6Z6c6H)YUfpx9Q6{jdG-hcvoQLa E22$5bMgRZ+ delta 272 zcmV+r0q_2TfdtBd1h9hv0_G2sg#lgy=|Z#R0apP5nv*>Pw*kAe^#iW~0gscV1*ZW% zlT8LE0j9Hc1_uEF3$uL(DFP2+Uyc9(|nEM6c6IF;Pwau0Ya1U_7()Pl*z!8 zR{1eLOi*lPVRL05ZDDI=AaiwcWgvNPb#fqSZggdGZe?^JV{dM5Wn*+{Z*CxIb0Bwb Wa%*XBXCQELZ*XODYeFq@|2Z62900A?NldTDt0gkgp3b_IYf;SET0Wx!w{R|!g zHYJlC4QByllZ6e|0yp%NT@JSa3bPdt76Ae}oRcjOrUE>Xv(*r<0s(H5g%c+c`wwWD z5C8yE!VhU!#{dC0pOd{4cNHKH=yZty0ExY600BTC0{{R3EC5iG%s488a}>986ahvu Zmr5}KWtT5Z0TQ>lMgcYixAIE?3kf&(N6-KO delta 329 zcmeykg7xo8)(tI;jK3$hGR864lqmnCog4P#$^0y zvM-xD5)Dd%)X@y)heJDDc`}+$yXt*utMN zQ-FaX_z-_)#Bl~j3+>5!h08_P@V_YOWMJsro5{fFu!fm|fkB5MVDcFYt>$8p?ZqOD zZbsV;+!@VS7^h9{36>WwV8~~5Vq|4VW~gFFWyoX5WJsNE>&YmotiX^06v|{sWOQOk zWKduzU?>98hv?djFKV>nZ*j_ Z`9;~8dFcuTMfnA(MLCt*9laS1I00;VWBdRB diff --git a/res/localization/LameXP_RU.qm b/res/localization/LameXP_RU.qm index bc11ca25bf9c888bea4158f557d07e275b01972d..d2943268c3cdd80d9e9440107ea0dc0b7028e566 100644 GIT binary patch delta 199 zcmV;&0671>h6Le-1h6Xs0_n(;EdfUXF_U!x{{bVDbpnS01hf4DMgaonUz0@ye*x-~ z#RMM#FO%g2?gHg$v(*L30SAGt(f|PF5Ra0089PlWhtf0_a+k zjS5czcaz-;w*f(ul?$%{Ns~nk{sQdhlSK`F0`AbW#SJ$C0gsdY4=xhsdJkxs5C8x* zF%M~2#{dB80FylsUk+&x=yZty09%r2008nOv#Jo{MmAaB^>OWpZqJAYpD~ WAarthAYo@=X>OD8_!qMm`pO9IXm$Aj diff --git a/res/localization/LameXP_SV.qm b/res/localization/LameXP_SV.qm index af747bef35a4cc431b3d0f9e3808198e00bc27cb..102e5d9dcf5ce31708db17333231b3f0fd74eeed 100644 GIT binary patch delta 214 zcmV;{04e|J{si0o1h9kw0aKHO0bc<^v*iI-0Rd=}Jp;D^Nwf6>t^ood9FwI5rva&x zO$H_cDS)$e1_l8F9x$_g2PpyvfvwU20UqI#wF#dAsIyfH$pQz0Hx2*+9nF&+4ITm^ zF_S$FW&$X{lcf#T0wT(jeGaw)BcQW24;KLeHj_;drUE9@v-J?J0s<$hlcf_b5+6?w zXqgZI08Hf%X;{Yq0V0o+5H|r?2)5%yivR!s delta 341 zcmccpm*wR@mJKb8j1MQbGR8Ar*!+|+oRRU{WLxI#jMq1RWnRa~B)@a=Qr6{+Zj*i4 z)R?sRHkY!oF*3=X-CWDA$;6)+-^akHxRI@K?Ii|Axw^?~Ip;IFZuaFm$uwDxSC&cP z++7iG84Gh%$g z%-AydqOZ86Cqo`X2}3GF5s*#=vPu~WfH0dOA57;kWCF$0fiigv3JhsLSqQI)A#r-6 zD5LoF-=>Uec0K_)sfop@3b~2dsS3rVMX3sv`K3h)nRz9tMR}9|8B1 zJq>381e2u=*8wb(eGaw)&cw4d4-NqW&*+my5T*jq`?Kv3uL1#ZlbsVU5u*=inGgT~ zH|P&(SjPYW&HIzx6L$`l59oA>003J{X#fDzB(q`^k;;>T(L38LX)Kp*8ysieGaw)&jPbG4-NqW&?b{b5T*jrIkW8$uL1$ClbsVU5l#003J{X#fDzVzXitk;=13-?RdMCW^~=x=-C;sCI;X zvVCEYBV(m&V_rC2I Ta(N(OXJKh>E(ZX!=;59PLS%EQ diff --git a/res/localization/LameXP_UK.qm b/res/localization/LameXP_UK.qm index 5bc114a9d509ba6c0120d6fad2c48c2289ad4aec..dc97bc6fd5e598dad4f914d0914633b1c1d50e4f 100644 GIT binary patch delta 216 zcmV;}04M+azy&66z+ z9s)pTlT8h00YsCv4c7s3lZ_6x0z;&;MGqDM0!5CKT@a=MM|ZOY5w8LPPLs70E)qUt z4``VX002_Z4{2D(00BZPll2pJ4?%0qzOW^hnMC delta 325 zcmV-L0lNP1zXklj1+aqw0zz+-g#lgyM@qBh0agJ5MpBbK1GWN11GDu5t^oo*!;_^2 zrvXBfO$H|cuCsLp4gmr@&9j9EF#-=^Uyc9)K=}rNtT@a=MNCUG45w8LP+LN^tE)qT1 z4``VX002_Z4{2D(00Ba`ll2pJ4?++R=yZty0E?w*00B$zgL)LVdK3ZCJh#?S0W1Uo zs*`cc8JGW50V4tgHJ3|R0Vf|I1V02o1TX|f1Wp8003ZZ91U>{n1T_RY1VRKo1U{E? zRRJ$POi*lPVRL05ZDDI=AaiwcWgvNPb#fqSZggdGZe?^JV{dM5Wn*+{Z*CxIb0Bwb Xa%*XBXCQELZ*XODY{04z~dsvqcXV0RcRdT@a@MPqPIPt^xwl#*?)ZE)vWO4``VX z001~34{2D(007Qcll2pJ56$uq=yZty09&7F007f+vw9T!%9DK2Lz6z<60>#RrUJ9B G;(P^}XifwG delta 290 zcmV+-0p0%W&jYH^1F(bv0c(?m0bT;p9<${ER{;U0lRX2s0oSwj1Fr!AN0X%mrUJ|Q zlT8LD0@Dh!bp{Rr0?PNZg$FSL4`E-9007OM27#^8007Hqlf4O_0im;93dsVKE)5+5 z%>I*24QBzAleG=k0mhS!4z~eVvqcXV0ReiGT@a@Mjk5(2t^xwm1e3KBE)vVO4``VX z001~34{2D(007RFll2pJ56&jaW+&AQH_h$Faihw000060000?lMvz-CuweUWpZw1 obRc7IZf<2`bZKvHAZc?TcW-iQX>MmAaB^>OWpZqJvrFQk1=Oc*fB*mh diff --git a/src/Config.h b/src/Config.h index 108cf6ce..c668d235 100644 --- a/src/Config.h +++ b/src/Config.h @@ -35,7 +35,7 @@ #define VER_LAMEXP_MINOR_LO 9 #define VER_LAMEXP_TYPE Alpha #define VER_LAMEXP_PATCH 7 -#define VER_LAMEXP_BUILD 1454 +#define VER_LAMEXP_BUILD 1458 #define VER_LAMEXP_CONFG 1348 /////////////////////////////////////////////////////////////////////////////// diff --git a/src/Dialog_Update.cpp b/src/Dialog_Update.cpp index adbb8eaa..312c4a27 100644 --- a/src/Dialog_Update.cpp +++ b/src/Dialog_Update.cpp @@ -28,146 +28,24 @@ //LameXP includes #include "Global.h" #include "Resource.h" +#include "Thread_CheckUpdate.h" #include "Dialog_LogView.h" #include "Model_Settings.h" #include "WinSevenTaskbar.h" -#include "Tool_Abstract.h" //Qt includes #include #include #include #include -#include -#include #include #include #include #include -#include -#include - -/////////////////////////////////////////////////////////////////////////////// - -static const char *header_id = "!Update"; -static const char *section_id = "LameXP"; - -static const char *mirror_url_postfix[] = -{ - "update.ver", - "update_beta.ver", - NULL -}; - -static const char *update_mirrors_prim[] = -{ - "http://muldersoft.com/", - "http://mulder.bplaced.net/", - "http://mulder.cwsurf.de/", - "http://mulder.6te.net/", - "http://mulder.webuda.com/", - "http://mulder.byethost13.com/", - "http://muldersoft.kilu.de/", - "http://muldersoft.zxq.net/", - "http://lamexp.sourceforge.net/", - "http://lamexp.berlios.de/", - "http://lordmulder.github.com/LameXP/", - "http://lord_mulder.bitbucket.org/", - "http://www.tricksoft.de/", - NULL -}; - -static const char *update_mirrors_back[] = -{ - "http://mplayer.savedonthe.net/", - NULL -}; - -static const char *known_hosts[] = //Taken form: http://www.alexa.com/topsites !!! -{ - "http://www.163.com/", - "http://www.ac3filter.net/", - "http://www.amazon.com/", - "http://www.aol.com/", - "http://www.apache.org/", - "http://www.apple.com/", - "http://www.adobe.com/", - "http://www.avidemux.org/", - "http://www.babylon.com/", - "http://www.baidu.com/", - "http://www.bbc.co.uk/", - "http://www.berlios.de/", - "http://www.bing.com/", - "http://www.cnet.com/", - "http://cnzz.com/", - "http://codecs.com/", - "http://www.codeplex.com/", - "http://qt.digia.com/", - "http://www.ebay.com/", - "http://www.equation.com/", - "http://fc2.com/", - "http://www.ffmpeg.org/", - "http://www.flickr.com/", - "http://blog.gitorious.org/", - "http://git-scm.com/", - "http://www.gnome.org/", - "http://www.gnu.org/", - "http://go.com/", - "http://code.google.com/", - "http://www.heise.de/", - "http://www.huffingtonpost.co.uk/", - "http://www.iana.org/", - "http://www.imdb.com/", - "http://www.imgburn.com/", - "http://imgur.com/", - "http://en.jd.com/", - "http://mirrors.kernel.org/", - "http://www.libav.org/", - "http://www.linkedin.com/", - "http://www.livedoor.com/", - "http://www.livejournal.com/", - "http://mail.ru/", - "http://www.mediafire.com/", - "http://www.mozilla.org/en-US/", - "http://mplayerhq.hu/", - "http://www.msn.com/?st=1", - "http://oss.netfarm.it/", - "http://www.nytimes.com/", - "http://www.opera.com/", - "http://www.portablefreeware.com/", - "http://qt-project.org/", - "http://www.quakelive.com/", - "http://www.seamonkey-project.org/", - "http://www.sina.com.cn/", - "http://www.sohu.com/", - "http://www.soso.com/", - "http://sourceforge.net/", - "http://www.spiegel.de/", - "http://tdm-gcc.tdragon.net/", - "http://www.tdrsmusic.com/", - "http://www.ubuntu.com/", - "http://status.twitter.com/", - "http://www.uol.com.br/", - "http://www.videohelp.com/", - "http://www.videolan.org/", - "http://www.weibo.com/", - "http://www.wikipedia.org/", - "http://www.winamp.com/", - "http://wordpress.com/", - "http://us.yahoo.com/", - "http://www.yandex.ru/", - "http://www.youtube.com/", - "http://www.zedo.com/", - "http://ffmpeg.zeranoe.com/", - NULL -}; - -static const int MIN_CONNSCORE = 8; -static const int VERSION_INFO_EXPIRES_MONTHS = 6; -static char *USER_AGENT_STR = "Mozilla/5.0 (X11; Linux i686; rv:7.0.1) Gecko/20111106 IceCat/7.0.1"; /////////////////////////////////////////////////////////////////////////////// +/* template T DO_ASYNC(T (*functionPointer)()) { @@ -177,31 +55,23 @@ T DO_ASYNC(T (*functionPointer)()) loop.exec(QEventLoop::ExcludeUserInputEvents); return watcher.result(); } +*/ -/////////////////////////////////////////////////////////////////////////////// +#define SHOW_HINT(TEXT, ICON) do \ +{ \ + ui->hintLabel->setText((TEXT)); \ + ui->hintIcon->setPixmap(QIcon((ICON)).pixmap(16,16)); \ + ui->hintIcon->show(); \ + ui->hintLabel->show(); \ +} \ +while(0) -class UpdateInfo -{ -public: - UpdateInfo(void) { resetInfo(); } - - void resetInfo(void) - { - m_buildNo = 0; - m_buildDate.setDate(1900, 1, 1); - m_downloadSite.clear(); - m_downloadAddress.clear(); - m_downloadFilename.clear(); - m_downloadFilecode.clear(); - } - - unsigned int m_buildNo; - QDate m_buildDate; - QString m_downloadSite; - QString m_downloadAddress; - QString m_downloadFilename; - QString m_downloadFilecode; -}; +#define UPDATE_TASKBAR(STATE, ICON) do \ +{ \ + WinSevenTaskbar::setTaskbarState(this->parentWidget(), (STATE)); \ + WinSevenTaskbar::setOverlayIcon(this->parentWidget(), &QIcon((ICON))); \ +} \ +while(0) /////////////////////////////////////////////////////////////////////////////// @@ -209,24 +79,21 @@ UpdateDialog::UpdateDialog(SettingsModel *settings, QWidget *parent) : QDialog(parent), ui(new Ui::UpdateDialog), - m_binaryWGet(lamexp_lookup_tool("wget.exe")), - m_binaryGnuPG(lamexp_lookup_tool("gpgv.exe")), - m_binaryUpdater(lamexp_lookup_tool("wupdate.exe")), - m_binaryKeys(lamexp_lookup_tool("gpgv.gpg")), - m_updateInfo(NULL), + m_thread(NULL), m_settings(settings), m_logFile(new QStringList()), m_betaUpdates(settings ? (settings->autoUpdateCheckBeta() || lamexp_version_demo()) : lamexp_version_demo()), m_success(false), m_firstShow(true), m_updateReadyToInstall(false), - m_updaterProcess(NULL) + m_updaterProcess(NULL), + m_binaryUpdater(lamexp_lookup_tool("wupdate.exe")) { - if(m_binaryWGet.isEmpty() || m_binaryGnuPG.isEmpty() || m_binaryUpdater.isEmpty() || m_binaryKeys.isEmpty()) + if(m_binaryUpdater.isEmpty()) { THROW("Tools not initialized correctly!"); } - + //Init the dialog, from the .ui file ui->setupUi(this); setWindowFlags(windowFlags() ^ Qt::WindowContextHelpButtonHint); @@ -257,9 +124,21 @@ UpdateDialog::UpdateDialog(SettingsModel *settings, QWidget *parent) UpdateDialog::~UpdateDialog(void) { - if(m_animator) m_animator->stop(); - - LAMEXP_DELETE(m_updateInfo); + if(m_animator) + { + m_animator->stop(); + } + + if(m_thread) + { + if(!m_thread->wait(1000)) + { + m_thread->terminate(); + m_thread->wait(); + } + } + + LAMEXP_DELETE(m_thread); LAMEXP_DELETE(m_logFile); LAMEXP_DELETE(m_animator); @@ -275,6 +154,17 @@ void UpdateDialog::showEvent(QShowEvent *event) if(m_firstShow) { + if(!m_thread) + { + m_thread = new UpdateCheckThread(m_betaUpdates); + connect(m_thread, SIGNAL(statusChanged(int)), this, SLOT(threadStatusChanged(int))); + connect(m_thread, SIGNAL(progressChanged(int)), this, SLOT(threadProgressChanged(int))); + connect(m_thread, SIGNAL(messageLogged(QString)), this, SLOT(threadMessageLogged(QString))); + connect(m_thread, SIGNAL(finished()), this, SLOT(threadFinished())); + connect(m_thread, SIGNAL(terminated()), this, SLOT(threadFinished())); + } + + threadStatusChanged(m_thread->getUpdateStatus()); ui->labelVersionInstalled->setText(QString("%1 %2 (%3)").arg(tr("Build"), QString::number(lamexp_version_build()), lamexp_version_date().toString(Qt::ISODate))); ui->labelVersionLatest->setText(QString("(%1)").arg(tr("Unknown"))); @@ -289,11 +179,7 @@ void UpdateDialog::showEvent(QShowEvent *event) ui->hintIcon->hide(); ui->frameAnimation->hide(); - int counter = MIN_CONNSCORE + 2; - for(int i = 0; update_mirrors_prim[i]; i++) counter++; - for(int i = 0; update_mirrors_back[i]; i++) counter++; - - ui->progressBar->setMaximum(counter); + ui->progressBar->setMaximum(m_thread->getMaximumProgress()); ui->progressBar->setValue(0); m_updaterProcess = NULL; @@ -324,11 +210,7 @@ void UpdateDialog::keyPressEvent(QKeyEvent *e) } else if((e->key() == Qt::Key_F12) && e->modifiers().testFlag(Qt::ControlModifier)) { - if(ui->closeButton->isEnabled()) - { - testKnownWebSites(); - logButtonClicked(); - } + if(ui->closeButton->isEnabled()) testKnownHosts(); } else { @@ -360,16 +242,15 @@ void UpdateDialog::updateInit(void) void UpdateDialog::checkForUpdates(void) { - bool success = false; - int connectionScore = 0; + if(m_thread->isRunning()) + { + qWarning("Update in progress, cannot check for updates now!"); + } - // ----- Initialization ----- // - - m_updateInfo = new UpdateInfo; - - ui->progressBar->setValue(0); WinSevenTaskbar::setTaskbarState(this->parentWidget(), WinSevenTaskbar::WinSevenTaskbarNormalState); WinSevenTaskbar::setOverlayIcon(this->parentWidget(), &QIcon(":/icons/transmit_blue.png")); + + ui->progressBar->setValue(0); ui->installButton->setEnabled(false); ui->closeButton->setEnabled(false); ui->retryButton->setEnabled(false); @@ -382,477 +263,102 @@ void UpdateDialog::checkForUpdates(void) QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); QApplication::setOverrideCursor(Qt::WaitCursor); - // ----- Test Internet Connection ----- // - - ui->statusLabel->setText(tr("Testing your internet connection, please wait...")); - m_logFile->clear(); - m_logFile->append("Checking internet connection..."); - - const int networkStatus = DO_ASYNC(lamexp_network_status); - if(networkStatus == lamexp_network_non) + m_thread->start(); +} + +void UpdateDialog::threadStatusChanged(const int status) +{ + switch(status) { - m_logFile->append(QStringList() << "" << "Operating system reports that the computer is currently offline !!!"); - if(!ui->retryButton->isVisible()) ui->retryButton->show(); - if(!ui->logButton->isVisible()) ui->logButton->show(); - ui->closeButton->setEnabled(true); - ui->retryButton->setEnabled(true); - ui->logButton->setEnabled(true); - if(ui->frameAnimation->isVisible()) ui->frameAnimation->hide(); - ui->statusLabel->setText(tr("It appears that the computer currently is offline!")); - ui->progressBar->setValue(ui->progressBar->maximum()); - ui->hintIcon->setPixmap(QIcon(":/icons/network_error.png").pixmap(16,16)); - ui->hintLabel->setText(tr("Please make sure your computer is connected to the internet and try again.")); - ui->hintIcon->show(); - ui->hintLabel->show(); - LAMEXP_DELETE(m_updateInfo); - if(m_settings->soundsEnabled()) lamexp_play_sound(IDR_WAVE_ERROR, true); - QApplication::restoreOverrideCursor(); - ui->progressBar->setValue(ui->progressBar->maximum()); - WinSevenTaskbar::setTaskbarState(this->parentWidget(), WinSevenTaskbar::WinSevenTaskbarErrorState); - WinSevenTaskbar::setOverlayIcon(this->parentWidget(), &QIcon(":/icons/exclamation.png")); - return; - } - - ui->progressBar->setValue(1); - QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); - - // ----- Test Known Hosts Connectivity ----- // - - QStringList hostList; - for(int i = 0; known_hosts[i]; i++) - { - hostList << QString::fromLatin1(known_hosts[i]); - } - - lamexp_seed_rand(); - while(!hostList.isEmpty()) - { - QString currentHost = hostList.takeAt(lamexp_rand() % hostList.count()); - if(connectionScore < MIN_CONNSCORE) - { - m_logFile->append(QStringList() << "" << "Testing host:" << currentHost << ""); - QString outFile = QString("%1/%2.htm").arg(lamexp_temp_folder2(), lamexp_rand_str()); - bool httpOk = false; - if(getFile(currentHost, outFile, 0, &httpOk)) - { - connectionScore++; - ui->progressBar->setValue(qBound(1, connectionScore + 1, MIN_CONNSCORE + 1)); - QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); - lamexp_sleep(64); - } - if(httpOk) - { - connectionScore++; - ui->progressBar->setValue(qBound(1, connectionScore + 1, MIN_CONNSCORE + 1)); - QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); - lamexp_sleep(64); - } - QFile::remove(outFile); - } - } - - if(connectionScore < MIN_CONNSCORE) - { - if(!ui->retryButton->isVisible()) ui->retryButton->show(); - if(!ui->logButton->isVisible()) ui->logButton->show(); - ui->closeButton->setEnabled(true); - ui->retryButton->setEnabled(true); - ui->logButton->setEnabled(true); - if(ui->frameAnimation->isVisible()) ui->frameAnimation->hide(); - ui->statusLabel->setText(tr("Network connectivity test has failed!")); - ui->progressBar->setValue(ui->progressBar->maximum()); - ui->hintIcon->setPixmap(QIcon(":/icons/network_error.png").pixmap(16,16)); - ui->hintLabel->setText(tr("Please make sure your internet connection is working properly and try again.")); - ui->hintIcon->show(); - ui->hintLabel->show(); - LAMEXP_DELETE(m_updateInfo); - if(m_settings->soundsEnabled()) lamexp_play_sound(IDR_WAVE_ERROR, true); - QApplication::restoreOverrideCursor(); - ui->progressBar->setValue(ui->progressBar->maximum()); - WinSevenTaskbar::setTaskbarState(this->parentWidget(), WinSevenTaskbar::WinSevenTaskbarErrorState); - WinSevenTaskbar::setOverlayIcon(this->parentWidget(), &QIcon(":/icons/exclamation.png")); - return; - } - - // ----- Build Mirror List ----- // - - ui->statusLabel->setText(tr("Checking for new updates online, please wait...")); - m_logFile->append(QStringList() << "" << "----" << "" << "Checking for updates online..."); - - QStringList mirrorList; - for(int index = 0; update_mirrors_prim[index]; index++) - { - mirrorList << QString::fromLatin1(update_mirrors_prim[index]); - } - - lamexp_seed_rand(); - if(const int len = mirrorList.count()) - { - const int rounds = len * 1097; - for(int i = 0; i < rounds; i++) - { - mirrorList.swap(i % len, lamexp_rand() % len); - } - } - - for(int index = 0; update_mirrors_back[index]; index++) - { - mirrorList << QString::fromLatin1(update_mirrors_back[index]); - } - - // ----- Fetch Update Info From Server ----- // - - while(!mirrorList.isEmpty()) - { - QString currentMirror = mirrorList.takeFirst(); - ui->progressBar->setValue(ui->progressBar->value() + 1); - if(!success) - { - if(tryUpdateMirror(m_updateInfo, currentMirror)) - { - success = true; - } - } - else - { - QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); - lamexp_sleep(64); - } - } - - QApplication::restoreOverrideCursor(); - ui->progressBar->setValue(ui->progressBar->maximum()); - - if(!success) - { - if(!ui->retryButton->isVisible()) ui->retryButton->show(); - if(!ui->logButton->isVisible()) ui->logButton->show(); - ui->closeButton->setEnabled(true); - ui->retryButton->setEnabled(true); - ui->logButton->setEnabled(true); - if(ui->frameAnimation->isVisible()) ui->frameAnimation->hide(); - ui->statusLabel->setText(tr("Failed to fetch update information from server!")); - ui->progressBar->setValue(ui->progressBar->maximum()); - WinSevenTaskbar::setTaskbarState(this->parentWidget(), WinSevenTaskbar::WinSevenTaskbarErrorState); - WinSevenTaskbar::setOverlayIcon(this->parentWidget(), &QIcon(":/icons/exclamation.png")); - ui->hintIcon->setPixmap(QIcon(":/icons/server_error.png").pixmap(16,16)); - ui->hintLabel->setText(tr("Sorry, the update server might be busy at this time. Plase try again later.")); - ui->hintIcon->show(); - ui->hintLabel->show(); - LAMEXP_DELETE(m_updateInfo); - if(m_settings->soundsEnabled()) lamexp_play_sound(IDR_WAVE_ERROR, true); - return; - } - - // ----- Download New Program Version ----- // - - ui->labelVersionLatest->setText(QString("%1 %2 (%3)").arg(tr("Build"), QString::number(m_updateInfo->m_buildNo), m_updateInfo->m_buildDate.toString(Qt::ISODate))); - ui->infoLabel->show(); - ui->infoLabel->setText(QString("%1
%2").arg(tr("More information available at:"), m_updateInfo->m_downloadSite)); - QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); - - if(m_updateInfo->m_buildNo > lamexp_version_build()) - { - ui->installButton->setEnabled(true); + case UpdateCheckThread::UpdateStatus_NotStartedYet: + ui->statusLabel->setText(tr("Initializing, please wait...")); + break; + case UpdateCheckThread::UpdateStatus_CheckingConnection: + ui->statusLabel->setText(tr("Testing your internet connection, please wait...")); + break; + case UpdateCheckThread::UpdateStatus_FetchingUpdates: + ui->statusLabel->setText(tr("Checking for new updates online, please wait...")); + break; + case UpdateCheckThread::UpdateStatus_CompletedUpdateAvailable: ui->statusLabel->setText(tr("A new version of LameXP is available!")); - ui->hintIcon->setPixmap(QIcon(":/icons/shield_exclamation.png").pixmap(16,16)); - ui->hintLabel->setText(tr("We highly recommend all users to install this update as soon as possible.")); - if(ui->frameAnimation->isVisible()) ui->frameAnimation->hide(); - ui->hintIcon->show(); - ui->hintLabel->show(); - WinSevenTaskbar::setOverlayIcon(this->parentWidget(), &QIcon(":/icons/shield_exclamation.png")); - lamexp_beep(lamexp_beep_info); - } - else if(m_updateInfo->m_buildNo == lamexp_version_build()) - { + SHOW_HINT(tr("We highly recommend all users to install this update as soon as possible."), ":/icons/shield_exclamation.png"); + UPDATE_TASKBAR(WinSevenTaskbar::WinSevenTaskbarNormalState, ":/icons/shield_exclamation.png"); + break; + case UpdateCheckThread::UpdateStatus_CompletedNoUpdates: ui->statusLabel->setText(tr("No new updates available at this time.")); - ui->hintIcon->setPixmap(QIcon(":/icons/shield_green.png").pixmap(16,16)); - ui->hintLabel->setText(tr("Your version of LameXP is still up-to-date. Please check for updates regularly!")); - if(ui->frameAnimation->isVisible()) ui->frameAnimation->hide(); - ui->hintIcon->show(); - ui->hintLabel->show(); - WinSevenTaskbar::setOverlayIcon(this->parentWidget(), &QIcon(":/icons/shield_green.png")); - lamexp_beep(lamexp_beep_info); - } - else - { + SHOW_HINT(tr("Your version of LameXP is still up-to-date. Please check for updates regularly!"), ":/icons/shield_green.png"); + UPDATE_TASKBAR(WinSevenTaskbar::WinSevenTaskbarNormalState, ":/icons/shield_green.png"); + break; + case UpdateCheckThread::UpdateStatus_CompletedNewVersionOlder: ui->statusLabel->setText(tr("Your version appears to be newer than the latest release.")); - ui->hintIcon->setPixmap(QIcon(":/icons/shield_error.png").pixmap(16,16)); - ui->hintLabel->setText(tr("This usually indicates your are currently using a pre-release version of LameXP.")); - if(ui->frameAnimation->isVisible()) ui->frameAnimation->hide(); - ui->hintIcon->show(); - ui->hintLabel->show(); - WinSevenTaskbar::setOverlayIcon(this->parentWidget(), &QIcon(":/icons/shield_error.png")); - lamexp_beep(lamexp_beep_warning); + SHOW_HINT(tr("This usually indicates your are currently using a pre-release version of LameXP."), ":/icons/shield_error.png"); + UPDATE_TASKBAR(WinSevenTaskbar::WinSevenTaskbarNormalState, ":/icons/shield_error.png"); + break; + case UpdateCheckThread::UpdateStatus_ErrorNoConnection: + ui->statusLabel->setText(tr("It appears that the computer currently is offline!")); + SHOW_HINT(tr("Please make sure your computer is connected to the internet and try again."), ":/icons/network_error.png"); + UPDATE_TASKBAR(WinSevenTaskbar::WinSevenTaskbarErrorState, ":/icons/exclamation.png"); + break; + case UpdateCheckThread::UpdateStatus_ErrorConnectionTestFailed: + ui->statusLabel->setText(tr("Network connectivity test has failed!")); + SHOW_HINT(tr("Please make sure your computer is connected to the internet and try again."), ":/icons/network_error.png"); + UPDATE_TASKBAR(WinSevenTaskbar::WinSevenTaskbarErrorState, ":/icons/exclamation.png"); + break; + case UpdateCheckThread::UpdateStatus_ErrorFetchUpdateInfo: + ui->statusLabel->setText(tr("Failed to fetch update information from server!")); + SHOW_HINT(tr("Sorry, the update server might be busy at this time. Plase try again later."), ":/icons/server_error.png"); + UPDATE_TASKBAR(WinSevenTaskbar::WinSevenTaskbarErrorState, ":/icons/exclamation.png"); + break; + default: + qWarning("Unknown status %d !!!", int(status)); } - - ui->closeButton->setEnabled(true); - if(ui->retryButton->isVisible()) ui->retryButton->hide(); - if(ui->logButton->isVisible()) ui->logButton->hide(); - if(ui->frameAnimation->isVisible()) ui->frameAnimation->hide(); - - m_success = true; } -bool UpdateDialog::tryUpdateMirror(UpdateInfo *updateInfo, const QString &url) +void UpdateDialog::threadProgressChanged(const int progress) { - bool success = false; - m_logFile->append(QStringList() << "" << "Trying mirror:" << url); + ui->progressBar->setValue(progress); +} - QString randPart = lamexp_rand_str(); - QString outFileVersionInfo = QString("%1/%2.ver").arg(lamexp_temp_folder2(), randPart); - QString outFileSignature = QString("%1/%2.sig").arg(lamexp_temp_folder2(), randPart); +void UpdateDialog::threadMessageLogged(const QString &message) +{ + (*m_logFile) << message; +} - m_logFile->append(QStringList() << "" << "Downloading update info:"); - bool ok1 = getFile(QString("%1%2").arg(url, mirror_url_postfix[m_betaUpdates ? 1 : 0]), outFileVersionInfo); +void UpdateDialog::threadFinished(void) +{ + const bool bSuccess = m_thread->getSuccess(); + + ui->closeButton->setEnabled(true); + if(ui->frameAnimation->isVisible()) ui->frameAnimation->hide(); + ui->progressBar->setValue(ui->progressBar->maximum()); - m_logFile->append(QStringList() << "" << "Downloading signature:"); - bool ok2 = getFile(QString("%1%2.sig").arg(url, mirror_url_postfix[m_betaUpdates ? 1 : 0]), outFileSignature); - - if(ok1 && ok2) + if(!bSuccess) { - m_logFile->append(QStringList() << "" << "Download okay, checking signature:"); - if(checkSignature(outFileVersionInfo, outFileSignature)) - { - m_logFile->append(QStringList() << "" << "Signature okay, parsing info:"); - success = parseVersionInfo(outFileVersionInfo, updateInfo); - } - else - { - m_logFile->append(QStringList() << "" << "Bad signature, take care!"); - } + if(m_settings->soundsEnabled()) lamexp_play_sound(IDR_WAVE_ERROR, true); } else { - m_logFile->append(QStringList() << "" << "Download has failed!"); - } + const bool bHaveUpdate = (m_thread->getUpdateStatus() == UpdateCheckThread::UpdateStatus_CompletedUpdateAvailable); + ui->installButton->setEnabled(bHaveUpdate); + lamexp_beep(bHaveUpdate ? lamexp_beep_info : lamexp_beep_warning); - QFile::remove(outFileVersionInfo); - QFile::remove(outFileSignature); - - return success; -} - -bool UpdateDialog::getFile(const QString &url, const QString &outFile, unsigned int maxRedir, bool *httpOk) -{ - QFileInfo output(outFile); - output.setCaching(false); - if(httpOk) *httpOk = false; - - if(output.exists()) - { - QFile::remove(output.canonicalFilePath()); - if(output.exists()) + if(const UpdateInfo *const updateInfo = m_thread->getUpdateInfo()) { - return false; + ui->infoLabel->setText(QString("%1
%2").arg(tr("More information available at:"), updateInfo->m_downloadSite)); + ui->labelVersionLatest->setText(QString("%1 %2 (%3)").arg(tr("Build"), QString::number(updateInfo->m_buildNo), updateInfo->m_buildDate.toString(Qt::ISODate))); + ui->infoLabel->show(); } + + m_success = true; } - QProcess process; - lamexp_init_process(process, output.absolutePath()); + ui->retryButton->setVisible(!bSuccess); + ui->logButton->setVisible(!bSuccess); + ui->retryButton->setEnabled(!bSuccess); + ui->logButton->setEnabled(!bSuccess); - QStringList args; - args << "--no-cache" << "--no-dns-cache" << QString().sprintf("--max-redirect=%u", maxRedir); - args << QString("--referer=%1://%2/").arg(QUrl(url).scheme(), QUrl(url).host()) << "-U" << USER_AGENT_STR; - args << "-O" << output.fileName() << url; - - QEventLoop loop; - connect(&process, SIGNAL(error(QProcess::ProcessError)), &loop, SLOT(quit())); - connect(&process, SIGNAL(finished(int,QProcess::ExitStatus)), &loop, SLOT(quit())); - connect(&process, SIGNAL(readyRead()), &loop, SLOT(quit())); - - QTimer timer; - timer.setSingleShot(true); - timer.setInterval(25000); - connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit())); - - const QRegExp httpResponseOK("200 OK$"); - - process.start(m_binaryWGet, args); - - if(!process.waitForStarted()) - { - return false; - } - - timer.start(); - - while(process.state() == QProcess::Running) - { - loop.exec(); - bool bTimeOut = (!timer.isActive()); - while(process.canReadLine()) - { - QString line = QString::fromLatin1(process.readLine()).simplified(); - if(line.contains(httpResponseOK)) - { - line.append(" [OK]"); - if(httpOk) *httpOk = true; - } - m_logFile->append(line); - } - if(bTimeOut) - { - qWarning("WGet process timed out <-- killing!"); - process.kill(); - process.waitForFinished(); - m_logFile->append("!!! TIMEOUT !!!"); - return false; - } - } - - timer.stop(); - timer.disconnect(&timer, SIGNAL(timeout()), &loop, SLOT(quit())); - - m_logFile->append(QString().sprintf("Exited with code %d", process.exitCode())); - return (process.exitCode() == 0) && output.exists() && output.isFile(); -} - -bool UpdateDialog::checkSignature(const QString &file, const QString &signature) -{ - if(QFileInfo(file).absolutePath().compare(QFileInfo(signature).absolutePath(), Qt::CaseInsensitive) != 0) - { - qWarning("CheckSignature: File and signature should be in same folder!"); - return false; - } - if(QFileInfo(file).absolutePath().compare(QFileInfo(m_binaryKeys).absolutePath(), Qt::CaseInsensitive) != 0) - { - qWarning("CheckSignature: File and keyring should be in same folder!"); - return false; - } - - QProcess process; - lamexp_init_process(process, QFileInfo(file).absolutePath()); - - QEventLoop loop; - connect(&process, SIGNAL(error(QProcess::ProcessError)), &loop, SLOT(quit())); - connect(&process, SIGNAL(finished(int,QProcess::ExitStatus)), &loop, SLOT(quit())); - connect(&process, SIGNAL(readyRead()), &loop, SLOT(quit())); - - process.start(m_binaryGnuPG, QStringList() << "--homedir" << "." << "--keyring" << QFileInfo(m_binaryKeys).fileName() << QFileInfo(signature).fileName() << QFileInfo(file).fileName()); - - if(!process.waitForStarted()) - { - return false; - } - - while(process.state() == QProcess::Running) - { - loop.exec(); - while(process.canReadLine()) - { - m_logFile->append(QString::fromLatin1(process.readLine()).simplified()); - } - } - - m_logFile->append(QString().sprintf("Exited with code %d", process.exitCode())); - return (process.exitCode() == 0); -} - -bool UpdateDialog::parseVersionInfo(const QString &file, UpdateInfo *updateInfo) -{ - QRegExp value("^(\\w+)=(.+)$"); - QRegExp section("^\\[(.+)\\]$"); - - QDate updateInfoDate; - updateInfo->resetInfo(); - - QFile data(file); - if(!data.open(QIODevice::ReadOnly)) - { - qWarning("Cannot open update info file for reading!"); - return false; - } - - bool inHeader = false; - bool inSection = false; - - while(!data.atEnd()) - { - QString line = QString::fromLatin1(data.readLine()).trimmed(); - if(section.indexIn(line) >= 0) - { - m_logFile->append(QString("Sec: [%1]").arg(section.cap(1))); - inSection = (section.cap(1).compare(section_id, Qt::CaseInsensitive) == 0); - inHeader = (section.cap(1).compare(header_id, Qt::CaseInsensitive) == 0); - continue; - } - if(inSection && (value.indexIn(line) >= 0)) - { - m_logFile->append(QString("Val: '%1' ==> '%2").arg(value.cap(1), value.cap(2))); - if(value.cap(1).compare("BuildNo", Qt::CaseInsensitive) == 0) - { - bool ok = false; - unsigned int temp = value.cap(2).toUInt(&ok); - if(ok) updateInfo->m_buildNo = temp; - } - else if(value.cap(1).compare("BuildDate", Qt::CaseInsensitive) == 0) - { - QDate temp = QDate::fromString(value.cap(2).trimmed(), Qt::ISODate); - if(temp.isValid()) updateInfo->m_buildDate = temp; - } - else if(value.cap(1).compare("DownloadSite", Qt::CaseInsensitive) == 0) - { - updateInfo->m_downloadSite = value.cap(2).trimmed(); - } - else if(value.cap(1).compare("DownloadAddress", Qt::CaseInsensitive) == 0) - { - updateInfo->m_downloadAddress = value.cap(2).trimmed(); - } - else if(value.cap(1).compare("DownloadFilename", Qt::CaseInsensitive) == 0) - { - updateInfo->m_downloadFilename = value.cap(2).trimmed(); - } - else if(value.cap(1).compare("DownloadFilecode", Qt::CaseInsensitive) == 0) - { - updateInfo->m_downloadFilecode = value.cap(2).trimmed(); - } - } - if(inHeader && (value.indexIn(line) >= 0)) - { - m_logFile->append(QString("Val: '%1' ==> '%2").arg(value.cap(1), value.cap(2))); - if(value.cap(1).compare("TimestampCreated", Qt::CaseInsensitive) == 0) - { - QDate temp = QDate::fromString(value.cap(2).trimmed(), Qt::ISODate); - if(temp.isValid()) updateInfoDate = temp; - } - } - } - - if(!updateInfoDate.isValid()) - { - updateInfo->resetInfo(); - m_logFile->append("WARNING: Version info timestamp is missing!"); - return false; - } - else if(updateInfoDate.addMonths(VERSION_INFO_EXPIRES_MONTHS) < lamexp_current_date_safe()) - { - updateInfo->resetInfo(); - m_logFile->append(QString::fromLatin1("WARNING: This version info has expired at %1!").arg(updateInfoDate.addMonths(VERSION_INFO_EXPIRES_MONTHS).toString(Qt::ISODate))); - return false; - } - else if(lamexp_current_date_safe() < updateInfoDate) - { - m_logFile->append("Version info is from the future, take care!"); - qWarning("Version info is from the future, take care!"); - } - - bool complete = true; - - if(!(updateInfo->m_buildNo > 0)) complete = false; - if(!(updateInfo->m_buildDate.year() >= 2010)) complete = false; - if(updateInfo->m_downloadSite.isEmpty()) complete = false; - if(updateInfo->m_downloadAddress.isEmpty()) complete = false; - if(updateInfo->m_downloadFilename.isEmpty()) complete = false; - if(updateInfo->m_downloadFilecode.isEmpty()) complete = false; - - if(!complete) - { - m_logFile->append("WARNING: Version info is incomplete!"); - } - - return complete; + QApplication::restoreOverrideCursor(); } void UpdateDialog::linkActivated(const QString &link) @@ -866,7 +372,7 @@ void UpdateDialog::applyUpdate(void) ui->closeButton->setEnabled(false); ui->retryButton->setEnabled(false); - if(m_updateInfo) + if(const UpdateInfo *updateInfo = m_thread->getUpdateInfo()) { ui->statusLabel->setText(tr("Update is being downloaded, please be patient...")); ui->frameAnimation->show(); @@ -886,16 +392,15 @@ void UpdateDialog::applyUpdate(void) connect(&process, SIGNAL(error(QProcess::ProcessError)), &loop, SLOT(quit())); connect(&process, SIGNAL(finished(int,QProcess::ExitStatus)), &loop, SLOT(quit())); - args << QString("/Location=%1").arg(m_updateInfo->m_downloadAddress); - args << QString("/Filename=%1").arg(m_updateInfo->m_downloadFilename); - args << QString("/TicketID=%1").arg(m_updateInfo->m_downloadFilecode); + args << QString("/Location=%1").arg(updateInfo->m_downloadAddress); + args << QString("/Filename=%1").arg(updateInfo->m_downloadFilename); + args << QString("/TicketID=%1").arg(updateInfo->m_downloadFilecode); args << QString("/ToFolder=%1").arg(QDir::toNativeSeparators(QDir(QApplication::applicationDirPath()).canonicalPath())); args << QString("/ToExFile=%1.exe").arg(QFileInfo(QFileInfo(QApplication::applicationFilePath()).canonicalFilePath()).completeBaseName()); - args << QString("/AppTitle=LameXP (Build #%1)").arg(QString::number(m_updateInfo->m_buildNo)); + args << QString("/AppTitle=LameXP (Build #%1)").arg(QString::number(updateInfo->m_buildNo)); QApplication::setOverrideCursor(Qt::WaitCursor); - WinSevenTaskbar::setTaskbarState(this->parentWidget(), WinSevenTaskbar::WinSevenTaskbarIndeterminateState); - WinSevenTaskbar::setOverlayIcon(this->parentWidget(), &QIcon(":/icons/transmit_blue.png")); + UPDATE_TASKBAR(WinSevenTaskbar::WinSevenTaskbarIndeterminateState, ":/icons/transmit_blue.png"); process.start(m_binaryUpdater, args); bool updateStarted = process.waitForStarted(); @@ -946,136 +451,30 @@ void UpdateDialog::progressBarValueChanged(int value) WinSevenTaskbar::setTaskbarProgress(this->parentWidget(), value, ui->progressBar->maximum()); } -void UpdateDialog::testKnownWebSites(void) +void UpdateDialog::testKnownHosts(void) { - int connectionScore = 0; - - // ----- Initialization ----- // - - ui->progressBar->setValue(0); - WinSevenTaskbar::setTaskbarState(this->parentWidget(), WinSevenTaskbar::WinSevenTaskbarNormalState); - WinSevenTaskbar::setOverlayIcon(this->parentWidget(), &QIcon(":/icons/transmit_blue.png")); - ui->installButton->setEnabled(false); - ui->closeButton->setEnabled(false); - ui->retryButton->setEnabled(false); - ui->logButton->setEnabled(false); - if(ui->infoLabel->isVisible()) ui->infoLabel->hide(); - if(ui->hintLabel->isVisible()) ui->hintLabel->hide(); - if(ui->hintIcon->isVisible()) ui->hintIcon->hide(); - ui->frameAnimation->show(); - - QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); - QApplication::setOverrideCursor(Qt::WaitCursor); - - // ----- Test Internet Connection ----- // - ui->statusLabel->setText("Testing all known hosts, this may take a few minutes..."); - - m_logFile->clear(); - m_logFile->append("Checking internet connection..."); - const int networkStatus = DO_ASYNC(lamexp_network_status); - if(networkStatus == lamexp_network_non) + if(UpdateCheckThread *testThread = new UpdateCheckThread(m_betaUpdates, true)) { - m_logFile->append(QStringList() << "" << "Operating system reports that the computer is currently offline !!!"); - if(!ui->retryButton->isVisible()) ui->retryButton->show(); - if(!ui->logButton->isVisible()) ui->logButton->show(); - ui->closeButton->setEnabled(true); - ui->retryButton->setEnabled(true); - ui->logButton->setEnabled(true); - if(ui->frameAnimation->isVisible()) ui->frameAnimation->hide(); - ui->statusLabel->setText(tr("It appears that the computer currently is offline!")); - ui->progressBar->setValue(ui->progressBar->maximum()); - ui->hintIcon->setPixmap(QIcon(":/icons/network_error.png").pixmap(16,16)); - ui->hintLabel->setText(tr("Please make sure your computer is connected to the internet and try again.")); - ui->hintIcon->show(); - ui->hintLabel->show(); - LAMEXP_DELETE(m_updateInfo); - if(m_settings->soundsEnabled()) lamexp_play_sound(IDR_WAVE_ERROR, true); - QApplication::restoreOverrideCursor(); - ui->progressBar->setValue(ui->progressBar->maximum()); - WinSevenTaskbar::setTaskbarState(this->parentWidget(), WinSevenTaskbar::WinSevenTaskbarErrorState); - WinSevenTaskbar::setOverlayIcon(this->parentWidget(), &QIcon(":/icons/exclamation.png")); - return; - } - - // ----- Test Known Hosts Connectivity ----- // + QEventLoop loop; + m_logFile->clear(); - QStringList hostList; - for(int i = 0; known_hosts[i]; i++) - { - hostList << QString::fromLatin1(known_hosts[i]); - } + connect(testThread, SIGNAL(messageLogged(QString)), this, SLOT(threadMessageLogged(QString))); + connect(testThread, SIGNAL(finished()), &loop, SLOT(quit())); + connect(testThread, SIGNAL(terminated()), &loop, SLOT(quit())); - qDebug("[Known Hosts]"); - - int hostCount = hostList.count(); - while(!hostList.isEmpty()) - { - QString currentHost = hostList.takeFirst(); - ui->progressBar->setValue(qRound((static_cast(ui->progressBar->maximum() - 1) / static_cast(hostCount)) * static_cast(connectionScore)) + 1); - qDebug("Testing: %s", currentHost.toLatin1().constData()); - m_logFile->append(QStringList() << "" << "Testing host:" << currentHost << ""); - QString outFile = QString("%1/%2.htm").arg(lamexp_temp_folder2(), lamexp_rand_str()); - bool httpOk = false; - if(getFile(currentHost, outFile, 0, &httpOk)) + testThread->start(); + while(testThread->isRunning()) { - connectionScore++; + QTimer::singleShot(5000, &loop, SLOT(quit())); + loop.exec(QEventLoop::ExcludeUserInputEvents); } - else - { - if(httpOk) - { - qWarning("\nConnectivity test was SLOW on the following site:\n%s\n", currentHost.toLatin1().constData()); - connectionScore++; - } - else - { - qWarning("\nConnectivity test FAILED on the following site:\n%s\n", currentHost.toLatin1().constData()); - } - } - QFile::remove(outFile); - } - if(connectionScore < hostCount) - { - if(!ui->retryButton->isVisible()) ui->retryButton->show(); - if(!ui->logButton->isVisible()) ui->logButton->show(); - ui->closeButton->setEnabled(true); - ui->retryButton->setEnabled(true); - ui->logButton->setEnabled(true); - if(ui->frameAnimation->isVisible()) ui->frameAnimation->hide(); - ui->statusLabel->setText("At least one host could not be reached!"); - ui->progressBar->setValue(ui->progressBar->maximum()); - ui->hintIcon->setPixmap(QIcon(":/icons/network_error.png").pixmap(16,16)); - ui->hintLabel->setText("Please make sure your internet connection is working properly and try again."); - ui->hintIcon->show(); - ui->hintLabel->show(); - LAMEXP_DELETE(m_updateInfo); - if(m_settings->soundsEnabled()) lamexp_play_sound(IDR_WAVE_ERROR, true); - QApplication::restoreOverrideCursor(); - ui->progressBar->setValue(ui->progressBar->maximum()); - WinSevenTaskbar::setTaskbarState(this->parentWidget(), WinSevenTaskbar::WinSevenTaskbarErrorState); - WinSevenTaskbar::setOverlayIcon(this->parentWidget(), &QIcon(":/icons/exclamation.png")); - return; + LAMEXP_DELETE(testThread); + logButtonClicked(); } - // ----- Done ----- // - - QApplication::restoreOverrideCursor(); - ui->progressBar->setValue(ui->progressBar->maximum()); - ui->statusLabel->setText("Test completed."); - ui->hintIcon->setPixmap(QIcon(":/icons/shield_green.png").pixmap(16,16)); - ui->hintLabel->setText("Congratulations, the test has completed."); - if(ui->frameAnimation->isVisible()) ui->frameAnimation->hide(); - ui->hintIcon->show(); - ui->hintLabel->show(); - WinSevenTaskbar::setOverlayIcon(this->parentWidget(), &QIcon(":/icons/shield_green.png")); lamexp_beep(lamexp_beep_info); - - ui->closeButton->setEnabled(true); - if(ui->retryButton->isVisible()) ui->retryButton->hide(); - if(ui->logButton->isVisible()) ui->logButton->hide(); - if(ui->frameAnimation->isVisible()) ui->frameAnimation->hide(); } diff --git a/src/Dialog_Update.h b/src/Dialog_Update.h index c029f412..accbf970 100644 --- a/src/Dialog_Update.h +++ b/src/Dialog_Update.h @@ -27,6 +27,7 @@ class UpdateInfo; class SettingsModel; class QMovie; +class UpdateCheckThread; //UIC forward declartion namespace Ui { @@ -53,6 +54,11 @@ private slots: void logButtonClicked(void); void progressBarValueChanged(int value); + void threadStatusChanged(const int status); + void threadProgressChanged(const int progress); + void threadMessageLogged(const QString &message); + void threadFinished(void); + protected: virtual void showEvent(QShowEvent *event); virtual void closeEvent(QCloseEvent *event); @@ -65,24 +71,19 @@ protected: private: Ui::UpdateDialog *ui; //for Qt UIC - bool tryUpdateMirror(UpdateInfo *updateInfo, const QString &url); - bool getFile(const QString &url, const QString &outFile, unsigned int maxRedir = 5, bool *httpOk = NULL); - bool checkSignature(const QString &file, const QString &signature); - bool parseVersionInfo(const QString &file, UpdateInfo *updateInfo); - void testKnownWebSites(void); + const QString m_binaryUpdater; - UpdateInfo *m_updateInfo; + UpdateCheckThread *m_thread; QStringList *m_logFile; SettingsModel *m_settings; QMovie *m_animator; - - const QString m_binaryWGet; - const QString m_binaryGnuPG; - const QString m_binaryUpdater; - const QString m_binaryKeys; + unsigned long m_updaterProcess; bool m_success; bool m_updateReadyToInstall; bool m_firstShow; + + void testKnownHosts(void); + }; diff --git a/src/Thread_CheckUpdate.cpp b/src/Thread_CheckUpdate.cpp new file mode 100644 index 00000000..e528f886 --- /dev/null +++ b/src/Thread_CheckUpdate.cpp @@ -0,0 +1,710 @@ +/////////////////////////////////////////////////////////////////////////////// +// LameXP - Audio Encoder Front-End +// Copyright (C) 2004-2013 LoRd_MuldeR +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version, but always including the *additional* +// restrictions defined in the "License.txt" file. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// http://www.gnu.org/licenses/gpl-2.0.txt +/////////////////////////////////////////////////////////////////////////////// + +#include "Thread_CheckUpdate.h" + +#include "Global.h" + +#include +#include +#include +#include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +// CONSTANTS +/////////////////////////////////////////////////////////////////////////////// + +static const char *header_id = "!Update"; +static const char *section_id = "LameXP"; + +static const char *mirror_url_postfix[] = +{ + "update.ver", + "update_beta.ver", + NULL +}; + +static const char *update_mirrors_prim[] = +{ + "http://muldersoft.com/", + "http://mulder.bplaced.net/", + "http://mulder.cwsurf.de/", + "http://mulder.6te.net/", + "http://mulder.webuda.com/", + "http://mulder.byethost13.com/", + "http://muldersoft.kilu.de/", + "http://muldersoft.zxq.net/", + "http://lamexp.sourceforge.net/", + "http://lamexp.berlios.de/", + "http://lordmulder.github.com/LameXP/", + "http://lord_mulder.bitbucket.org/", + "http://www.tricksoft.de/", + NULL +}; + +static const char *update_mirrors_back[] = +{ + "http://mplayer.savedonthe.net/", + NULL +}; + +static const char *known_hosts[] = //Taken form: http://www.alexa.com/topsites !!! +{ + "http://www.163.com/", + "http://www.ac3filter.net/", + "http://www.amazon.com/", + "http://www.aol.com/", + "http://www.apache.org/", + "http://www.apple.com/", + "http://www.adobe.com/", + "http://www.avidemux.org/", + "http://www.babylon.com/", + "http://www.baidu.com/", + "http://www.bbc.co.uk/", + "http://www.berlios.de/", + "http://www.bing.com/", + "http://www.cnet.com/", + "http://cnzz.com/", + "http://codecs.com/", + "http://www.codeplex.com/", + "http://qt.digia.com/", + "http://www.ebay.com/", + "http://www.equation.com/", + "http://fc2.com/", + "http://www.ffmpeg.org/", + "http://www.flickr.com/", + "http://blog.gitorious.org/", + "http://git-scm.com/", + "http://www.gnome.org/", + "http://www.gnu.org/", + "http://go.com/", + "http://code.google.com/", + "http://www.heise.de/", + "http://www.huffingtonpost.co.uk/", + "http://www.iana.org/", + "http://www.imdb.com/", + "http://www.imgburn.com/", + "http://imgur.com/", + "http://en.jd.com/", + "http://mirrors.kernel.org/", + "http://www.libav.org/", + "http://www.linkedin.com/about-us", + "http://www.livedoor.com/", + "http://www.livejournal.com/", + "http://mail.ru/", + "http://www.mediafire.com/", + "http://www.mozilla.org/en-US/", + "http://mplayerhq.hu/", + "http://www.msn.com/?st=1", + "http://oss.netfarm.it/", + "http://www.nytimes.com/", + "http://www.opera.com/", + "http://www.portablefreeware.com/", + "http://qt-project.org/", + "http://www.quakelive.com/", + "http://www.seamonkey-project.org/", + "http://www.sina.com.cn/", + "http://www.sohu.com/", + "http://www.soso.com/", + "http://sourceforge.net/", + "http://www.spiegel.de/", + "http://tdm-gcc.tdragon.net/", + "http://www.tdrsmusic.com/", + "http://www.ubuntu.com/", + "http://status.twitter.com/", + "http://www.uol.com.br/", + "http://www.videohelp.com/", + "http://www.videolan.org/", + "http://www.weibo.com/", + "http://www.wikipedia.org/", + "http://www.winamp.com/", + "http://wordpress.com/", + "http://us.yahoo.com/", + "http://www.yandex.ru/", + "http://www.youtube.com/", + "http://www.zedo.com/", + "http://ffmpeg.zeranoe.com/", + NULL +}; + +static const int MIN_CONNSCORE = 8; +static const int VERSION_INFO_EXPIRES_MONTHS = 6; +static char *USER_AGENT_STR = "Mozilla/5.0 (X11; Linux i686; rv:7.0.1) Gecko/20111106 IceCat/7.0.1"; + +//Helper function +static int getMaxProgress(void) +{ + int counter = MIN_CONNSCORE + 2; + for(int i = 0; update_mirrors_prim[i]; i++) counter++; + for(int i = 0; update_mirrors_back[i]; i++) counter++; + return counter; +} + +//////////////////////////////////////////////////////////// +// Update Info Class +//////////////////////////////////////////////////////////// + +UpdateInfo::UpdateInfo(void) +{ + resetInfo(); +} + +void UpdateInfo::resetInfo(void) +{ + m_buildNo = 0; + m_buildDate.setDate(1900, 1, 1); + m_downloadSite.clear(); + m_downloadAddress.clear(); + m_downloadFilename.clear(); + m_downloadFilecode.clear(); +} + +//////////////////////////////////////////////////////////// +// Constructor & Destructor +//////////////////////////////////////////////////////////// + +UpdateCheckThread::UpdateCheckThread(const bool betaUpdates, const bool testMode) +: + m_updateInfo(new UpdateInfo()), + m_betaUpdates(betaUpdates), + m_testMode(testMode), + m_binaryWGet(lamexp_lookup_tool("wget.exe")), + m_binaryGnuPG(lamexp_lookup_tool("gpgv.exe")), + m_binaryKeys(lamexp_lookup_tool("gpgv.gpg")), + m_maxProgress(getMaxProgress()) +{ + m_success = false; + m_status = UpdateStatus_NotStartedYet; + m_progress = 0; + + if(m_binaryWGet.isEmpty() || m_binaryGnuPG.isEmpty() || m_binaryKeys.isEmpty()) + { + THROW("Tools not initialized correctly!"); + } +} + +UpdateCheckThread::~UpdateCheckThread(void) +{ + delete m_updateInfo; +} + +//////////////////////////////////////////////////////////// +// Protected functions +//////////////////////////////////////////////////////////// + +void UpdateCheckThread::run(void) +{ + qDebug("Update checker thread started!"); + + try + { + m_testMode ? testKnownHosts() : checkForUpdates(); + } + catch(const std::exception &error) + { + fflush(stdout); fflush(stderr); + fprintf(stderr, "\nGURU MEDITATION !!!\n\nException error:\n%s\n", error.what()); + lamexp_fatal_exit(L"Unhandeled C++ exception error, application will exit!"); + } + catch(...) + { + fflush(stdout); fflush(stderr); + fprintf(stderr, "\nGURU MEDITATION !!!\n\nUnknown exception error!\n"); + lamexp_fatal_exit(L"Unhandeled C++ exception error, application will exit!"); + } + + qDebug("Update checker thread completed."); +} + +void UpdateCheckThread::checkForUpdates(void) +{ + // ----- Initialization ----- // + + m_success = false; + m_updateInfo->resetInfo(); + setProgress(0); + + // ----- Test Internet Connection ----- // + + int connectionScore = 0; + + log("Checking internet connection..."); + setStatus(UpdateStatus_CheckingConnection); + + const int networkStatus = lamexp_network_status(); + if(networkStatus == lamexp_network_non) + { + log("", "Operating system reports that the computer is currently offline !!!"); + setProgress(m_maxProgress); + setStatus(UpdateStatus_ErrorNoConnection); + return; + } + + setProgress(1); + + // ----- Test Known Hosts Connectivity ----- // + + QStringList hostList; + for(int i = 0; known_hosts[i]; i++) + { + hostList << QString::fromLatin1(known_hosts[i]); + } + + lamexp_seed_rand(); + while(!hostList.isEmpty()) + { + QString currentHost = hostList.takeAt(lamexp_rand() % hostList.count()); + if(connectionScore < MIN_CONNSCORE) + { + log("", "Testing host:", currentHost); + QString outFile = QString("%1/%2.htm").arg(lamexp_temp_folder2(), lamexp_rand_str()); + bool httpOk = false; + if(getFile(currentHost, outFile, 0, &httpOk)) + { + connectionScore++; + setProgress(qBound(1, connectionScore + 1, MIN_CONNSCORE + 1)); + lamexp_sleep(64); + } + if(httpOk) + { + connectionScore++; + setProgress(qBound(1, connectionScore + 1, MIN_CONNSCORE + 1)); + lamexp_sleep(64); + } + QFile::remove(outFile); + } + } + + if(connectionScore < MIN_CONNSCORE) + { + setProgress(m_maxProgress); + setStatus(UpdateStatus_ErrorConnectionTestFailed); + return; + } + + // ----- Build Mirror List ----- // + + log("", "----", "", "Checking for updates online..."); + setStatus(UpdateStatus_FetchingUpdates); + + QStringList mirrorList; + for(int index = 0; update_mirrors_prim[index]; index++) + { + mirrorList << QString::fromLatin1(update_mirrors_prim[index]); + } + + lamexp_seed_rand(); + if(const int len = mirrorList.count()) + { + const int rounds = len * 1097; + for(int i = 0; i < rounds; i++) + { + mirrorList.swap(i % len, lamexp_rand() % len); + } + } + + for(int index = 0; update_mirrors_back[index]; index++) + { + mirrorList << QString::fromLatin1(update_mirrors_back[index]); + } + + // ----- Fetch Update Info From Server ----- // + + while(!mirrorList.isEmpty()) + { + QString currentMirror = mirrorList.takeFirst(); + setProgress(m_progress + 1); + if(!m_success) + { + if(tryUpdateMirror(m_updateInfo, currentMirror)) + { + m_success = true; + } + } + else + { + lamexp_sleep(64); + } + } + + setProgress(m_maxProgress); + + if(m_success) + { + if(m_updateInfo->m_buildNo > lamexp_version_build()) + { + setStatus(UpdateStatus_CompletedUpdateAvailable); + } + else if(m_updateInfo->m_buildNo == lamexp_version_build()) + { + setStatus(UpdateStatus_CompletedNoUpdates); + } + else + { + setStatus(UpdateStatus_CompletedNewVersionOlder); + } + } + else + { + setStatus(UpdateStatus_ErrorFetchUpdateInfo); + } +} + +void UpdateCheckThread::testKnownHosts(void) +{ + QStringList hostList; + for(int i = 0; known_hosts[i]; i++) + { + hostList << QString::fromLatin1(known_hosts[i]); + } + + qDebug("\n[Known Hosts]"); + log("Testing all known hosts...", "", "---"); + + int hostCount = hostList.count(); + while(!hostList.isEmpty()) + { + QString currentHost = hostList.takeFirst(); + qDebug("Testing: %s", currentHost.toLatin1().constData()); + log("", "Testing:", currentHost, ""); + QString outFile = QString("%1/%2.htm").arg(lamexp_temp_folder2(), lamexp_rand_str()); + bool httpOk = false; + if(!getFile(currentHost, outFile, 0, &httpOk)) + { + if(httpOk) + { + qWarning("\nConnectivity test was SLOW on the following site:\n%s\n", currentHost.toLatin1().constData()); + } + else + { + qWarning("\nConnectivity test FAILED on the following site:\n%s\n", currentHost.toLatin1().constData()); + } + } + log("", "---"); + QFile::remove(outFile); + } +} + +//////////////////////////////////////////////////////////// +// PRIVATE FUNCTIONS +//////////////////////////////////////////////////////////// + +void UpdateCheckThread::setStatus(const int status) +{ + if(m_status != status) + { + m_status = status; + emit statusChanged(status); + } +} + +void UpdateCheckThread::setProgress(const int progress) +{ + if(m_progress != progress) + { + m_progress = progress; + emit progressChanged(progress); + } +} + +void UpdateCheckThread::log(const QString &str1, const QString &str2, const QString &str3, const QString &str4) +{ + if(!str1.isNull()) emit messageLogged(str1); + if(!str2.isNull()) emit messageLogged(str2); + if(!str3.isNull()) emit messageLogged(str3); + if(!str4.isNull()) emit messageLogged(str4); +} + +bool UpdateCheckThread::tryUpdateMirror(UpdateInfo *updateInfo, const QString &url) +{ + bool success = false; + log("", "Trying mirror:", url); + + QString randPart = lamexp_rand_str(); + QString outFileVersionInfo = QString("%1/%2.ver").arg(lamexp_temp_folder2(), randPart); + QString outFileSignature = QString("%1/%2.sig").arg(lamexp_temp_folder2(), randPart); + + log("", "Downloading update info:"); + bool ok1 = getFile(QString("%1%2").arg(url, mirror_url_postfix[m_betaUpdates ? 1 : 0]), outFileVersionInfo); + + log("", "Downloading signature:"); + bool ok2 = getFile(QString("%1%2.sig").arg(url, mirror_url_postfix[m_betaUpdates ? 1 : 0]), outFileSignature); + + if(ok1 && ok2) + { + log("", "Download okay, checking signature:"); + if(checkSignature(outFileVersionInfo, outFileSignature)) + { + log("", "Signature okay, parsing info:"); + success = parseVersionInfo(outFileVersionInfo, updateInfo); + } + else + { + log("", "Bad signature, take care!"); + } + } + else + { + log("", "Download has failed!"); + } + + QFile::remove(outFileVersionInfo); + QFile::remove(outFileSignature); + + return success; +} + +bool UpdateCheckThread::getFile(const QString &url, const QString &outFile, unsigned int maxRedir, bool *httpOk) +{ + QFileInfo output(outFile); + output.setCaching(false); + if(httpOk) *httpOk = false; + + if(output.exists()) + { + QFile::remove(output.canonicalFilePath()); + if(output.exists()) + { + return false; + } + } + + QProcess process; + lamexp_init_process(process, output.absolutePath()); + + QStringList args; + args << "--no-cache" << "--no-dns-cache" << QString().sprintf("--max-redirect=%u", maxRedir); + args << QString("--referer=%1://%2/").arg(QUrl(url).scheme(), QUrl(url).host()) << "-U" << USER_AGENT_STR; + args << "-O" << output.fileName() << url; + + QEventLoop loop; + connect(&process, SIGNAL(error(QProcess::ProcessError)), &loop, SLOT(quit())); + connect(&process, SIGNAL(finished(int,QProcess::ExitStatus)), &loop, SLOT(quit())); + connect(&process, SIGNAL(readyRead()), &loop, SLOT(quit())); + + QTimer timer; + timer.setSingleShot(true); + timer.setInterval(25000); + connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit())); + + const QRegExp httpResponseOK("200 OK$"); + + process.start(m_binaryWGet, args); + + if(!process.waitForStarted()) + { + return false; + } + + timer.start(); + + while(process.state() == QProcess::Running) + { + loop.exec(); + bool bTimeOut = (!timer.isActive()); + while(process.canReadLine()) + { + QString line = QString::fromLatin1(process.readLine()).simplified(); + if(line.contains(httpResponseOK)) + { + line.append(" [OK]"); + if(httpOk) *httpOk = true; + } + log(line); + } + if(bTimeOut) + { + qWarning("WGet process timed out <-- killing!"); + process.kill(); + process.waitForFinished(); + log("!!! TIMEOUT !!!"); + return false; + } + } + + timer.stop(); + timer.disconnect(&timer, SIGNAL(timeout()), &loop, SLOT(quit())); + + log(QString().sprintf("Exited with code %d", process.exitCode())); + return (process.exitCode() == 0) && output.exists() && output.isFile(); +} + +bool UpdateCheckThread::checkSignature(const QString &file, const QString &signature) +{ + if(QFileInfo(file).absolutePath().compare(QFileInfo(signature).absolutePath(), Qt::CaseInsensitive) != 0) + { + qWarning("CheckSignature: File and signature should be in same folder!"); + return false; + } + if(QFileInfo(file).absolutePath().compare(QFileInfo(m_binaryKeys).absolutePath(), Qt::CaseInsensitive) != 0) + { + qWarning("CheckSignature: File and keyring should be in same folder!"); + return false; + } + + QProcess process; + lamexp_init_process(process, QFileInfo(file).absolutePath()); + + QEventLoop loop; + connect(&process, SIGNAL(error(QProcess::ProcessError)), &loop, SLOT(quit())); + connect(&process, SIGNAL(finished(int,QProcess::ExitStatus)), &loop, SLOT(quit())); + connect(&process, SIGNAL(readyRead()), &loop, SLOT(quit())); + + process.start(m_binaryGnuPG, QStringList() << "--homedir" << "." << "--keyring" << QFileInfo(m_binaryKeys).fileName() << QFileInfo(signature).fileName() << QFileInfo(file).fileName()); + + if(!process.waitForStarted()) + { + return false; + } + + while(process.state() == QProcess::Running) + { + loop.exec(); + while(process.canReadLine()) + { + log(QString::fromLatin1(process.readLine()).simplified()); + } + } + + log(QString().sprintf("Exited with code %d", process.exitCode())); + return (process.exitCode() == 0); +} + +bool UpdateCheckThread::parseVersionInfo(const QString &file, UpdateInfo *updateInfo) +{ + QRegExp value("^(\\w+)=(.+)$"); + QRegExp section("^\\[(.+)\\]$"); + + QDate updateInfoDate; + updateInfo->resetInfo(); + + QFile data(file); + if(!data.open(QIODevice::ReadOnly)) + { + qWarning("Cannot open update info file for reading!"); + return false; + } + + bool inHeader = false; + bool inSection = false; + + while(!data.atEnd()) + { + QString line = QString::fromLatin1(data.readLine()).trimmed(); + if(section.indexIn(line) >= 0) + { + log(QString("Sec: [%1]").arg(section.cap(1))); + inSection = (section.cap(1).compare(section_id, Qt::CaseInsensitive) == 0); + inHeader = (section.cap(1).compare(header_id, Qt::CaseInsensitive) == 0); + continue; + } + if(inSection && (value.indexIn(line) >= 0)) + { + log(QString("Val: '%1' ==> '%2").arg(value.cap(1), value.cap(2))); + if(value.cap(1).compare("BuildNo", Qt::CaseInsensitive) == 0) + { + bool ok = false; + unsigned int temp = value.cap(2).toUInt(&ok); + if(ok) updateInfo->m_buildNo = temp; + } + else if(value.cap(1).compare("BuildDate", Qt::CaseInsensitive) == 0) + { + QDate temp = QDate::fromString(value.cap(2).trimmed(), Qt::ISODate); + if(temp.isValid()) updateInfo->m_buildDate = temp; + } + else if(value.cap(1).compare("DownloadSite", Qt::CaseInsensitive) == 0) + { + updateInfo->m_downloadSite = value.cap(2).trimmed(); + } + else if(value.cap(1).compare("DownloadAddress", Qt::CaseInsensitive) == 0) + { + updateInfo->m_downloadAddress = value.cap(2).trimmed(); + } + else if(value.cap(1).compare("DownloadFilename", Qt::CaseInsensitive) == 0) + { + updateInfo->m_downloadFilename = value.cap(2).trimmed(); + } + else if(value.cap(1).compare("DownloadFilecode", Qt::CaseInsensitive) == 0) + { + updateInfo->m_downloadFilecode = value.cap(2).trimmed(); + } + } + if(inHeader && (value.indexIn(line) >= 0)) + { + log(QString("Val: '%1' ==> '%2").arg(value.cap(1), value.cap(2))); + if(value.cap(1).compare("TimestampCreated", Qt::CaseInsensitive) == 0) + { + QDate temp = QDate::fromString(value.cap(2).trimmed(), Qt::ISODate); + if(temp.isValid()) updateInfoDate = temp; + } + } + } + + if(!updateInfoDate.isValid()) + { + updateInfo->resetInfo(); + log("WARNING: Version info timestamp is missing!"); + return false; + } + else if(updateInfoDate.addMonths(VERSION_INFO_EXPIRES_MONTHS) < lamexp_current_date_safe()) + { + updateInfo->resetInfo(); + log(QString::fromLatin1("WARNING: This version info has expired at %1!").arg(updateInfoDate.addMonths(VERSION_INFO_EXPIRES_MONTHS).toString(Qt::ISODate))); + return false; + } + else if(lamexp_current_date_safe() < updateInfoDate) + { + log("Version info is from the future, take care!"); + qWarning("Version info is from the future, take care!"); + } + + bool complete = true; + + if(!(updateInfo->m_buildNo > 0)) complete = false; + if(!(updateInfo->m_buildDate.year() >= 2010)) complete = false; + if(updateInfo->m_downloadSite.isEmpty()) complete = false; + if(updateInfo->m_downloadAddress.isEmpty()) complete = false; + if(updateInfo->m_downloadFilename.isEmpty()) complete = false; + if(updateInfo->m_downloadFilecode.isEmpty()) complete = false; + + if(!complete) + { + log("WARNING: Version info is incomplete!"); + } + + return complete; +} + +//////////////////////////////////////////////////////////// +// SLOTS +//////////////////////////////////////////////////////////// + +/*NONE*/ + +//////////////////////////////////////////////////////////// +// EVENTS +//////////////////////////////////////////////////////////// + +/*NONE*/ diff --git a/src/Thread_CheckUpdate.h b/src/Thread_CheckUpdate.h new file mode 100644 index 00000000..6d9a5ae5 --- /dev/null +++ b/src/Thread_CheckUpdate.h @@ -0,0 +1,108 @@ +/////////////////////////////////////////////////////////////////////////////// +// LameXP - Audio Encoder Front-End +// Copyright (C) 2004-2013 LoRd_MuldeR +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version, but always including the *additional* +// restrictions defined in the "License.txt" file. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// http://www.gnu.org/licenses/gpl-2.0.txt +/////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include +#include + +/////////////////////////////////////////////////////////////////////////////// + +class UpdateInfo +{ +public: + UpdateInfo(void); + void resetInfo(void); + + unsigned int m_buildNo; + QDate m_buildDate; + QString m_downloadSite; + QString m_downloadAddress; + QString m_downloadFilename; + QString m_downloadFilecode; +}; + +/////////////////////////////////////////////////////////////////////////////// + +class UpdateCheckThread : public QThread +{ + Q_OBJECT + +public: + enum + { + UpdateStatus_NotStartedYet = 0, + UpdateStatus_CheckingConnection = 1, + UpdateStatus_FetchingUpdates = 2, + UpdateStatus_CompletedUpdateAvailable = 3, + UpdateStatus_CompletedNoUpdates = 4, + UpdateStatus_CompletedNewVersionOlder = 5, + UpdateStatus_ErrorNoConnection = 6, + UpdateStatus_ErrorConnectionTestFailed = 7, + UpdateStatus_ErrorFetchUpdateInfo = 8 + } + update_status_t; + + UpdateCheckThread(const bool betaUpdates, const bool testMode = false); + ~UpdateCheckThread(void); + + const int getUpdateStatus(void) const { return m_status; } + const bool getSuccess(void) const { return m_success; }; + const int getMaximumProgress(void) const { return m_maxProgress; }; + const int getCurrentProgress(void) const { return m_progress; }; + const UpdateInfo *getUpdateInfo(void) const { return m_updateInfo; } + +protected: + void run(void); + void checkForUpdates(void); + void testKnownHosts(void); + +signals: + void statusChanged(const int status); + void progressChanged(const int progress); + void messageLogged(const QString &text); + +private: + const int m_maxProgress; + UpdateInfo *const m_updateInfo; + + const bool m_betaUpdates; + const bool m_testMode; + + const QString m_binaryWGet; + const QString m_binaryGnuPG; + const QString m_binaryKeys; + + volatile bool m_success; + + int m_status; + int m_progress; + + inline void setStatus(const int status); + inline void setProgress(const int progress); + inline void log(const QString &str1, const QString &str2 = QString(), const QString &str3 = QString(), const QString &str4 = QString()); + + bool getFile(const QString &url, const QString &outFile, unsigned int maxRedir = 5, bool *httpOk = NULL); + bool tryUpdateMirror(UpdateInfo *updateInfo, const QString &url); + bool checkSignature(const QString &file, const QString &signature); + bool parseVersionInfo(const QString &file, UpdateInfo *updateInfo); +};