static BOOL move_program() { if (MoveFileEx(L"Calibre Portable\\calibre-portable.exe", L"..\\calibre-portable.exe", MOVEFILE_REPLACE_EXISTING) == 0) { show_last_error(L"Failed to move calibre-portable.exe, make sure calibre is not running"); return false; } if (directory_exists(L"..\\Calibre")) { if (!rmtree(L"..\\Calibre")) { show_error(L"Failed to delete the Calibre program folder. Make sure calibre is not running."); return false; } } if (MoveFileEx(L"Calibre Portable\\Calibre", L"..\\Calibre", 0) == 0) { Sleep(4000); // Sleep and try again if (MoveFileEx(L"Calibre Portable\\Calibre", L"..\\Calibre", 0) == 0) { show_last_error(L"Failed to move calibre program folder. This is usually caused by an antivirus program or a file sync program like DropBox. Turn them off temporarily and try again. Underlying error: "); return false; } } if (!directory_exists(L"..\\Calibre Library")) { MoveFileEx(L"Calibre Portable\\Calibre Library", L"..\\Calibre Library", 0); } if (!directory_exists(L"..\\Calibre Settings")) { MoveFileEx(L"Calibre Portable\\Calibre Settings", L"..\\Calibre Settings", 0); } return true; }
static HANDLE temp_file(LPWSTR name) { UINT res; HANDLE h; res = GetTempFileNameW(L".", L"portable_data", 0, name); if (res == 0) { show_last_error(L"Failed to create temporary file to decompress portable data"); return INVALID_HANDLE_VALUE; } h = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (h == INVALID_HANDLE_VALUE) { show_last_error(L"Failed to open temp file to decompress portable data"); } return h; }
static BOOL load_data(LPVOID *data, DWORD *sz) { HRSRC rsrc; HGLOBAL h; rsrc = FindResourceW(NULL, L"extra", L"extra"); if (rsrc == NULL) { show_last_error(L"Failed to find portable data in exe"); return false; } h = LoadResource(NULL, rsrc); if (h == NULL) { show_last_error(L"Failed to load portable data from exe"); return false; } *data = LockResource(h); if (*data == NULL) { show_last_error(L"Failed to lock portable data in exe"); return false; } *sz = SizeofResource(NULL, rsrc); if (sz == 0) { show_last_error(L"Failed to get size of portable data in exe"); return false; } return true; }
void launch_calibre(LPCTSTR exe, LPCTSTR config_dir, LPCTSTR library_dir) { DWORD dwFlags=0; STARTUPINFO si; PROCESS_INFORMATION pi; BOOL fSuccess; TCHAR cmdline[BUFSIZE]; if (! SetEnvironmentVariable(_T("CALIBRE_CONFIG_DIRECTORY"), config_dir)) { show_last_error(_T("Failed to set environment variables")); ExitProcess(1); } if (! SetEnvironmentVariable(_T("CALIBRE_PORTABLE_BUILD"), exe)) { show_last_error(_T("Failed to set environment variables")); ExitProcess(1); } dwFlags = CREATE_UNICODE_ENVIRONMENT | CREATE_NEW_PROCESS_GROUP; _sntprintf_s(cmdline, BUFSIZE, _TRUNCATE, _T(" \"--with-library=%s\""), library_dir); ZeroMemory( &si, sizeof(si) ); si.cb = sizeof(si); ZeroMemory( &pi, sizeof(pi) ); fSuccess = CreateProcess(exe, cmdline, NULL, // Process handle not inheritable NULL, // Thread handle not inheritable FALSE, // Set handle inheritance to FALSE dwFlags, // Creation flags http://msdn.microsoft.com/en-us/library/ms684863(v=vs.85).aspx NULL, // Use parent's environment block NULL, // Use parent's starting directory &si, // Pointer to STARTUPINFO structure &pi // Pointer to PROCESS_INFORMATION structure ); if (fSuccess == 0) { show_last_error(_T("Failed to launch the calibre program")); } // Close process and thread handles. CloseHandle( pi.hProcess ); CloseHandle( pi.hThread ); }
static ENTRYPROC load_launcher_dll() { wchar_t buf[MAX_PATH]; // Cannot use a zero initializer for the array as it generates an implicit call to memset() wchar_t *dll_point = NULL; int i = 0; DWORD sz = 0; HMODULE dll = 0; ENTRYPROC entrypoint = NULL; if ((sz = GetModuleFileNameW(NULL, buf, MAX_PATH)) >= MAX_PATH - 30) { show_error(L"Installation directory path too long", L"", 1); return NULL; } while (sz > 0) { if (buf[sz] == L'\\' || buf[sz] == L'/') { dll_point = buf + sz + 1; break; } sz--; } if (dll_point == NULL) { show_error(L"Executable path has no path separators", L"", 1); return NULL; } wsprintf(dll_point, L"%s\0\0", L"app\\DLLs"); if (SetDllDirectoryW(buf) == 0) { show_last_error(L"Failed to set DLL directory"); return NULL; } // Have to load ucrtbase manually first, otherwise loading fails on systems where the // Universal CRT is not installed. if (!LoadLibraryW(L"ucrtbase.dll")) { show_last_error(L"Unable to find ucrtbase.dll. You should install all Windows updates on your computer to get this file."); return NULL; } if (!(dll = LoadLibraryW(L"calibre-launcher.dll"))) { show_last_error(L"Failed to load: calibre-launcher.dll"); return NULL; } if (!(entrypoint = (ENTRYPROC) GetProcAddress(dll, "execute_python_entrypoint"))) { show_last_error(L"Failed to get the calibre-launcher dll entry point"); return NULL; } return entrypoint; }
static LPWSTR make_unpack_dir() { WCHAR buf[4*MAX_PATH] = {0}; LPWSTR ans = NULL; if (directory_exists(L"_unpack_calibre_portable")) rmtree(L"_unpack_calibre_portable"); if (!CreateDirectory(L"_unpack_calibre_portable", NULL) && GetLastError() != ERROR_ALREADY_EXISTS) { show_last_error(L"Failed to create temporary folder to unpack into"); return ans; } if (!GetFullPathName(L"_unpack_calibre_portable", 4*MAX_PATH, buf, NULL)) { show_last_error(L"Failed to resolve path"); return NULL; } ans = _wcsdup(buf); if (ans == NULL) show_error(L"Out of memory"); return ans; }
void alias_screen(int modified) { /* Stolen from showscreen() */ ClearScreen(); alias_title(modified); last_header_page = -1; /* force a redraw regardless */ show_headers(); if (mini_menu) show_alias_menu(); show_last_error(); }
static BOOL find_portable_dir(LPCWSTR base, LPWSTR *result, BOOL *existing) { WCHAR buf[4*MAX_PATH] = {0}; _snwprintf_s(buf, 4*MAX_PATH, _TRUNCATE, L"%s\\calibre-portable.exe", base); *existing = true; if (file_exists(buf)) { *result = _wcsdup(base); if (*result == NULL) { show_error(L"Out of memory"); return false; } return true; } WIN32_FIND_DATA fdFile; HANDLE hFind = NULL; _snwprintf_s(buf, 4*MAX_PATH, _TRUNCATE, L"%s\\*", base); if((hFind = FindFirstFileEx(buf, FindExInfoStandard, &fdFile, FindExSearchLimitToDirectories, NULL, 0)) != INVALID_HANDLE_VALUE) { do { if(is_dots(fdFile.cFileName)) continue; if(fdFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { _snwprintf_s(buf, 4*MAX_PATH, _TRUNCATE, L"%s\\%s\\calibre-portable.exe", base, fdFile.cFileName); if (file_exists(buf)) { *result = _wcsdup(buf); if (*result == NULL) { show_error(L"Out of memory"); return false; } PathRemoveFileSpec(*result); FindClose(hFind); return true; } } } while(FindNextFile(hFind, &fdFile)); FindClose(hFind); } *existing = false; _snwprintf_s(buf, 4*MAX_PATH, _TRUNCATE, L"%s\\Calibre Portable", base); if (!CreateDirectory(buf, NULL) && GetLastError() != ERROR_ALREADY_EXISTS) { show_last_error(L"Failed to create Calibre Portable folder"); return false; } *result = _wcsdup(buf); if (*result == NULL) { show_error(L"Out of memory"); return false; } return true; }
static size_t output_callback(void *ctx, const void *buf, size_t size) { struct DataStream * ds = (struct DataStream *) ctx; DWORD written = 0; if (size > 0) { if (!WriteFile(ds->out, buf, size, &written, NULL)) { show_last_error(L"Failed to write uncompressed data to temp file"); output_error_shown = 1; return 0; } written = SetFilePointer(ds->out, 0, NULL, FILE_CURRENT); ds->pd->SetProgress(written, UNCOMPRESSED_SIZE); } return size; }
static void launch_calibre() { STARTUPINFO si; PROCESS_INFORMATION pi; ZeroMemory( &si, sizeof(si) ); si.cb = sizeof(si); ZeroMemory( &pi, sizeof(pi) ); if (CreateProcess(_wcsdup(L"calibre-portable.exe"), NULL, NULL, NULL, FALSE, CREATE_UNICODE_ENVIRONMENT | CREATE_NEW_PROCESS_GROUP, NULL, NULL, &si, &pi) == 0) { show_last_error(L"Failed to launch calibre portable"); } // Close process and thread handles. CloseHandle( pi.hProcess ); CloseHandle( pi.hThread ); }
static BOOL extract(LPVOID cdata, DWORD csz) { HANDLE h; WCHAR tempnam[MAX_PATH+1] = {0}; BOOL ret = true; HZIP zipf; ZIPENTRYW ze; ZRESULT res; int nitems; HRESULT hr; IProgressDialog *pd = NULL; hr = CoCreateInstance(CLSID_ProgressDialog, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pd)); if (FAILED(hr)) { show_error(L"Failed to create progress dialog"); return false; } pd->SetTitle(L"Extracting Calibre Portable"); pd->SetLine(1, L"Decompressing data...", true, NULL); h = temp_file(tempnam); if (h == INVALID_HANDLE_VALUE) return false; pd->StartProgressDialog(NULL, NULL, PROGDLG_NORMAL | PROGDLG_AUTOTIME | PROGDLG_NOCANCEL, NULL); if (!decompress(cdata, csz, h, pd)) { ret = false; goto end; } SetFilePointer(h, 0, NULL, FILE_BEGIN); zipf = OpenZip(h, 0, ZIP_HANDLE); if (zipf == 0) { show_last_error(L"Failed to open zipped portable data"); ret = false; goto end; } res = GetZipItem(zipf, -1, &ze); if (res != ZR_OK) { show_zip_error(L"Failed to get count of items in portable data", L"", res); ret = false; goto end;} nitems = ze.index; pd->SetLine(1, L"Copying files...", true, NULL); if (!unzip(zipf, nitems, pd)) { ret = false; goto end; } end: pd->StopProgressDialog(); pd->Release(); CloseHandle(h); DeleteFile(tempnam); return ret; }
void alias(void) { /* * Work with alias commands... */ char name[NLEN], *address, buffer[SLEN]; char *commap; static int newaliases = 0; int ch, i; int nutitle = 0; int too_long; /* * We're going to try to match the way elm does it at * he main menu. I probably won't be able to use any * main menu routines, but I will "borrow" from them. RLH */ alias_main_state(); /* Save globals for return to main menu */ open_alias_files(FALSE); /* First, read the alias files. RLH */ alias_screen(newaliases); while (1) { redraw = 0; nucurr = 0; nufoot = 0; prompt(nls_Prompt); CleartoEOLN(); ch = GetKey(0); MoveCursor(LINES-3,strlen(nls_Prompt)); CleartoEOS(); dprint(3, (debugfile, "\n-- Alias command: %c\n\n", ch)); switch (ch) { case '?': redraw += alias_help(); break; #ifdef ALLOW_SUBSHELL case '!' : WriteChar('!'); alias_main_state(); /** reload index screen vars **/ redraw += subshell(); alias_main_state(); /** reload alias screen vars **/ break; #endif /* ALLOW_SUBSHELL */ case '$': PutLine(-1, -1, catgets(elm_msg_cat, AliasesSet, AliasesResync, "Resynchronize aliases...")); /* * Process deletions and then see if we need to * re-run the "newalias" routine. */ if (resync_aliases(newaliases)) { install_aliases(); newaliases = 0; redraw++; } break; case 'a': PutLine(-1, -1, catgets(elm_msg_cat, AliasesSet, AliasesAddCurrent, "Add address from current message...")); clear_error(); if (add_current_alias()) { newaliases++; nutitle++; } break; case 'c': if (curr_alias > 0) { PutLine(-1, -1, catgets(elm_msg_cat, AliasesSet, AliasesReplaceCurrent, "Replace current alias in database...")); clear_error(); if (add_alias(TRUE, curr_alias-1)) { newaliases++; nutitle++; } } else { show_error(catgets(elm_msg_cat, AliasesSet, AliasesNoneToReplace, "Warning: no aliases to replace!")); } break; case 'e': PutLine(LINES-3, strlen(nls_Prompt), catgets(elm_msg_cat, AliasesSet, AliasesEdit, "Edit %s..."), ALIAS_TEXT); /* * Process aliases.text for deletions, etc. You * have to do this *before* checking current because * all aliases could be marked for deletion. */ (void) resync_aliases(newaliases); if (edit_aliases_text()) { newaliases = 0; } redraw++; break; case 'm': if (curr_alias > 0) { PutLine(-1, -1, catgets(elm_msg_cat, AliasesSet, AliasesMail, "Mail...")); redraw += a_sendmsg(); } else { show_error(catgets(elm_msg_cat, AliasesSet, AliasesNoneToMail, "Warning: no aliases to send mail to!")); } break; case 'n': PutLine(-1, -1, catgets(elm_msg_cat, AliasesSet, AliasesAddNew, "Add a new alias to database...")); clear_error(); if (add_alias(FALSE, -1)) { newaliases++; nutitle++; } break; case 'q': case 'Q': case 'i': case 'I': case 'r': case 'R': PutLine(-1, -1, catgets(elm_msg_cat, AliasesSet, AliasesAddReturn, "Return to main menu...")); /* * leaving the alias system. Must check for * pending deletes, etc. prompt is set to FALSE * on uppercase letters so that deletions are * NOT queried. */ if (delete_aliases(newaliases, islower(ch))) { install_aliases(); newaliases = 0; } clear_error(); alias_main_state(); /* Done with aliases. */ return; case RETURN: case LINE_FEED: case ' ': case 'v': if (newaliases) { /* Need this ?? */ show_error(catgets(elm_msg_cat, AliasesSet, AliasesNotInstalled, "Warning: new aliases not installed yet!")); } if (curr_alias > 0) { if (aliases[curr_alias-1]->type & GROUP) { PutLine(LINES-1, 0, catgets(elm_msg_cat, AliasesSet, AliasesGroupAlias, "Group alias: %-60.60s"), aliases[curr_alias-1]->address); } else { PutLine(LINES-1, 0, catgets(elm_msg_cat, AliasesSet, AliasesAliasedAddress, "Aliased address: %-60.60s"), aliases[curr_alias-1]->address); } } else { show_error(catgets(elm_msg_cat, AliasesSet, AliasesNoneToView, "Warning: no aliases to view!")); } break; case 'x': case 'X': PutLine(-1, -1, catgets(elm_msg_cat, AliasesSet, AliasesAddReturn, "Return to main menu...")); exit_alias(); clear_error(); alias_main_state(); /* Done with aliases. */ return; case 'f': case 'F': if (curr_alias > 0) { clear_error(); strcpy(name, aliases[curr_alias-1]->alias); if (ch == 'F') { strcpy(buffer, catgets(elm_msg_cat, AliasesSet, AliasesFullyExpanded, "Fully expand alias: ")); PutLine(LINES-2, 0, buffer); if (enter_string(name, sizeof(name), -1, -1, ESTR_REPLACE) < 0 || name[0] == '\0') break; } too_long = FALSE; address = get_alias_address(name, TRUE, &too_long); if (address != NULL) { while (TRUE) { ClearScreen(); PutLine(2,0, catgets(elm_msg_cat, AliasesSet, AliasesAliasedFull, "Aliased address for:\t%s\n\r"), name); i = 4; while (i < LINES-2) { if ((commap = strchr(address, (int)',')) == NULL) { PutLine(i, 4, address); break; } *commap = '\0'; PutLine(i++, 4, address); address = commap+2; } PutLine(LINES-1, 0, catgets(elm_msg_cat, AliasesSet, AliasesPressReturn, "Press <return> to continue.")); (void) ReadCh(); if (commap == NULL) { redraw++; break; } } } else if (! too_long) { show_error(catgets(elm_msg_cat, AliasesSet, AliasesNotFound, "Not found.")); } } else { show_error(catgets(elm_msg_cat, AliasesSet, AliasesNoneToView, "Warning: no aliases to view!")); } break; case KEY_REDRAW: redraw = 1; break; /* * None of the menu specific commands were chosen, therefore * it must be a "motion" command (or an error). */ default : motion(ch); } if (redraw) { /* Redraw screen if necessary */ alias_screen(newaliases); nutitle = 0; } if (nutitle) { /* Redraw title if necessary */ alias_title(newaliases); nutitle = 0; } check_range(); if (nucurr == NEW_PAGE) show_headers(); else if (nucurr == SAME_PAGE) show_current(); else if (nufoot) { if (mini_menu) { MoveCursor(LINES-7, 0); CleartoEOS(); show_alias_menu(); } else { MoveCursor(LINES-4, 0); CleartoEOS(); } show_last_error(); /* for those operations that have to * clear the footer except for a message. */ } } /* BIG while loop... */ }
static void do_showerror(const char *s) { strcpy(err_buffer, s); show_last_error(); }
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow) { LPVOID cdata = NULL; DWORD csz = 0; int ret = 0, argc; HRESULT hr; LPWSTR tgt = NULL, dest = NULL, *argv, unpack_dir = NULL; BOOL existing = false, launch = false, automated = false; WCHAR buf[4*MAX_PATH] = {0}, mb_msg[4*MAX_PATH] = {0}, fdest[4*MAX_PATH] = {0}; if (!load_data(&cdata, &csz)) return 0; hr = CoInitialize(NULL); if (FAILED(hr)) { show_error(L"Failed to initialize COM"); return 0; } // Get the target directory for installation argv = CommandLineToArgvW(GetCommandLine(), &argc); if (argv == NULL) { show_last_error(L"Failed to get command line"); return 0; } if (argc > 1) { tgt = argv[1]; automated = true; } else { tgt = get_directory_from_user(); if (tgt == NULL) goto end; } if (!directory_exists(tgt)) { show_detailed_error(L"The specified directory does not exist: ", tgt, 1); goto end; } // Ensure the path to Calibre Portable is not too long do { if (!find_portable_dir(tgt, &dest, &existing)) goto end; if (GetFullPathName(dest, MAX_PATH*4, fdest, NULL) == 0) { show_last_error(L"Failed to resolve target folder"); goto end; } free(dest); dest = NULL; if (wcslen(fdest) > 58) { _snwprintf_s(buf, 4*MAX_PATH, _TRUNCATE, L"Path to Calibre Portable (%s) too long. Must be less than 59 characters.", fdest); if (!existing) RemoveDirectory(fdest); show_error(buf); tgt = get_directory_from_user(); if (tgt == NULL) goto end; } } while (wcslen(fdest) > 58); // Confirm the user wants to upgrade if (existing && !automated) { _snwprintf_s(mb_msg, 4*MAX_PATH, _TRUNCATE, L"An existing install of Calibre Portable was found at %s. Do you want to upgrade it?", fdest); if (MessageBox(NULL, mb_msg, L"Upgrade Calibre Portable?", MB_ICONEXCLAMATION | MB_YESNO | MB_TOPMOST) != IDYES) goto end; } if (existing) { if (!ensure_not_running(fdest)) goto end; } // Make a temp dir to unpack into if (!SetCurrentDirectoryW(fdest)) { show_detailed_error(L"Failed to change to unzip directory: ", fdest, 0); goto end; } if ( (unpack_dir = make_unpack_dir()) == NULL ) goto end; if (!SetCurrentDirectoryW(unpack_dir)) { show_detailed_error(L"Failed to change to unpack directory: ", fdest, 0); goto end; } // Extract files if (!extract(cdata, csz)) goto end; // Move files from temp dir to the install dir if (!move_program()) goto end; _snwprintf_s(mb_msg, 4*MAX_PATH, _TRUNCATE, L"Calibre Portable successfully installed to %s. Launch calibre?", fdest); launch = MessageBox(NULL, mb_msg, L"Success", MB_ICONINFORMATION | MB_YESNO | MB_TOPMOST) == IDYES; end: if (unpack_dir != NULL) { SetCurrentDirectoryW(L".."); rmtree(unpack_dir); free(unpack_dir); } CoUninitialize(); if (launch) launch_calibre(); return 0; }