client.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522
  1. /*-------------------------------------------------------------------------
  2. Client.cpp
  3. Per client stuff, including site for Clients session
  4. Owner:
  5. Copyright 1986-2000 Microsoft Corporation, All Rights Reserved
  6. *-----------------------------------------------------------------------*/
  7. #include "pch.h"
  8. const DWORD CFLClient::c_dwID = 19680815;
  9. #ifndef NO_MSG_CRC
  10. bool g_fLogonCRC = true;
  11. #endif
  12. static GetRegDWORD(const char* szKey, DWORD dwDefault)
  13. {
  14. DWORD dwResult = dwDefault;
  15. HKEY hk;
  16. if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, HKLM_AllLobby, 0, "",
  17. REG_OPTION_NON_VOLATILE, KEY_READ, NULL, &hk, NULL) == ERROR_SUCCESS)
  18. {
  19. _Module.ReadFromRegistry(hk, false, szKey, &dwResult, dwDefault);
  20. }
  21. return dwResult;
  22. }
  23. void QueueMissions(FedMessaging * pfm)
  24. {
  25. // Send client all the mission infos, in as few packets as possible
  26. bool fIsFreeLobby = g_pLobbyApp->EnforceCDKey();
  27. ListConnections::Iterator iterCnxn(*g_pLobbyApp->GetFMServers().GetConnections());
  28. while (!iterCnxn.End())
  29. {
  30. CFLServer * pServerT = CFLServer::FromConnection(*iterCnxn.Value());
  31. if (!pServerT->GetPaused())
  32. {
  33. MissionList::Iterator iterMissions(*pServerT->GetMissions());
  34. while (!iterMissions.End())
  35. {
  36. FMD_LS_LOBBYMISSIONINFO * plmi = iterMissions.Value()->GetMissionInfo();
  37. if (plmi && (fIsFreeLobby || plmi->nNumPlayers > 0 || plmi->fMSArena))
  38. pfm->QueueExistingMsg(plmi);
  39. iterMissions.Next();
  40. }
  41. }
  42. iterCnxn.Next();
  43. }
  44. }
  45. #ifdef USEAUTH
  46. /*-------------------------------------------------------------------------
  47. * GotLogonInfo
  48. *-------------------------------------------------------------------------
  49. Purpose:
  50. Callback from the database when a logon info query comes back
  51. Parameters:
  52. the completed query
  53. */
  54. void GotLogonInfo(CQLobbyLogon * pquery)
  55. {
  56. FedMessaging & fm = g_pLobbyApp->GetFMClients();
  57. CQLobbyLogonData * pqd = pquery->GetData();
  58. char * szReason = pqd->szReason;
  59. CFMConnection * pcnxn = fm.GetConnectionFromId(pqd->dwConnectionID);
  60. if (!pcnxn)
  61. return; // nothing we can do for someone who's gone
  62. if (g_pLobbyApp->EnforceCDKey() && pqd->fValid && !pqd->fValidCode)
  63. {
  64. pqd->fValid = false;
  65. pqd->fRetry = true;
  66. szReason = "The CD Key you entered is not valid. Please "
  67. "press <CD Key> and re-enter the CD Key from "
  68. "the back of your CD case.";
  69. }
  70. if (pqd->fValid)
  71. {
  72. fm.SetDefaultRecipient(pcnxn, FM_GUARANTEED);
  73. BEGIN_PFM_CREATE(fm, pfmLogonAck, L, LOGON_ACK)
  74. END_PFM_CREATE
  75. pfmLogonAck->dwTimeOffset = pqd->dTime;
  76. // tell them which squads they are on
  77. int cRows;
  78. CQLobbyLogonData * pRows = pquery->GetOutputRows(&cRows); // all the rows are here
  79. SquadMembership* pargSquads = new SquadMembership[cRows];
  80. for (int iSquad = 0; iSquad < cRows; iSquad++)
  81. {
  82. Strcpy(pargSquads[iSquad].m_szSquadName, pRows->szSquadName);
  83. pargSquads[iSquad].m_squadID = pRows->squadID;
  84. pargSquads[iSquad].m_fIsLeader = 0 == pRows->status;
  85. pargSquads[iSquad].m_fIsAssistantLeader = 1 == pRows->status && 1 == pRows->detailedStatus;
  86. }
  87. BEGIN_PFM_CREATE(fm, pfmSquadMemberships, LS, SQUAD_MEMBERSHIPS)
  88. FM_VAR_PARM(cRows ? pargSquads : NULL, sizeof(SquadMembership) * cRows)
  89. END_PFM_CREATE
  90. pfmSquadMemberships->cSquadMemberships = cRows;
  91. delete [] pargSquads;
  92. QueueMissions(FedMessaging * pfm);
  93. }
  94. if (!pqd->fValid)
  95. {
  96. BEGIN_PFM_CREATE(fm, pfmLogonNack, L, LOGON_NACK)
  97. FM_VAR_PARM(szReason, CB_ZTS)
  98. END_PFM_CREATE
  99. pfmLogonNack->fRetry = pqd->fRetry;
  100. }
  101. g_pLobbyApp->GetFMClients().SendMessages(pcnxn, FM_GUARANTEED, FM_FLUSH);
  102. }
  103. #endif
  104. const int c_cMaxPlayers = GetRegDWORD("MaxPlayersPerServer", 350);
  105. HRESULT LobbyClientSite::OnAppMessage(FedMessaging * pthis, CFMConnection & cnxnFrom, FEDMESSAGE * pfm)
  106. {
  107. CFLClient * pClient = CFLClient::FromConnection(cnxnFrom);
  108. assert(pClient);
  109. debugf("Client: %s from <%s> at time %u\n", g_rgszMsgNames[pfm->fmid], cnxnFrom.GetName(), Time::Now());
  110. switch (pfm->fmid)
  111. {
  112. // TODO: remove this post-beta.
  113. case FM_C_LOGON_LOBBY_OLD:
  114. {
  115. #ifndef NO_MSG_CRC
  116. bool fCRC = g_fLogonCRC;
  117. g_fLogonCRC = true; // assume always yes until we find one via OnBadCRC that is not.
  118. #endif
  119. CASTPFM(pfmLogon, C, LOGON_LOBBY_OLD, pfm);
  120. // no need to authenticate - they're out of sync and need to auto-update
  121. if (g_pAutoUpdate && pfmLogon->crcFileList != g_pAutoUpdate->GetFileListCRC())
  122. {
  123. // they need auto update
  124. BEGIN_PFM_CREATE(*pthis, pfmAutoUpdate, L, AUTO_UPDATE_INFO)
  125. FM_VAR_PARM(g_pAutoUpdate->GetFTPServer(), CB_ZTS)
  126. FM_VAR_PARM(g_pAutoUpdate->GetFTPInitialDir(), CB_ZTS)
  127. FM_VAR_PARM(g_pAutoUpdate->GetFTPAccount(), CB_ZTS)
  128. FM_VAR_PARM(g_pAutoUpdate->GetFTPPassword(), CB_ZTS)
  129. END_PFM_CREATE
  130. pfmAutoUpdate->crcFileList = g_pAutoUpdate->GetFileListCRC();
  131. pfmAutoUpdate->nFileListSize = g_pAutoUpdate->GetFileListSize();
  132. }
  133. else
  134. {
  135. // tell client that his version is wrong
  136. char * szReason = "Your game's version did not get auto-updated properly. Please try again later.";
  137. BEGIN_PFM_CREATE(*pthis, pfmLogonNack, L, LOGON_NACK)
  138. FM_VAR_PARM((char *)szReason, CB_ZTS)
  139. END_PFM_CREATE
  140. pfmLogonNack->fRetry = false;
  141. }
  142. #ifndef NO_MSG_CRC
  143. // Big hack to communicate w/ old non-crc clients. This is the ONLY time we send them any non-crc'd messages
  144. // by increasing the announced size of the message, the client will skip past the crc.
  145. if (!fCRC)
  146. *(CB*)(pthis->BuffOut()) += sizeof(int);
  147. #endif
  148. pthis->SendMessages(&cnxnFrom, FM_GUARANTEED, FM_FLUSH);
  149. }
  150. break;
  151. case FM_C_LOGON_LOBBY:
  152. {
  153. CASTPFM(pfmLogon, C, LOGON_LOBBY, pfm);
  154. bool fValid = false; // whether we have a valid logon
  155. bool fRetry = false;
  156. char * szReason = NULL; // when fValid==false
  157. #ifdef USEAUTH
  158. LPBYTE pZoneTicket = (LPBYTE) FM_VAR_REF(pfmLogon, ZoneTicket);
  159. TRef<IZoneAuthServer> pzas = g_pLobbyApp->GetZoneAuthServer();
  160. CQLobbyLogon * pquery = new CQLobbyLogon(GotLogonInfo);
  161. CQLobbyLogonData * pqd = pquery->GetData();
  162. pqd->dTime = pfmLogon->dwTime - Time::Now().clock();
  163. Strcpy(pqd->szCharacterName, cnxnFrom.GetName()); // unless and until we get one form the zticket
  164. pqd->characterID = 0;
  165. if (pzas) // it's all in the Zone Ticket
  166. {
  167. if (pZoneTicket)
  168. {
  169. HRESULT hr = pzas->DecryptTicket(pZoneTicket, pfmLogon->cbZoneTicket);
  170. switch (hr)
  171. {
  172. case ZT_NO_ERROR:
  173. {
  174. bool fValidNow = false;
  175. Strcpy(pqd->szCharacterName, pzas->GetName());
  176. pqd->characterID = pzas->GetAccountID();
  177. fValid = pzas->HasToken(g_pLobbyApp->GetToken(), &fValidNow);
  178. // todo: keep track of players for find/zone friends
  179. if (!(fValid && fValidNow))
  180. {
  181. fRetry = true;
  182. const char szExpired[] = "The Allegiance Zone subscription for %s has expired. Hit <Sign Up> to go to the Allegiance Zone signup and subscription page, where you can renew your account subscription.";
  183. const char szNoToken[] = "The %s Zone account does not have a valid Allegiance Zone subscription. Hit <Sign Up> to go to the Allegiance Zone signup and subscription page, where you can look up your account status.";
  184. const DWORD cbReason = 25 + max(sizeof(szNoToken), sizeof(szExpired)); // 25 = sizeof max zoneid
  185. szReason = (char*)_alloca(cbReason);
  186. _snprintf(szReason, cbReason, (fValid ? szExpired : szNoToken), pqd->szCharacterName);
  187. fValid = false;
  188. }
  189. else if (g_pLobbyApp->EnforceCDKey())
  190. {
  191. const char * szEncryptedCDKey = (const char*) FM_VAR_REF(pfmLogon, CDKey);
  192. const char * szName = pzas->GetName();
  193. if (!szEncryptedCDKey || szEncryptedCDKey[pfmLogon->cbCDKey - 1] != '\0')
  194. szEncryptedCDKey = "";
  195. char * szDecryptionKey = (char *)_alloca(strlen(CL_LOGON_KEY) + 12 + c_cbName);
  196. wsprintf(szDecryptionKey, CL_LOGON_KEY, pfmLogon->dwTime, szName);
  197. // note: they can get away with a replay attack here, but only
  198. // if they keep the name the same.
  199. ZUnscramble(pqd->szCDKey, szEncryptedCDKey, szDecryptionKey);
  200. ZString strOldPlayer;
  201. if (g_pLobbyApp->BootPlayersByCDKey(pqd->szCDKey, szName, strOldPlayer))
  202. {
  203. fValid = false;
  204. fRetry = true;
  205. const char szDuplicateCDKey[] = "%s was logged on with your CD Key!";
  206. const DWORD cbReason = 25 + sizeof(szDuplicateCDKey); // 25 = sizeof max zoneid
  207. szReason = (char*)_alloca(cbReason);
  208. _snprintf(szReason, cbReason, szDuplicateCDKey, (PCC)strOldPlayer);
  209. }
  210. }
  211. break;
  212. }
  213. case ZT_E_BUFFER_TOO_SMALL:
  214. g_pLobbyApp->GetSite()->LogEvent(EVENTLOG_WARNING_TYPE, LE_MoreTokens);
  215. break;
  216. case ZT_E_AUTH_INVALID_TICKET:
  217. {
  218. char szRemoteAddress[16];
  219. HRESULT hr = pthis->GetIPAddress(cnxnFrom, szRemoteAddress);
  220. g_pLobbyApp->GetSite()->LogEvent(EVENTLOG_WARNING_TYPE, LE_BadZTicket,
  221. SUCCEEDED(hr) ? szRemoteAddress : "unknown");
  222. szReason = "Could not validate Zone ID.";
  223. break;
  224. }
  225. default:
  226. g_pLobbyApp->GetSite()->LogEvent(EVENTLOG_ERROR_TYPE, LE_DecryptTicketFailure, hr);
  227. }
  228. }
  229. else
  230. {
  231. char szRemoteAddress[16];
  232. HRESULT hr = pthis->GetIPAddress(cnxnFrom, szRemoteAddress);
  233. g_pLobbyApp->GetSite()->LogEvent(EVENTLOG_WARNING_TYPE, LE_NoCredentials,
  234. SUCCEEDED(hr) ? szRemoteAddress : "unknown");
  235. szReason = "No login credentials provided. This is the zone lobby which requires secure logins. Perhaps you are looking for the Internet Lobby.";
  236. }
  237. }
  238. else
  239. #endif
  240. fValid = true; // if this isn't secure, then you're automatically in
  241. if (g_pAutoUpdate && pfmLogon->crcFileList != g_pAutoUpdate->GetFileListCRC())
  242. {
  243. // they need auto update
  244. BEGIN_PFM_CREATE(*pthis, pfmAutoUpdate, L, AUTO_UPDATE_INFO)
  245. FM_VAR_PARM(g_pAutoUpdate->GetFTPServer(), CB_ZTS)
  246. FM_VAR_PARM(g_pAutoUpdate->GetFTPInitialDir(), CB_ZTS)
  247. FM_VAR_PARM(g_pAutoUpdate->GetFTPAccount(), CB_ZTS)
  248. FM_VAR_PARM(g_pAutoUpdate->GetFTPPassword(), CB_ZTS)
  249. END_PFM_CREATE
  250. pfmAutoUpdate->crcFileList = g_pAutoUpdate->GetFileListCRC();
  251. pfmAutoUpdate->nFileListSize = g_pAutoUpdate->GetFileListSize();
  252. // This is sort of a wacky case. It's the only case that's neither valid nor invalid.
  253. // That is, we neither send a logon ack, nor a logon nack, so we kind of have to munge things
  254. pthis->SendMessages(&cnxnFrom, FM_GUARANTEED, FM_FLUSH);
  255. #ifdef USEAUTH
  256. delete pquery;
  257. #endif
  258. break; // out of big switch
  259. }
  260. if (fValid)
  261. {
  262. // they don't need auto update
  263. // verify messaging version
  264. if(pfmLogon->verLobby != LOBBYVER)
  265. {
  266. fValid = false;
  267. // tell client that his version is wrong
  268. szReason = "Your game's version did not get auto-updated properly. Please try again later.";
  269. }
  270. }
  271. #ifdef USEAUTH
  272. pqd->fValid = fValid;
  273. pqd->fRetry = fRetry;
  274. // I'd rather not alloc, but since the strings are not all static, and failure should be fairly uncommon, I'll accept it
  275. pqd->szReason = new char[lstrlen(szReason) + 1];
  276. Strcpy(pqd->szReason, szReason);
  277. pqd->dwConnectionID = cnxnFrom.GetID();
  278. if (fValid)
  279. g_pLobbyApp->GetSQL().PostQuery(pquery);
  280. else
  281. pquery->DataReady();
  282. #else
  283. pthis->SetDefaultRecipient(&cnxnFrom, FM_GUARANTEED);
  284. BEGIN_PFM_CREATE(*pthis, pfmLogonAck, L, LOGON_ACK)
  285. END_PFM_CREATE
  286. pfmLogonAck->dwTimeOffset = pfmLogon->dwTime - Time::Now().clock();
  287. QueueMissions(pthis);
  288. g_pLobbyApp->GetFMClients().SendMessages(&cnxnFrom, FM_GUARANTEED, FM_FLUSH);
  289. #endif
  290. }
  291. break;
  292. case FM_C_LOGOFF_LOBBY:
  293. {
  294. // TODO: mark 'em so we know they weren't dropped
  295. }
  296. break;
  297. case FM_C_CREATE_MISSION_REQ:
  298. {
  299. // Choose a server to host the game on
  300. CFLServer * pServerMin = NULL;
  301. //int cPlayersMin = 10000; // some big number we'll never hit
  302. int cPlayersMin = c_cMaxPlayers;
  303. debugf("Received mission creation request from %s\n", cnxnFrom.GetName());
  304. ListConnections::Iterator iterCnxn(*g_pLobbyApp->GetFMServers().GetConnections());
  305. while (!iterCnxn.End())
  306. {
  307. CFLServer * pServerT = CFLServer::FromConnection(*iterCnxn.Value());
  308. if (!pServerT->GetPaused() && pServerT->GetPlayerCount() < cPlayersMin)
  309. {
  310. cPlayersMin = pServerT->GetPlayerCount();
  311. pServerMin = pServerT;
  312. }
  313. iterCnxn.Next();
  314. }
  315. if (pServerMin)
  316. {
  317. CFLMission * pMission = pServerMin->CreateMission(pClient);
  318. BEGIN_PFM_CREATE(g_pLobbyApp->GetFMServers(), pfmNewMissionReq, L, CREATE_MISSION_REQ)
  319. FM_VAR_PARM(cnxnFrom.GetName(), CB_ZTS)
  320. END_PFM_CREATE
  321. pfmNewMissionReq->dwCookie = pMission->GetCookie();
  322. // Tell the player that their mission is on the way
  323. BEGIN_PFM_CREATE(*pthis, pfmCreateMissionAck, L, CREATE_MISSION_ACK)
  324. END_PFM_CREATE
  325. pfmCreateMissionAck->dwCookie = pfmNewMissionReq->dwCookie;
  326. g_pLobbyApp->GetFMServers().SendMessages(pServerMin->GetConnection(), FM_GUARANTEED, FM_FLUSH);
  327. // TODO: check up on this mission later to make sure that we got a lobbymissioninfo from the server
  328. }
  329. else
  330. {
  331. debugf("No servers exist to create the game on\n");
  332. BEGIN_PFM_CREATE(*pthis, pfmCreateMissionNack, L, CREATE_MISSION_NACK)
  333. END_PFM_CREATE
  334. }
  335. pthis->SendMessages(&cnxnFrom, FM_GUARANTEED, FM_FLUSH);
  336. }
  337. break;
  338. case FM_C_JOIN_GAME_REQ:
  339. {
  340. CASTPFM(pfmJoinGameReq, C, JOIN_GAME_REQ, pfm);
  341. CFLMission * pMission = CFLMission::FromCookie(pfmJoinGameReq->dwCookie);
  342. if (pMission && pMission->GetServer()->GetPlayerCount() < c_cMaxPlayers)
  343. {
  344. BEGIN_PFM_CREATE(*pthis, pfmJoinMission, L, JOIN_MISSION)
  345. END_PFM_CREATE
  346. char szServer[16];
  347. g_pLobbyApp->GetFMServers().GetIPAddress(*pMission->GetServer()->GetConnection(), szServer);
  348. assert(lstrlen(szServer) < sizeof(pfmJoinMission->szServer)); // as long as szServer is fixed length
  349. lstrcpy(pfmJoinMission->szServer, szServer);
  350. pfmJoinMission->dwCookie = pfmJoinGameReq->dwCookie;
  351. pfmJoinMission->guidInstance = GUID_NULL; // until we have separate sessions for each game
  352. }
  353. else
  354. {
  355. BEGIN_PFM_CREATE(*pthis, pfmJoingameNack, L, JOIN_GAME_NACK)
  356. END_PFM_CREATE
  357. // client will know which one, because they're waiting for it
  358. }
  359. pthis->SendMessages(&cnxnFrom, FM_GUARANTEED, FM_FLUSH);
  360. }
  361. break;
  362. case FM_C_FIND_PLAYER:
  363. {
  364. CASTPFM(pfmFindPlayer, C, FIND_PLAYER, pfm);
  365. const char* szCharacterName = FM_VAR_REF(pfmFindPlayer, szCharacterName);
  366. CFLMission * pMissionFound = NULL;
  367. if (szCharacterName == NULL || szCharacterName[pfmFindPlayer->cbszCharacterName-1] != '\0')
  368. {
  369. // corrupt data
  370. g_pLobbyApp->GetSite()->LogEvent(EVENTLOG_WARNING_TYPE, LE_CorruptFindPlayerMsg,
  371. cnxnFrom.GetName(), cnxnFrom.GetID());
  372. }
  373. else
  374. pMissionFound = g_pLobbyApp->FindPlayersMission(szCharacterName);
  375. BEGIN_PFM_CREATE(*pthis, pfmFoundPlayer, L, FOUND_PLAYER)
  376. END_PFM_CREATE
  377. pfmFoundPlayer->dwCookie = pMissionFound ? pMissionFound->GetCookie() : -1;
  378. pthis->SendMessages(&cnxnFrom, FM_GUARANTEED, FM_FLUSH);
  379. }
  380. break;
  381. default:
  382. g_pLobbyApp->GetSite()->LogEvent(EVENTLOG_WARNING_TYPE, LE_UnknownMsgFromPlayer,
  383. pfm->fmid, cnxnFrom.GetName(), cnxnFrom.GetID());
  384. }
  385. return S_OK;
  386. }
  387. HRESULT LobbyClientSite::OnSysMessage(FedMessaging * pthis)
  388. {
  389. return S_OK;
  390. }
  391. void LobbyClientSite::OnMessageNAK(FedMessaging * pthis, DWORD dwTime, CFMRecipient * prcp)
  392. {
  393. debugf("ACK!! A guaranteed message didn't make it through to recipient %s.\n", prcp->GetName());
  394. }
  395. HRESULT LobbyClientSite::OnNewConnection(FedMessaging * pthis, CFMConnection & cnxn)
  396. {
  397. CFLClient * pClient = new CFLClient(&cnxn);
  398. debugf("Player %s has connected.\n", cnxn.GetName());
  399. g_pLobbyApp->GetCounters()->cLogins++;
  400. return S_OK;
  401. }
  402. HRESULT LobbyClientSite::OnDestroyConnection(FedMessaging * pthis, CFMConnection & cnxn)
  403. {
  404. debugf("Player %s has left.\n", cnxn.GetName());
  405. g_pLobbyApp->GetCounters()->cLogoffs++;
  406. delete CFLClient::FromConnection(cnxn);
  407. return S_OK;
  408. }
  409. HRESULT LobbyClientSite::OnSessionLost(FedMessaging * pthis)
  410. {
  411. g_pLobbyApp->GetSite()->LogEvent(EVENTLOG_ERROR_TYPE, LE_ClientsSessionLost);
  412. return S_OK;
  413. }
  414. int LobbyClientSite::OnMessageBox(FedMessaging * pthis, const char * strText, const char * strCaption, UINT nType)
  415. {
  416. debugf("LobbyClientSite::OnMessageBox: ");
  417. return g_pLobbyApp->OnMessageBox(strText, strCaption, nType);
  418. }
  419. #ifndef NO_MSG_CRC
  420. void LobbyClientSite::OnBadCRC(FedMessaging * pthis, CFMConnection & cnxn, BYTE * pMsg, DWORD cbMsg)
  421. {
  422. char buf[256];
  423. // We don't KNOW it's a logon, but let's assume it is (it's ok if it's not)
  424. FMD_C_LOGON_LOBBY * pfmLogon = (FMD_C_LOGON_LOBBY *) pMsg;
  425. if (pfmLogon->fmid == FM_C_LOGON_LOBBY &&
  426. cbMsg == sizeof(FMD_C_LOGON_LOBBY) + pfmLogon->cbZoneTicket) // we'll accept it, just so that we can auto-update
  427. {
  428. // there can never be a piggy-backed message w/ FM_C_LOGON_LOBBY
  429. g_fLogonCRC = false;
  430. OnAppMessage(pthis, cnxn, pfmLogon);
  431. }
  432. else
  433. {
  434. wsprintf(buf, "HEY! We got a corrupt message!\nPlayer=%s(%d), "
  435. "cbmsg=%d, fmid=%d, total packet size=%d.\n"
  436. "Copy the above line to crashplayers.txt on \\\\zoneagga01. Going to drop player now.\n",
  437. cnxn.GetName(), cnxn.GetID(),
  438. cbMsg >= 2 ? pfmLogon->cbmsg : 0, cbMsg >= 4 ? pfmLogon->fmid : 0, cbMsg);
  439. OnMessageBox(pthis, buf, "AllLobby", 0);
  440. pthis->DeleteConnection(cnxn); // bye bye now
  441. }
  442. }
  443. #endif