00001 #include "SexyApp.h"
00002
00003 #include "..\Crypt\RegKey.h"
00004 #include "SEHCatcher.h"
00005 #include "InternetManager.h"
00006 #include <time.h>
00007 #include <fstream>
00008 #include <direct.h>
00009 #include "BetaSupport.h"
00010
00011 #ifdef ZYLOM
00012 #include "zylomso.h"
00013 using namespace zylom::zylomso;
00014 #endif
00015
00016 using namespace Sexy;
00017
00018 SexyApp* Sexy::gSexyApp = NULL;
00019
00020
00021 const char DYNAMIC_DATA_BLOCK[400] =
00022 "DYN00000PACPOPPOPCAPPACPOPPOPCAPBUILDINFOMARKERPACPOPPOPCAPPACPOPPOPCAPXXXXXXXXX"
00023 "00000000PACPOPPOPCAPPACPOPPOPCAPBUILDINFOMARKERPACPOPPOPCAPPACPOPPOPCAPXXXXXXXXX";
00024
00025 const char* BUILD_INFO_MARKER = DYNAMIC_DATA_BLOCK + 80;
00026 const char* SIGNATURE_CODE_MARKER = DYNAMIC_DATA_BLOCK + 80*2;
00027 const char* BETA_ID_MARKER = DYNAMIC_DATA_BLOCK + 80*3;
00028
00029 SexyApp::SexyApp()
00030 {
00031 gSexyApp = this;
00032
00033 mTimesPlayed = 0;
00034 mTimesExecuted = 0;
00035 mTimedOut = false;
00036
00037 mIsRegistered = false;
00038 mBuildUnlocked = false;
00039 mDownloadId = 0;
00040 mRegSource = "ingame";
00041 mSkipAd = false;
00042 mDontUpdate = false;
00043 mLastVerCheckQueryTime = 0;
00044
00045 mDemoPrefix = "popcap";
00046 mDemoFileName = mDemoPrefix + ".dmo";
00047 mCompanyName = "PopCap";
00048
00049 mInternetManager = new InternetManager();
00050 mBetaSupport = NULL;
00051 mBetaValidate = false;
00052
00053 SetString("UPDATE_CHECK_BODY", "Contacting PopCap.com to determine if there are any updates available for this product ...");
00054
00055 char aStr[9] = {0};
00056 strncpy(aStr, BUILD_INFO_MARKER, 8);
00057 mBuildNum = atoi(aStr);
00058
00059 if (mBuildNum != 0)
00060 mBuildDate = BUILD_INFO_MARKER + 8;
00061 }
00062
00063 SexyApp::~SexyApp()
00064 {
00065 delete mBetaSupport;
00066 delete mInternetManager;
00067 }
00068
00069 bool SexyApp::Validate(const std::string& theUserName, const std::string& theRegCode)
00070 {
00071 BigInt n("42BF94023BBA6D040C8B81D9");
00072 BigInt e("11");
00073
00074 ulong i;
00075 std::string aDataString;
00076 bool space = false;
00077 for (i = 0; i < theUserName.size(); i++)
00078 {
00079 if (theUserName[i] == ' ')
00080 {
00081 if (aDataString.length() > 0)
00082 space = true;
00083 }
00084 else
00085 {
00086 if (space)
00087 {
00088 aDataString += " ";
00089 space = false;
00090 }
00091
00092 char aChar = theUserName[i];
00093 for (int j = 0; gRegKeyTranslationTable[j][0] != 0; j++)
00094 if (gRegKeyTranslationTable[j][0] == aChar)
00095 aChar = gRegKeyTranslationTable[j][1];
00096
00097 aDataString += toupper(aChar);
00098 }
00099 }
00100
00101 std::string aProduct;
00102 aProduct = mProdName;
00103 for (i = 0; i < aProduct.length(); i++)
00104 aProduct[i] = toupper(aProduct[i]);
00105
00106 aDataString += "\n";
00107 aDataString += aProduct;
00108 BigInt aHash = HashString(aDataString, 94);
00109
00110 BigInt aSignature = KeyToInt(theRegCode);
00111 BigInt aHashTest = aSignature.ModPow(e, n);
00112
00113 return aHashTest == aHash;
00114 }
00115
00116 void SexyApp::ReadFromRegistry()
00117 {
00118 SexyAppBase::ReadFromRegistry();
00119
00120 if (!mPlayingDemoBuffer)
00121 {
00122 mTimesPlayed = 0;
00123 mTimesExecuted = 0;
00124
00125 char aFileName[256];
00126 GetWindowsDirectory(aFileName, 256);
00127 if (aFileName[strlen(aFileName)-1] != '\\')
00128 strcat(aFileName, "\\");
00129 strcat(aFileName, "popcinfo.dat");
00130
00131 FILE* fp = fopen(aFileName, "rb");
00132 if (fp != NULL)
00133 {
00134 for (;;)
00135 {
00136 ushort aLen;
00137 if (fread(&aLen, 1, sizeof(short), fp) == 0)
00138 break;
00139
00140 if (aLen < 256)
00141 {
00142 char aProdName[256];
00143 aProdName[aLen] = '\0';
00144 fread(aProdName, aLen, sizeof(char), fp);
00145
00146 if (strcmp(aProdName, mProdName.c_str()) == 0)
00147 {
00148 short aShort;
00149 fread(&aShort, 1, sizeof(short), fp);
00150 mTimesPlayed = aShort;
00151
00152 fread(&aShort, 1, sizeof(short), fp);
00153 mTimesExecuted = aShort;
00154
00155 break;
00156 }
00157 }
00158
00159 fseek(fp, sizeof(int), SEEK_CUR);
00160 }
00161 fclose(fp);
00162 }
00163 }
00164
00165 RegistryReadString("ReferId", &mReferId);
00166 mReferId = GetString("ReferId", mReferId);
00167 mRegisterLink = "http://www.popcap.com/register.php?theGame=" + mProdName + "&referid=" + mReferId;
00168 RegistryReadString("RegisterLink", &mRegisterLink);
00169
00170 int anInt;
00171
00172 if (RegistryReadInteger("DontUpdate", &anInt))
00173 mDontUpdate = anInt != 0;
00174
00175 if (RegistryReadInteger("DownloadId", &anInt))
00176 mDownloadId = anInt;
00177
00178 RegistryReadString("Variation", &mVariation);
00179
00180 if (RegistryReadInteger("TimesPlayed", &anInt))
00181 {
00182 if (!mPlayingDemoBuffer)
00183 {
00184 if (mTimesPlayed != anInt)
00185 mTimesPlayed = 100;
00186 }
00187 else
00188 {
00189 mTimesPlayed = anInt;
00190 }
00191 }
00192
00193 if (RegistryReadInteger("TimesExecuted", &anInt))
00194 {
00195 if (!mPlayingDemoBuffer)
00196 {
00197 if (mTimesExecuted != anInt)
00198 mTimesExecuted = 100;
00199 }
00200 else
00201 {
00202 mTimesExecuted = anInt;
00203 }
00204 }
00205
00206 if (RegistryReadInteger("LastVerCheckQueryTime", &anInt))
00207 {
00208 mLastVerCheckQueryTime = anInt;
00209 }
00210 else
00211 {
00212 time_t aTimeNow;
00213 time(&aTimeNow);
00214
00215 mLastVerCheckQueryTime = aTimeNow;
00216 }
00217
00218 if (RegistryReadString("RegName", &mRegUserName))
00219 mUserName = mRegUserName;
00220
00221 RegistryReadString("RegCode", &mRegCode);
00222
00223 mIsRegistered |= Validate(mRegUserName, mRegCode);
00224
00225
00226 mRegisterLink = GetString("RegisterLink", mRegisterLink);
00227 mDontUpdate = GetBoolean("DontUpdate", mDontUpdate);
00228 }
00229
00230 void SexyApp::WriteToRegistry()
00231 {
00232 SexyAppBase::WriteToRegistry();
00233
00234 if (!mPlayingDemoBuffer)
00235 {
00236 char aFileName[256];
00237 GetWindowsDirectory(aFileName, 256);
00238 if (aFileName[strlen(aFileName)-1] != '\\')
00239 strcat(aFileName, "\\");
00240 strcat(aFileName, "popcinfo.dat");
00241
00242 FILE* fp = fopen(aFileName, "r+b");
00243 if (fp != NULL)
00244 {
00245 for (;;)
00246 {
00247 ushort aLen;
00248 if (fread(&aLen, 1, sizeof(short), fp) == 0)
00249 break;
00250
00251 if (aLen < 256)
00252 {
00253 char aProdName[256];
00254 aProdName[aLen] = '\0';
00255 fread(aProdName, aLen, sizeof(char), fp);
00256
00257 if (strcmp(aProdName, mProdName.c_str()) == 0)
00258 {
00259 fseek(fp, -(2 + aLen), SEEK_CUR);
00260 break;
00261 }
00262 }
00263
00264 fseek(fp, sizeof(int), SEEK_CUR);
00265 }
00266 }
00267 else
00268 fp = fopen(aFileName, "wb");
00269
00270 if (fp != NULL)
00271 {
00272 ushort aLen = mProdName.length();
00273 fwrite(&aLen, 1, sizeof(short), fp);
00274 fwrite(mProdName.c_str(), aLen, sizeof(char), fp);
00275
00276 short aShort = mTimesPlayed;
00277 fwrite(&aShort, 1, sizeof(short), fp);
00278
00279 aShort = mTimesExecuted;
00280 fwrite(&aShort, 1, sizeof(short), fp);
00281
00282 fclose(fp);
00283 }
00284 }
00285
00286 RegistryWriteInteger("LastVerCheckQueryTime", mLastVerCheckQueryTime);
00287 RegistryWriteInteger("TimesPlayed", mTimesPlayed);
00288 RegistryWriteInteger("TimesExecuted", mTimesExecuted);
00289
00290
00291 if ((mRegUserName.length() == 0) &&
00292 (mUserName.length() > 0) &&
00293 (mRegCode.length() > 0))
00294 mRegUserName = mUserName;
00295
00296 if (mRegUserName.length() > 0)
00297 RegistryWriteString("RegName", mRegUserName);
00298
00299 if (mRegCode.length() > 0)
00300 RegistryWriteString("RegCode", mRegCode);
00301 }
00302
00303 bool SexyApp::OpenHTMLTemplate(const std::string& theTemplateFile, const DefinesMap& theDefinesMap)
00304 {
00305 std::fstream anInStream(theTemplateFile.c_str(), std::ios::in);
00306
00307 if (!anInStream.is_open())
00308 return false;
00309
00310 WIN32_FIND_DATA aFindData;
00311 HANDLE aHandle = FindFirstFile("temp\\tpl*.html", &aFindData);
00312 if (aHandle != NULL)
00313 {
00314 do
00315 {
00316 std::string aFilePath = std::string("temp\\") + aFindData.cFileName;
00317 DeleteFile(aFilePath.c_str());
00318 }
00319 while (FindNextFile(aHandle, &aFindData));
00320
00321 FindClose(aHandle);
00322 }
00323
00324 mkdir("temp");
00325
00326 std::string anOutFilename = StrFormat("temp\\tpl%04d.html", rand()%10000);
00327
00328
00329 std::fstream anOutStream(anOutFilename.c_str(), std::ios::out);
00330 if (!anOutStream.is_open())
00331 return false;
00332
00333 char aStr[4096];
00334 while (!anInStream.eof())
00335 {
00336 anInStream.getline(aStr, 4096);
00337
00338 std::string aNewString = Evaluate(aStr, theDefinesMap);
00339
00340 anOutStream << aNewString.c_str() << std::endl;
00341 }
00342
00343 return OpenURL(GetFullPath(anOutFilename));
00344 }
00345
00346 bool SexyApp::OpenRegisterPage(DefinesMap theStatsMap)
00347 {
00348 #ifdef ZYLOM
00349 ZylomGS_StandAlone_ShowBuyPage();
00350 return true;
00351 #endif
00352
00353
00354 DefinesMap aDefinesMap;
00355
00356 aDefinesMap.insert(DefinesMap::value_type("Src", mRegSource));
00357 aDefinesMap.insert(DefinesMap::value_type("ProdName", mProdName));
00358 aDefinesMap.insert(DefinesMap::value_type("Version", mProductVersion));
00359 aDefinesMap.insert(DefinesMap::value_type("Variation", mVariation));
00360 aDefinesMap.insert(DefinesMap::value_type("ReferId", mReferId));
00361 aDefinesMap.insert(DefinesMap::value_type("DownloadId", StrFormat("%d", mDownloadId)));
00362 aDefinesMap.insert(DefinesMap::value_type("TimesPlayed", StrFormat("%d", mTimesPlayed)));
00363 aDefinesMap.insert(DefinesMap::value_type("TimesExecuted", StrFormat("%d", mTimesExecuted)));
00364 aDefinesMap.insert(DefinesMap::value_type("TimedOut", mTimedOut ? "Y" : "N"));
00365
00366
00367 std::string aStatsString;
00368 DefinesMap::iterator anItr = theStatsMap.begin();
00369 while (anItr != theStatsMap.end())
00370 {
00371 std::string aKeyString = anItr->first;
00372 std::string aValueString = anItr->second;
00373
00374 aStatsString +=
00375 StrFormat("%04X", aKeyString.length()) + aKeyString +
00376 "S" +
00377 StrFormat("%04X", aValueString.length()) + aValueString;
00378
00379 ++anItr;
00380 }
00381
00382 aDefinesMap.insert(DefinesMap::value_type("Stats", aStatsString));
00383
00384 if (FileExists("register.tpl"))
00385 {
00386 return OpenHTMLTemplate("register.tpl", aDefinesMap);
00387 }
00388 else
00389 {
00390 return OpenURL(mRegisterLink);
00391 }
00392 }
00393
00394 bool SexyApp::ShouldCheckForUpdate()
00395 {
00396 if (mDontUpdate)
00397 return false;
00398
00399 #ifdef ZYLOM
00400 return ZylomUpdateCheckNeeded();
00401 #else
00402 time_t aTimeNow;
00403 time(&aTimeNow);
00404
00405
00406 return ((mLastVerCheckQueryTime == 0) ||
00407 (!mLastShutdownWasGraceful) ||
00408 ((mLastVerCheckQueryTime != 0) &&
00409 (aTimeNow - mLastVerCheckQueryTime > 7*24*60*60)));
00410 #endif
00411 }
00412
00413 void SexyApp::UpdateCheckQueried()
00414 {
00415 time_t aTimeNow;
00416 time(&aTimeNow);
00417
00418 mLastVerCheckQueryTime = aTimeNow;
00419 }
00420
00421 void SexyApp::URLOpenSucceeded(const std::string& theURL)
00422 {
00423 SexyAppBase::URLOpenSucceeded(theURL);
00424
00425 if (mShutdownOnURLOpen)
00426 mSkipAd = true;
00427 }
00428
00429 bool SexyApp::OpenRegisterPage()
00430 {
00431 DefinesMap aStatsMap;
00432 return OpenRegisterPage(aStatsMap);
00433 }
00434
00435 bool SexyApp::CheckSignature(const Buffer& theBuffer, const std::string& theFileName)
00436 {
00437 #ifdef _DEBUG
00438
00439
00440 return true;
00441 #endif
00442
00443 if (mSkipSignatureChecks)
00444 return true;
00445
00446 char aSigStr[25];
00447
00448 FILE* aFP = fopen((theFileName + ".sig").c_str(), "rb");
00449 if (aFP == NULL)
00450 return false;
00451
00452 fread(aSigStr, 1, 24, aFP);
00453 aSigStr[24] = 0;
00454
00455 fclose(aFP);
00456
00457 char* aFileData = new char[theBuffer.GetDataLen()+4];
00458 int aFileDataPos = 0;
00459
00460 char aStr[9] = {0};
00461 strncpy(aStr, SIGNATURE_CODE_MARKER, 8);
00462 int aSignatureCode = atoi(aStr);
00463
00464 aFileData[aFileDataPos++] = (aSignatureCode & 0xFF);
00465 aFileData[aFileDataPos++] = ((aSignatureCode >> 8) & 0xFF);
00466 aFileData[aFileDataPos++] = ((aSignatureCode >> 16) & 0xFF);
00467 aFileData[aFileDataPos++] = ((aSignatureCode >> 24) & 0xFF);
00468
00469 theBuffer.SeekFront();
00470 while (!theBuffer.AtEnd())
00471 {
00472 unsigned char c = theBuffer.ReadByte();
00473 fread(&c, 1, 1, aFP);
00474 if (!::isspace(c))
00475 aFileData[aFileDataPos++] = c;
00476 }
00477
00478
00479 BigInt n("D99BC76AB7B2578738E606F7");
00480 BigInt e("11");
00481
00482 BigInt aHash = HashData(aFileData, aFileDataPos, 94);
00483 delete aFileData;
00484
00485 BigInt aSignature(aSigStr);
00486 BigInt aHashTest = aSignature.ModPow(e, n);
00487
00488 return aHashTest == aHash;
00489 }
00490
00491 void SexyApp::PreTerminate()
00492 {
00493 #ifdef ZYLOM
00494 ZylomShowAd();
00495 #else
00496 if ((!mSkipAd) &&
00497 ((((!mIsRegistered) || (mInternetManager->HasNewAds())) && ((Rand()%2) == 0))))
00498 {
00499 mInternetManager->TryShowAd();
00500 }
00501 #endif
00502 }
00503
00504 void SexyApp::OpenUpdateURL()
00505 {
00506 #ifdef ZYLOM
00507 ZylomGS_StandAlone_ShowUpdatePage();
00508 #else
00509 OpenURL(mInternetManager->GetUpdateURL(), true);
00510 #endif
00511 Shutdown();
00512 }
00513
00514 void SexyApp::HandleCmdLineParam(const std::string& theParamName, const std::string& theParamValue)
00515 {
00516 if (theParamName == "-version")
00517 {
00518
00519
00520 std::string aVersionString =
00521 "Product: " + mProdName + "\r\n" +
00522 "Version: " + mProductVersion + "\r\n" +
00523 "Build Num: " + StrFormat("%d", mBuildNum) + "\r\n" +
00524 "Build Date: " + mBuildDate;
00525
00526 MessageBox(NULL, aVersionString.c_str(), "Version Info", MB_ICONINFORMATION | MB_OK);
00527 DoExit(0);
00528 }
00529 else
00530 SexyAppBase::HandleCmdLineParam(theParamName, theParamValue);
00531 }
00532
00533 std::string SexyApp::GetGameSEHInfo()
00534 {
00535 char aGamesPlayedStr[16];
00536 sprintf(aGamesPlayedStr, "%d", mTimesPlayed);
00537
00538 std::string anInfoString = SexyAppBase::GetGameSEHInfo() +
00539 "Times Played: " + std::string(aGamesPlayedStr) + "\r\n";
00540 "Build Num: " + StrFormat("%d", mBuildNum) + "\r\n" +
00541 "Build Date: " + mBuildDate + "\r\n";
00542
00543 if (mReferId.length() != 0)
00544 {
00545 anInfoString +=
00546 "ReferId: " + mReferId + "\r\n";
00547 }
00548
00549 return anInfoString;
00550 }
00551
00552 void SexyApp::GetSEHWebParams(DefinesMap* theDefinesMap)
00553 {
00554 theDefinesMap->insert(DefinesMap::value_type("username", mUserName));
00555 theDefinesMap->insert(DefinesMap::value_type("buildnum", StrFormat("%d", mBuildNum)));
00556 theDefinesMap->insert(DefinesMap::value_type("builddate", mBuildDate));
00557 theDefinesMap->insert(DefinesMap::value_type("referid", mReferId));
00558 }
00559
00560 void SexyApp::PreDisplayHook()
00561 {
00562 if (mBetaValidate && !mBetaSupport->Validate())
00563 {
00564 Shutdown();
00565 DoExit(0);
00566 return;
00567 }
00568 }
00569
00570 void SexyApp::InitPropertiesHook()
00571 {
00572
00573 bool checkSig = !IsScreenSaver();
00574 LoadProperties("properties\\partner.xml", false, checkSig);
00575
00576
00577 if (GetBoolean("NoReg", false))
00578 {
00579 mIsRegistered = true;
00580 mBuildUnlocked = true;
00581 }
00582
00583 mProdName = GetString("ProdName", mProdName);
00584 mIsWindowed = GetBoolean("DefaultWindowed", mIsWindowed);
00585
00586 std::string aNewTitle = GetString("Title", "");
00587 if (aNewTitle.length() > 0)
00588 mTitle = aNewTitle + " " + mProductVersion;
00589
00590 mInternetManager->Init();
00591 mBetaSupport = new BetaSupport(this);
00592
00593 #ifdef ZYLOM
00594 LoadProperties();
00595 ZylomGS_StandAlone_Init(mZylomGameId, (char*) GetString("BUG_REPORT_TITLE").c_str(), (char*) GetString("BUG_REPORT_BODY").c_str());
00596 #endif
00597 }
00598
00599 void SexyApp::Init()
00600 {
00601 SEHCatcher::mCrashMessage =
00602 "An unexpected error has occured! Pressing 'Send Report' "
00603 "will send us helpful debugging information that may help "
00604 "us resolve this issue in the future.\r\n\r\n"
00605 "You can also contact us directly at feedback@popcap.com.";
00606
00607 SEHCatcher::mSubmitMessage =
00608 "Please help us out by providing as much information as "
00609 "you can about this crash. Is this the first time it happened? "
00610 "Have you used other PopCap Deluxe games successfully before? "
00611 "Have you upgraded your drivers or any software recently that "
00612 "may be interfering with this program?";
00613
00614 SEHCatcher::mSubmitErrorMessage =
00615 "Failed to connect to PopCap servers. Please check your Internet connection.\n"
00616 "If you are on a dial-up connection, you may have to manually connect to your ISP.";
00617
00618 SEHCatcher::mSubmitHost = "www.popcap.com";
00619
00620 OutputDebugString(StrFormat("Product: %s\r\n", mProdName.c_str()).c_str());
00621 OutputDebugString(StrFormat("BuildNum: %d\r\n", mBuildNum).c_str());
00622 OutputDebugString(StrFormat("BuildDate: %s\r\n", mBuildDate.c_str()).c_str());
00623
00624 SexyAppBase::Init();
00625
00626 if (IsScreenSaver())
00627 mSkipAd = true;
00628
00629 mTimesExecuted++;
00630 }
00631
00632 void SexyApp::UpdateFrames()
00633 {
00634 SexyAppBase::UpdateFrames();
00635
00636 mInternetManager->Update();
00637 }
00638
00639 #ifdef ZYLOM
00640
00641 bool SexyApp::ZylomUpdateCheckNeeded()
00642 {
00643 return ZylomGS_StandAlone_UpdateCheckNeeded();
00644 }
00645
00646 void SexyApp::ZylomShowAd()
00647 {
00648 ZylomGS_StandAlone_ShowAd(mIsRegistered);
00649 }
00650
00651 #endif