/* * This file is a part of TTCalc - a mathematical calculator * and is distributed under the (new) BSD licence. * Author: Tomasz Sowa */ /* * Copyright (c) 2006-2009, Tomasz Sowa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * * Neither the name Tomasz Sowa nor the names of contributors to this * project may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #include "compileconfig.h" #include #include #include "update.h" #include "programresources.h" #include "messages.h" #include "resource.h" #include "winmain.h" namespace Update { bool continue_download; int level; std::string url; std::string remote_file_name; std::string local_file_name; int major; int minor; int revision; } /* */ DownloadIni::DownloadIni() { file = 0; file_name = new char[MAX_PATH]; file_name[0] = 0; } DownloadIni::~DownloadIni() { if( file ) fclose(file); DeleteTmpFile(); delete [] file_name; } void DownloadIni::DeleteTmpFile() { if( file_name[0] != 0 ) DeleteFile(file_name); } const char * DownloadIni::GetFileName() { return file_name; } FILE * DownloadIni::CreateTmpFile() { char buf[MAX_PATH]; file = 0; file_name[0] = 0; if( !GetTempPath(MAX_PATH, buf) ) return 0; if( !GetTempFileName(buf, "ttcalc_", 0, file_name) ) { file_name[0] = 0; return 0; } file = fopen(file_name, "wb"); return file; } void DownloadIni::GetLen(HINTERNET conn) { char buf[100]; DWORD buf_len = sizeof(buf); DWORD index = 0; if( HttpQueryInfo(conn, HTTP_QUERY_CONTENT_LENGTH, buf, &buf_len, &index) ) all_len = atoi(buf); else all_len = 0; } bool DownloadIni::Init() { if( !CreateTmpFile() ) return false; Update::continue_download = true; return true; } bool DownloadIni::Read(char * buffer, size_t size) { if( !file ) return false; fwrite(buffer, size, 1, file); CheckMessages(); return Update::continue_download; } void DownloadIni::Close() { if( file ) fclose(file); file = 0; } /* */ void DownloadProgram::GetLen(HINTERNET conn) { char buf[100]; DWORD buf_len = sizeof(buf); DWORD index = 0; if( HttpQueryInfo(conn, HTTP_QUERY_CONTENT_LENGTH, buf, &buf_len, &index) ) all_len = atoi(buf); else all_len = 0; } bool DownloadProgram::Init() { file.open(Update::local_file_name.c_str(), std::ios_base::out | std::ios_base::binary); Update::continue_download = true; if( !file ) return false; return true; } bool DownloadProgram::Read(char * buffer, size_t size) { file.write(buffer, size); CheckMessages(); return Update::continue_download; } void DownloadProgram::Close() { file.close(); } namespace Update { /* */ bool CheckUpdateFromIni(HWND hwnd) { DownloadIni down_ini; down_ini.AttachProgress(GetDlgItem(hwnd, IDC_PROGRESS)); if( down_ini.DownloadUrl("http://ttcalc.sourceforge.net/ttcalc_update.ini") ) { IniParser iparser; std::string ini_value[3]; iparser.SectionCaseSensitive(false); #ifndef TTCALC_PORTABLE iparser.Associate("normal|url", &url ); iparser.Associate("normal|filename", &remote_file_name ); iparser.Associate("normal|version.major", &ini_value[0] ); iparser.Associate("normal|version.minor", &ini_value[1] ); iparser.Associate("normal|version.revision", &ini_value[2] ); #else iparser.Associate("portable|url", &url ); iparser.Associate("portable|filename", &remote_file_name ); iparser.Associate("portable|version.major", &ini_value[0] ); iparser.Associate("portable|version.minor", &ini_value[1] ); iparser.Associate("portable|version.revision", &ini_value[2] ); #endif IniParser::Error err = iparser.ReadFromFile( down_ini.GetFileName() ); if( err == IniParser::err_ok ) { major = atoi(ini_value[0].c_str()); minor = atoi(ini_value[1].c_str()); revision = atoi(ini_value[2].c_str()); if( major > TTCALC_MAJOR_VER ) return true; else if( major == TTCALC_MAJOR_VER && minor > TTCALC_MINOR_VER ) return true; else if( major == TTCALC_MAJOR_VER && minor == TTCALC_MINOR_VER && revision > TTCALC_REVISION_VER ) return true; } } return false; } void CheckUpdate(HWND hwnd) { char buffer[200]; level = -1; // nothing to do when Next is pressed EnableWindow(GetDlgItem(hwnd, IDC_BUTTON_NEXT), false); EnableWindow(GetDlgItem(hwnd, IDC_UPDATE_INFO1), false); ShowWindow(GetDlgItem(hwnd, IDC_PROGRESS), SW_SHOW); CheckMessages(); if( CheckUpdateFromIni(hwnd) ) { level = 1; sprintf(buffer, "Version %d.%d.%d is available, press Next to download...", major, minor, revision); SetDlgItemText(hwnd, IDC_UPDATE_INFO1, buffer); } else { level = 100; SetDlgItemText(hwnd, IDC_UPDATE_INFO1, "There is not a new version available."); SetDlgItemText(hwnd, IDC_BUTTON_NEXT, "Finish"); ShowWindow(GetDlgItem(hwnd, IDC_PROGRESS), SW_HIDE); EnableWindow(GetDlgItem(hwnd, IDC_BUTTON_CANCEL), false); } EnableWindow(GetDlgItem(hwnd, IDC_BUTTON_NEXT), true); EnableWindow(GetDlgItem(hwnd, IDC_UPDATE_INFO1), true); ShowWindow(GetDlgItem(hwnd, IDC_PROGRESS), SW_HIDE); SetFocus(GetDlgItem(hwnd, IDC_BUTTON_NEXT)); } bool SaveDialog(HWND hwnd) { OPENFILENAME o; char buf[MAX_PATH], desktop[MAX_PATH]; if( !remote_file_name.empty() ) sprintf(buf, remote_file_name.c_str()); else { #ifndef TTCALC_PORTABLE sprintf(buf, "ttcalc-%d.%d.%d-setup.exe", major, minor, revision); #else sprintf(buf, "ttcalc-portable-%d.%d.%d-bin.tar.gz", major, minor, revision); #endif } if( !SHGetSpecialFolderPath(hwnd, desktop, CSIDL_DESKTOPDIRECTORY, 0) ) desktop[0] = 0; o.lStructSize = sizeof(o); o.hwndOwner = hwnd; o.hInstance = GetPrgRes()->GetInstance(); o.lpstrFilter = "*.*\0*.*\0"; o.lpstrCustomFilter = 0; o.nMaxCustFilter = 0; o.nFilterIndex = 1; o.lpstrFile = buf; o.nMaxFile = MAX_PATH; o.lpstrFileTitle = 0; o.nMaxFileTitle = 0; o.lpstrInitialDir = (desktop[0]) ? desktop : 0; o.lpstrTitle = 0; o.Flags = OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST; o.nFileOffset = 0; o.nFileExtension = 0; o.lpstrDefExt = 0; o.lCustData = 0; o.lpfnHook = 0; o.lpTemplateName = 0; if( GetSaveFileName(&o) ) { local_file_name = buf; return true; } return false; } bool DownloadUpdate(HWND hwnd) { DownloadProgram down; level = -1; // nothing to do when Next is pressed EnableWindow(GetDlgItem(hwnd, IDC_BUTTON_NEXT), false); if( SaveDialog(hwnd) ) { SetDlgItemText(hwnd, IDC_UPDATE_INFO1, "Downloading from:"); SetDlgItemText(hwnd, IDC_UPDATE_INFO2, url.c_str()); ShowWindow(GetDlgItem(hwnd, IDC_PROGRESS), SW_SHOW); down.AttachProgress(GetDlgItem(hwnd, IDC_PROGRESS)); CheckMessages(); if( down.DownloadUrl( url.c_str()) ) { #ifndef TTCALC_PORTABLE level = 2; SetDlgItemText(hwnd, IDC_UPDATE_INFO1, "A new setup program has been downloaded."); SetDlgItemText(hwnd, IDC_UPDATE_INFO2, "Press Finish to close TTCalc and run the installer."); #else level = 100; SetDlgItemText(hwnd, IDC_UPDATE_INFO1, "A new version of TTCalc has been downloaded"); SetDlgItemText(hwnd, IDC_UPDATE_INFO2, ""); EnableWindow(GetDlgItem(hwnd, IDC_BUTTON_CANCEL), false); #endif } else { level = 100; DeleteFile(local_file_name.c_str()); SetDlgItemText(hwnd, IDC_UPDATE_INFO1, "There was a problem with downloading, please try again later"); SetDlgItemText(hwnd, IDC_UPDATE_INFO2, ""); } ShowWindow(GetDlgItem(hwnd, IDC_PROGRESS), SW_HIDE); SetDlgItemText(hwnd, IDC_BUTTON_NEXT, "Finish"); } else { level = 100; EndDialog(hwnd, 0); } EnableWindow(GetDlgItem(hwnd, IDC_BUTTON_NEXT), true); SetFocus(GetDlgItem(hwnd, IDC_BUTTON_NEXT)); return false; } BOOL UpdateInit(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { SetDlgItemText(hwnd, IDC_UPDATE_INFO1, "Press Next to check for the update..."); SetDlgItemText(hwnd, IDC_UPDATE_INFO2, ""); SetDlgItemText(hwnd, IDC_BUTTON_NEXT, "Next"); SetDlgItemText(hwnd, IDC_BUTTON_CANCEL, "Cancel"); ShowWindow(GetDlgItem(hwnd, IDC_PROGRESS), SW_HIDE); return true; } BOOL UpdateCommand(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { if( LOWORD(wParam)==IDCANCEL || LOWORD(wParam)==IDC_BUTTON_CANCEL ) { continue_download = false; EndDialog(hwnd, 0); return 0; } if( LOWORD(wParam) == IDC_BUTTON_NEXT ) { switch(level) { case 0: CheckUpdate(hwnd); break; case 1: DownloadUpdate(hwnd); break; case 2: ShellExecute(0, "open", local_file_name.c_str(), "", "", SW_SHOWNORMAL); EndDialog(hwnd, 0); PostQuitMessage(0); break; case 100: EndDialog(hwnd, 0); break; } return 0; } return 1; } void CreateUpdateMessagesTable(Messages & messages) { messages.Associate(WM_INITDIALOG, UpdateInit); messages.Associate(WM_COMMAND, UpdateCommand); } BOOL CALLBACK UpdateProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { static Messages messages; if( messages.Empty() ) // initiation CreateUpdateMessagesTable(messages); return messages.Call(msg, hwnd, msg, wParam, lParam); } } // namespace void ShowUpdateDialog(HWND hwnd) { using namespace Update; level = 0; local_file_name.clear(); remote_file_name.clear(); url.clear(); DialogBox(GetPrgRes()->GetInstance(), MAKEINTRESOURCE(IDD_UPDATE_DIALOG), hwnd, UpdateProc); }