static void IGotAuthFileList(ENetError result, void* param, const NetCliAuthFileInfo infoArr[], unsigned infoCount) { pfPatcherWorker* patcher = static_cast<pfPatcherWorker*>(param); if (IS_NET_SUCCESS(result)) { // so everything goes directly into the Requests deque because AuthSrv lists // don't have any hashes attached. WHY did eap think this was a good idea?!?! { hsTempMutexLock lock(patcher->fRequestMut); for (unsigned i = 0; i < infoCount; ++i) { PatcherLogYellow("\tEnqueuing Legacy File '%S'", infoArr[i].filename); plFileName fn = plString::FromWchar(infoArr[i].filename); plFileSystem::CreateDir(fn.StripFileName()); // We purposefully do NOT Open this stream! This uses a special auth-file constructor that // utilizes a backing hsRAMStream. This will be fed to plStreamSource later... pfPatcherStream* s = new pfPatcherStream(patcher, fn, infoArr[i].filesize); pfPatcherWorker::Request req = pfPatcherWorker::Request(fn.AsString(), pfPatcherWorker::Request::kAuthFile, s); patcher->fRequests.push_back(req); } } patcher->IssueRequest(); } else { PatcherLogRed("\tSHIT! Some legacy manifest phailed"); patcher->EndPatch(result, "SecurePreloader failed"); } }
//============================================================================ static void DownloadCallback ( ENetError result, void * param, const wchar_t filename[], hsStream * writer ) { if(IS_NET_ERROR(result)) { switch (result) { case kNetErrTimeout: writer->Rewind(); NetCliFileDownloadRequest(filename, writer, DownloadCallback, param); break; default: plString msg = plString::Format("Error getting patcher file: %S", NetErrorToString(result)); plStatusLog::AddLineS("patcher.log", msg.c_str()); if (IS_NET_SUCCESS(s_patchResult)) s_patchResult = result; break; } return; } writer->Close(); delete writer; AtomicAdd(&s_numFiles, -1); if(!s_numFiles) { s_downloadComplete = true; s_updated = true; } }
// Add child node void _AddNodeCallback(ENetError result, void* param) { pyVaultNode::pyVaultNodeOperationCallback* cb = (pyVaultNode::pyVaultNodeOperationCallback*)param; if (IS_NET_SUCCESS(result)) cb->VaultOperationComplete(hsOK); else cb->VaultOperationComplete(hsFail); }
//============================================================================ static void ManifestCallback ( ENetError result, void * param, const wchar_t group[], const NetCliFileManifestEntry manifest[], unsigned entryCount ) { if(IS_NET_ERROR(result)) { switch (result) { case kNetErrTimeout: NetCliFileManifestRequest(ManifestCallback, nil, s_manifest); break; default: plString msg = plString::Format("Error getting patcher manifest: %S", NetErrorToString(result)); plStatusLog::AddLineS("patcher.log", msg.c_str()); if (IS_NET_SUCCESS(s_patchResult)) s_patchResult = result; break; } return; } #ifndef PLASMA_EXTERNAL_RELEASE if (entryCount == 0) { // dataserver does not contain a patcher s_downloadComplete = true; return; } #endif char ansi[MAX_PATH]; // MD5 check current patcher against value in manifest ASSERT(entryCount == 1); wchar_t curPatcherFile[MAX_PATH]; PathGetProgramName(curPatcherFile, arrsize(curPatcherFile)); StrToAnsi(ansi, curPatcherFile, arrsize(ansi)); if (!MD5Check(ansi, manifest[0].md5)) { // MessageBox(GetTopWindow(nil), "MD5 failed", "Msg", MB_OK); SelfPatcherStream::totalBytes += manifest[0].zipSize; AtomicAdd(&s_numFiles, 1); SetText("Downloading new patcher..."); StrToAnsi(ansi, s_newPatcherFile, arrsize(ansi)); SelfPatcherStream * stream = new SelfPatcherStream; if (!stream->Open(ansi, "wb")) ErrorAssert(__LINE__, __FILE__, "Failed to create file: %s, errno: %u", ansi, errno); NetCliFileDownloadRequest(manifest[0].downloadName, stream, DownloadCallback, nil); } else { s_downloadComplete = true; } }
static void IFileManifestDownloadCB(ENetError result, void* param, const wchar_t group[], const NetCliFileManifestEntry manifest[], unsigned entryCount) { pfPatcherWorker* patcher = static_cast<pfPatcherWorker*>(param); if (IS_NET_SUCCESS(result)) IHandleManifestDownload(patcher, group, manifest, entryCount); else { PatcherLogRed("\tDownload Failed: Manifest '%S'", group); patcher->EndPatch(result, plString::FromWchar(group)); } }
static void ManifestDownloaded( ENetError result, void* param, const wchar_t group[], const NetCliFileManifestEntry manifest[], uint32_t entryCount) { plResPatcher* patcher = (plResPatcher*)param; char* name = hsWStringToString(group); if (IS_NET_SUCCESS(result)) PatcherLog(kInfo, " Downloaded manifest %s", name); else { PatcherLog(kError, " Failed to download manifest %s", name); patcher->Finish(false); delete[] name; return; } for (uint32_t i = 0; i < entryCount; ++i) { const NetCliFileManifestEntry mfs = manifest[i]; char* fileName = hsWStringToString(mfs.clientName); // See if the files are the same // 1. Check file size before we do time consuming md5 operations // 2. Do wasteful md5. We should consider implementing a CRC instead. if (plFileUtils::GetFileSize(fileName) == mfs.fileSize) { plMD5Checksum cliMD5(fileName); plMD5Checksum srvMD5; char* eapSucksString = hsWStringToString(mfs.md5); srvMD5.SetFromHexString(eapSucksString); delete[] eapSucksString; if (cliMD5 == srvMD5) { delete[] fileName; continue; } else PatcherLog(kInfo, " Enqueueing %s: MD5 Checksums Differ", fileName); } else PatcherLog(kInfo, " Enqueueing %s: File Sizes Differ", fileName); // If we're still here, then we need to update the file. float size = mfs.zipSize ? (float)mfs.zipSize : (float)mfs.fileSize; patcher->GetProgress()->SetLength(size + patcher->GetProgress()->GetMax()); patcher->RequestFile(mfs.downloadName, mfs.clientName); } patcher->IssueRequest(); delete[] name; }
//============================================================================ static void NetErrorHandler (ENetProtocol protocol, ENetError error) { plString msg = plString::Format("NetErr: %S", NetErrorToString(error)); plStatusLog::AddLineS("patcher.log", msg.c_str()); if (IS_NET_SUCCESS(s_patchResult)) s_patchResult = error; s_downloadComplete = true; switch(error) { case kNetErrServerBusy: MessageBox(0, "Due to the high demand, the server is currently busy. Please try again later, or for alternative download options visit: http://www.mystonline.com/play/", "UruLauncher", MB_OK); s_patchResult = kNetErrServerBusy; s_downloadComplete = true; break; } }
static void IAuthThingDownloadCB(ENetError result, void* param, const plFileName& filename, hsStream* writer) { pfPatcherWorker* patcher = static_cast<pfPatcherWorker*>(param); if (IS_NET_SUCCESS(result)) { PatcherLogGreen("\tDownloaded Legacy File '%s'", filename.AsString().c_str()); patcher->IssueRequest(); // Now, we pass our RAM-backed file to the game code handlers. In the main client, // this will trickle down and add a new friend to plStreamSource. This should never // happen in any other app... writer->Rewind(); patcher->WhitelistFile(filename, true, writer); } else { PatcherLogRed("\tDownloaded Failed: File '%s'", filename.AsString().c_str()); patcher->EndPatch(result, filename.AsString()); } }
void pfPatcherWorker::EndPatch(ENetError result, const plString& msg) { // Guard against multiple calls if (fStarted) { // Send end status if (fOnComplete) fOnComplete(result, msg); // yay log hax if (IS_NET_SUCCESS(result)) PatcherLogWhite("--- Patch Complete ---"); else { PatcherLogRed("\tNetwork Error: %S", NetErrorToString(result)); PatcherLogWhite("--- Patch Killed by Error ---"); } } fStarted = false; fFileSignal.Signal(); }
static void IPreloaderManifestDownloadCB(ENetError result, void* param, const wchar_t group[], const NetCliFileManifestEntry manifest[], unsigned entryCount) { pfPatcherWorker* patcher = static_cast<pfPatcherWorker*>(param); if (IS_NET_SUCCESS(result)) IHandleManifestDownload(patcher, group, manifest, entryCount); else { PatcherLogYellow("\tWARNING: *** Falling back to AuthSrv file lists to get game code ***"); // so, we need to ask the AuthSrv about our game code { hsTempMutexLock lock(patcher->fRequestMut); patcher->fRequests.push_back(pfPatcherWorker::Request(plString::Null, pfPatcherWorker::Request::kPythonList)); patcher->fRequests.push_back(pfPatcherWorker::Request(plString::Null, pfPatcherWorker::Request::kSdlList)); } // continue pumping requests patcher->IssueRequest(); } }
static void IFileThingDownloadCB(ENetError result, void* param, const plFileName& filename, hsStream* writer) { pfPatcherWorker* patcher = static_cast<pfPatcherWorker*>(param); pfPatcherStream* stream = static_cast<pfPatcherStream*>(writer); stream->Close(); if (IS_NET_SUCCESS(result)) { PatcherLogGreen("\tDownloaded File '%s'", stream->GetFileName().AsString().c_str()); patcher->WhitelistFile(stream->GetFileName(), true); if (patcher->fSelfPatch && stream->IsSelfPatch()) patcher->fSelfPatch(stream->GetFileName()); if (patcher->fRedistUpdateDownloaded && stream->IsRedistUpdate()) patcher->fRedistUpdateDownloaded(stream->GetFileName()); patcher->IssueRequest(); } else { PatcherLogRed("\tDownloaded Failed: File '%s'", stream->GetFileName().AsString().c_str()); stream->Unlink(); patcher->EndPatch(result, filename.AsString()); } delete stream; }
//============================================================================ static bool SelfPatcherProc (bool * abort, plLauncherInfo *info) { bool patched = false; s_downloadComplete = false; s_patchResult = kNetSuccess; NetClientInitialize(); NetClientSetErrorHandler(NetErrorHandler); const char** addrs; unsigned count; count = GetGateKeeperSrvHostnames(&addrs); // Start connecting to the server NetCliGateKeeperStartConnect(addrs, count); // request a file server ip address NetCliGateKeeperFileSrvIpAddressRequest(FileSrvIpAddressCallback, nil, true); while(!s_downloadComplete && !*abort) { NetClientUpdate(); AsyncSleep(10); } NetCliFileDisconnect(); NetClientUpdate(); // Shutdown the client/server networking subsystem NetClientDestroy(); if (s_downloadComplete && !*abort && s_updated && IS_NET_SUCCESS(s_patchResult)) { // launch new patcher STARTUPINFOW si; PROCESS_INFORMATION pi; memset(&si, 0, sizeof(si)); memset(&pi, 0, sizeof(pi)); si.cb = sizeof(si); wchar_t cmdline[MAX_PATH]; StrPrintf(cmdline, arrsize(cmdline), L"%s %s", s_newPatcherFile, info->cmdLine); // we have only successfully patched if we actually launch the new version of the patcher patched = CreateProcessW( NULL, cmdline, NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &si, &pi ); SetReturnCode(pi.dwProcessId); CloseHandle( pi.hThread ); CloseHandle( pi.hProcess ); ASSERT(patched); } return patched; }
BOOL CALLBACK UruLoginDialogProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) { static LoginDialogParam* pLoginParam; static bool showAuthFailed = false; switch( uMsg ) { case WM_INITDIALOG: { s_loginDlgRunning = true; _beginthread(StatusCallback, 0, hwndDlg); pLoginParam = (LoginDialogParam*)lParam; SetWindowText(hwndDlg, "Login"); SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)LoadIcon(gHInst, MAKEINTRESOURCE(IDI_ICON_DIRT))); EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE); SetDlgItemText(hwndDlg, IDC_URULOGIN_USERNAME, pLoginParam->username); CheckDlgButton(hwndDlg, IDC_URULOGIN_REMEMBERPASS, pLoginParam->remember ? BST_CHECKED : BST_UNCHECKED); if (pLoginParam->remember) SetDlgItemText(hwndDlg, IDC_URULOGIN_PASSWORD, FAKE_PASS_STRING); SetFocus(GetDlgItem(hwndDlg, pLoginParam->focus)); if (IS_NET_ERROR(pLoginParam->authError)) { showAuthFailed = true; } SendMessage(GetDlgItem(hwndDlg, IDC_PRODUCTSTRING), WM_SETTEXT, 0, (LPARAM)plProduct::ProductString().c_str()); for (int i = 0; i < plLocalization::GetNumLocales(); i++) { SendMessage(GetDlgItem(hwndDlg, IDC_LANGUAGE), CB_ADDSTRING, 0, (LPARAM)plLocalization::GetLanguageName((plLocalization::Language)i)); } SendMessage(GetDlgItem(hwndDlg, IDC_LANGUAGE), CB_SETCURSEL, (WPARAM)plLocalization::GetLanguage(), 0); SetTimer(hwndDlg, AUTH_LOGIN_TIMER, 10, NULL); return FALSE; } case WM_USER_SETSTATUSMSG: SendMessage(GetDlgItem(hwndDlg, IDC_STATUS_TEXT), WM_SETTEXT, 0, lParam); return TRUE; case WM_DESTROY: { s_loginDlgRunning = false; s_statusEvent.Wait(); KillTimer(hwndDlg, AUTH_LOGIN_TIMER); return TRUE; } case WM_NCHITTEST: { SetWindowLongPtr(hwndDlg, DWL_MSGRESULT, (LONG_PTR)HTCAPTION); return TRUE; } case WM_PAINT: { if (showAuthFailed) { SetTimer(hwndDlg, AUTH_FAILED_TIMER, 10, NULL); showAuthFailed = false; } return FALSE; } case WM_COMMAND: { if (HIWORD(wParam) == BN_CLICKED && (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)) { bool ok = (LOWORD(wParam) == IDOK); if (ok) { char password[kMaxPasswordLength]; GetDlgItemText(hwndDlg, IDC_URULOGIN_USERNAME, pLoginParam->username, kMaxAccountNameLength); GetDlgItemText(hwndDlg, IDC_URULOGIN_PASSWORD, password, kMaxPasswordLength); pLoginParam->remember = (IsDlgButtonChecked(hwndDlg, IDC_URULOGIN_REMEMBERPASS) == BST_CHECKED); plLocalization::Language new_language = (plLocalization::Language)SendMessage(GetDlgItem(hwndDlg, IDC_LANGUAGE), CB_GETCURSEL, 0, 0L); plLocalization::SetLanguage(new_language); SaveUserPass (pLoginParam, password); // Welcome to HACKland, population: Branan // The code to write general.ini really doesn't belong here, but it works... for now. // When general.ini gets expanded, this will need to find a proper home somewhere. { plFileName gipath = plFileName::Join(plFileSystem::GetInitPath(), "general.ini"); plString ini_str = plFormat("App.SetLanguage {}\n", plLocalization::GetLanguageName(new_language)); hsStream* gini = plEncryptedStream::OpenEncryptedFileWrite(gipath); gini->WriteString(ini_str); gini->Close(); delete gini; } memset(&pLoginParam->authError, 0, sizeof(pLoginParam->authError)); bool cancelled = AuthenticateNetClientComm(&pLoginParam->authError, hwndDlg); if (IS_NET_SUCCESS(pLoginParam->authError) && !cancelled) EndDialog(hwndDlg, ok); else { if (!cancelled) ::DialogBoxParam(gHInst, MAKEINTRESOURCE( IDD_AUTHFAILED ), hwndDlg, AuthFailedDialogProc, (LPARAM)pLoginParam); else { NetCommDisconnect(); } } } else EndDialog(hwndDlg, ok); return TRUE; } else if (HIWORD(wParam) == EN_CHANGE && LOWORD(wParam) == IDC_URULOGIN_USERNAME) { char username[kMaxAccountNameLength]; GetDlgItemText(hwndDlg, IDC_URULOGIN_USERNAME, username, kMaxAccountNameLength); if (StrLen(username) == 0) EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE); else EnableWindow(GetDlgItem(hwndDlg, IDOK), TRUE); return TRUE; } else if (HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == IDC_URULOGIN_NEWACCTLINK) { plString signupurl = GetServerSignupUrl(); ShellExecuteW(NULL, L"open", signupurl.ToWchar(), NULL, NULL, SW_SHOWNORMAL); return TRUE; } break; } case WM_TIMER: { switch(wParam) { case AUTH_FAILED_TIMER: KillTimer(hwndDlg, AUTH_FAILED_TIMER); ::DialogBoxParam(gHInst, MAKEINTRESOURCE( IDD_AUTHFAILED ), hwndDlg, AuthFailedDialogProc, (LPARAM)pLoginParam); return TRUE; case AUTH_LOGIN_TIMER: NetCommUpdate(); return TRUE; } return FALSE; } } return FALSE; }