/* FTP File YM plugin Copyright (C) 2007-2010 Jan Holub 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 version 2 of the License. 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, see . */ #include "stdafx.h" Event PackerJob::jobDone; mir_cs PackerJob::mutexJobCount; int PackerJob::iRunningJobCount = 0; PackerJob::PackerJob(MCONTACT hContact, int iFtpNum, EMode mode) : GenericJob(hContact, iFtpNum, mode), m_uiFileSize(0), m_uiReaded(0), m_lastUpdateTick(0) { } void PackerJob::getZipFilePath() { wchar_t buff[256], stzFileName[256] = { 0 }; wchar_t *pch; if (m_files.size() == 1) { wcsncpy_s(stzFileName, Utils::getFileNameFromPath(m_files[0]), _TRUNCATE); pch = wcsrchr(stzFileName, '.'); if (pch) *pch = 0; } else { wcsncpy_s(buff, m_files[0], _TRUNCATE); pch = wcsrchr(buff, '\\'); if (pch) { *pch = 0; pch = wcsrchr(buff, '\\'); if (pch) wcsncpy_s(stzFileName, pch + 1, _TRUNCATE); } } if (stzFileName[0] == '\0') wcsncpy_s(stzFileName, L"archive", _TRUNCATE); GetTempPath(_countof(buff), buff); mir_snwprintf(m_tszFilePath, L"%s%s.zip", buff, stzFileName); wcsncpy_s(m_tszFileName, Utils::getFileNameFromPath(m_tszFilePath), _TRUNCATE); if (opt.bSetZipName) Utils::setFileNameDlg(m_tszFileName); } void PackerJob::addToUploadDlg() { getZipFilePath(); UploadDialog::Tab *newTab = new UploadDialog::Tab(this); m_tab = newTab; start(); } void PackerJob::waitingThread(PackerJob *job) { while (!Miranda_IsTerminated()) { mir_cslockfull lock(mutexJobCount); if (iRunningJobCount < MAX_RUNNING_JOBS) { iRunningJobCount++; lock.unlock(); job->pack(); delete job; lock.lock(); iRunningJobCount--; lock.unlock(); jobDone.release(); return; } lock.unlock(); jobDone.wait(); job->m_status = GenericJob::STATUS_WAITING; } } void PackerJob::start() { mir_forkThread(&PackerJob::waitingThread, this); } void PackerJob::pack() { struct _stat fileInfo; for (UINT i = 0; i < m_files.size(); i++) { if (_wstat(m_files[i], &fileInfo) == 0) m_uiFileSize += (UINT64)fileInfo.st_size; } setStatus(STATUS_PACKING); m_startTS = time(0); int res = createZipFile(); if (res == ZIP_OK) { UploadJob *ujob = new UploadJob(this); ujob->m_tab->m_job = ujob; ujob->start(); } else { if (res == ZIP_ERRNO) { Utils::msgBox(TranslateT("Error occurred when zipping the file(s)."), MB_OK | MB_ICONERROR); delete m_tab; } DeleteFile(m_tszFilePath); } } int PackerJob::createZipFile() { int result = ZIP_ERRNO; zipFile zf = zipOpen2_64(m_tszFilePath, 0, nullptr, nullptr); if (zf != nullptr) { result = ZIP_OK; int size_buf = 65536; void *buff = (void *)mir_alloc(size_buf); for (UINT i = 0; i < m_files.size(); i++) { int size_read; zip_fileinfo zi; zi.tmz_date.tm_sec = zi.tmz_date.tm_min = zi.tmz_date.tm_hour = 0; zi.tmz_date.tm_mday = zi.tmz_date.tm_mon = zi.tmz_date.tm_year = 0; zi.dosDate = 0; zi.internal_fa = 0; zi.external_fa = 0; getFileTime(m_files[i], &zi.tmz_date, &zi.dosDate); char *file = mir_u2a(Utils::getFileNameFromPath(m_files[i])); int err = zipOpenNewFileInZip(zf, file, &zi, nullptr, 0, nullptr, 0, nullptr, Z_DEFLATED, opt.iCompressionLevel); FREE(file); if (err == ZIP_OK) { FILE *fin = _wfopen(m_files[i], L"rb"); if (fin) { do { if (isCanceled()) { fclose(fin); result = STATUS_CANCELED; goto Cleanup; } err = ZIP_OK; size_read = (int)fread(buff, 1, size_buf, fin); if (size_read < size_buf && feof(fin) == 0) { fclose(fin); result = ZIP_ERRNO; goto Cleanup; } if (size_read > 0) { err = zipWriteInFileInZip(zf, buff, size_read); m_uiReaded += size_read; } updateStats(); } while ((err == ZIP_OK) && (size_read > 0)); fclose(fin); } else err = ZIP_ERRNO; err = zipCloseFileInZip(zf); if (err < 0) { result = ZIP_ERRNO; goto Cleanup; } } else { result = ZIP_ERRNO; break; } } Cleanup: zipClose(zf, nullptr); FREE(buff); } return result; } uLong PackerJob::getFileTime(wchar_t *file, tm_zip*, uLong *dt) { FILETIME ftLocal; HANDLE hFind; WIN32_FIND_DATA ff32; hFind = FindFirstFile(file, &ff32); if (hFind != INVALID_HANDLE_VALUE) { FileTimeToLocalFileTime(&(ff32.ftLastWriteTime), &ftLocal); FileTimeToDosDateTime(&ftLocal, ((LPWORD)dt) + 1, ((LPWORD)dt) + 0); FindClose(hFind); return 1; } return 0; } void PackerJob::updateStats() { DWORD dwNewTick = GetTickCount(); if (m_uiReaded && (time(0) > m_startTS) && (dwNewTick > m_lastUpdateTick + 100)) { m_lastUpdateTick = dwNewTick; double speed = ((double)m_uiReaded / 1024) / (time(0) - m_startTS); mir_snwprintf(m_tab->m_stzSpeed, TranslateT("%0.1f kB/s"), speed); double perc = m_uiFileSize ? ((double)m_uiReaded / m_uiFileSize) * 100 : 0; mir_snwprintf(m_tab->m_stzComplet, TranslateT("%0.1f%% (%d kB/%d kB)"), perc, (int)m_uiReaded / 1024, (int)m_uiFileSize / 1024); wchar_t buff[256]; long s = (m_uiFileSize - m_uiReaded) / (long)(speed * 1024); int d = (s / 60 / 60 / 24); int h = (s - d * 60 * 60 * 24) / 60 / 60; int m = (s - d * 60 * 60 * 24 - h * 60 * 60) / 60; s = s - (d * 24 * 60 * 60) - (h * 60 * 60) - (m * 60); if (d > 0) mir_snwprintf(buff, L"%dd %02d:%02d:%02d", d, h, m, s); else mir_snwprintf(buff, L"%02d:%02d:%02d", h, m, s); mir_snwprintf(m_tab->m_stzRemain, TranslateT("%s (%d kB/%d kB)"), buff, (m_uiFileSize - m_uiReaded) / 1024, m_uiFileSize / 1024); refreshTab(false); } } void PackerJob::refreshTab(bool bTabChanged) { if (uDlg->m_activeTab == m_tab->index()) { GenericJob::refreshTab(bTabChanged); SetDlgItemText(uDlg->m_hwnd, IDC_UP_SPEED, m_tab->m_stzSpeed); SetDlgItemText(uDlg->m_hwnd, IDC_UP_COMPLETED, m_tab->m_stzComplet); SetDlgItemText(uDlg->m_hwnd, IDC_UP_REMAIN, m_tab->m_stzRemain); SendDlgItemMessage(uDlg->m_hwnd, IDC_PB_UPLOAD, PBM_SETRANGE32, 0, (LPARAM)m_uiFileSize); SendDlgItemMessage(uDlg->m_hwnd, IDC_PB_UPLOAD, PBM_SETPOS, (WPARAM)m_uiReaded, 0); if (bTabChanged) { SetDlgItemText(uDlg->m_hwnd, IDC_STATUSBAR, TranslateT("PACKING...")); EnableWindow(GetDlgItem(uDlg->m_hwnd, IDC_BTN_PAUSE), FALSE); } } } bool PackerJob::isCanceled() { return m_status == STATUS_CANCELED; } void PackerJob::pauseHandler() { /* Not implemented */ } void PackerJob::pause() { /* Not implemented */ } void PackerJob::resume() { /* Not implemented */ } void PackerJob::cancel() { setStatus(STATUS_CANCELED); } void PackerJob::closeTab() { if (Utils::msgBox(TranslateT("Do you really want to cancel this upload?"), MB_YESNO | MB_ICONQUESTION) == IDYES) { cancel(); delete m_tab; } } void PackerJob::closeAllTabs() { cancel(); delete m_tab; } void PackerJob::createToolTip() { mir_snwprintf(uDlg->m_tszToolTipText, TranslateT("Status: %s\r\nFile: %s\r\nServer: %S"), getStatusString(), m_tszFileName, m_ftp->m_szServer); }