Starshatter_Open
Open source Starshatter engine
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
NetLobbyServer.cpp
Go to the documentation of this file.
1 /* Project Starshatter 4.5
2  Destroyer Studios LLC
3  Copyright © 1997-2004. All Rights Reserved.
4 
5  SUBSYSTEM: Stars.exe
6  FILE: NetLobbyServer.cpp
7  AUTHOR: John DiCamillo
8 
9 
10  OVERVIEW
11  ========
12  NetLink Engine for Multiplayer Lobby
13 */
14 
15 #include "MemDebug.h"
16 #include "NetLobbyServer.h"
17 #include "NetServerConfig.h"
18 #include "NetClientConfig.h"
19 #include "NetBrokerClient.h"
20 #include "NetAuth.h"
21 #include "NetChat.h"
22 #include "NetUser.h"
23 #include "Campaign.h"
24 #include "Mission.h"
25 #include "StarServer.h"
26 #include "Starshatter.h"
27 #include "StarServer.h"
28 #include "ShipDesign.h"
29 #include "Sim.h"
30 
31 #include "ModConfig.h"
32 #include "ModInfo.h"
33 
34 #include "NetGame.h"
35 #include "NetPlayer.h"
36 #include "NetUtil.h"
37 
38 #include "NetPeer.h"
39 #include "NetLayer.h"
40 #include "NetHost.h"
41 #include "NetMsg.h"
42 
43 #include "MachineInfo.h"
44 #include "Game.h"
45 #include "FormatUtil.h"
46 
47 extern const char* versionInfo;
48 
49 // +-------------------------------------------------------------------+
50 
51 static NetLobbyServer* net_lobby_server = 0;
52 
54 : announce_time(0), server_config(0), motd_index(1)
55 {
57  server_name = Text("Starshatter NetLobbyServer ") + versionInfo;
59 
60  selected_mission = 0;
61 
62  WORD server_port = 11100;
63 
65  if (server_config) {
67  server_port = server_config->GetLobbyPort();
69 
71 
72  server_addr = NetAddr(NetHost().Address().IPAddr(), server_port);
73  link = new(__FILE__,__LINE__) NetLink(server_addr);
74  }
75 
76  LoadMOTD();
77 
78  StarServer* star_server = StarServer::GetInstance();
79  DWORD mission_id = 0;
80 
81  // only one mission:
82  if (star_server && server_mission.length() > 0) {
83  NetCampaignInfo* c = new(__FILE__,__LINE__) NetCampaignInfo;
85  c->name = "Persistent Multiplayer";
86  campaigns.append(c);
87 
89  while (++c_iter && !mission_id) {
90  Campaign* campaign = c_iter.value();
91 
92  if (campaign->GetCampaignId() == Campaign::MULTIPLAYER_MISSIONS) {
93  ListIter<MissionInfo> m_iter = campaign->GetMissionList();
94  while (++m_iter && !mission_id) {
95  MissionInfo* m = m_iter.value();
96 
97  if (m->script == server_mission) {
98  c->missions.append(m);
100 
101  SelectMission(mission_id);
102  star_server->SetGameMode(StarServer::LOAD_MODE);
103 
104  // lock in mission:
106  }
107  }
108  }
109  }
110  }
111 
112  // player host may select mission:
113  if (!mission_id) {
114  campaigns.destroy();
115 
117  while (++c_iter) {
118  Campaign* campaign = c_iter.value();
119 
120  if (campaign->GetCampaignId() >= Campaign::MULTIPLAYER_MISSIONS) {
121  NetCampaignInfo* c = new(__FILE__,__LINE__) NetCampaignInfo;
122  c->id = campaign->GetCampaignId();
123  c->name = campaign->Name();
124  campaigns.append(c);
125 
126  ListIter<MissionInfo> m_iter = campaign->GetMissionList();
127  while (++m_iter) {
128  MissionInfo* m = m_iter.value();
129  c->missions.append(m);
130  }
131  }
132  }
133  }
134 
135  ModConfig* config = ModConfig::GetInstance();
136  List<ModInfo>& mods = config->GetModInfoList();
137 
138  server_mods.clear();
139  server_mods.append(mods);
140 
141  net_lobby_server = this;
142 }
143 
145 {
146  ListIter<NetUser> iter = users;
147  while (++iter) {
148  NetUser* u = iter.value();
150  ExecFrame();
151  }
152 
153  Sleep(500);
154 
155  unit_map.destroy();
156  chat_log.destroy();
157  users.destroy();
158  motd.destroy();
159 
160  if (net_lobby_server == this)
161  net_lobby_server = 0;
162 }
163 
166 {
167  return net_lobby_server;
168 }
169 
170 // +--------------------------------------------------------------------+
171 
172 void
174 {
175  motd.destroy();
176 
177  FILE* f;
178  fopen_s(&f, "motd.txt", "r");
179 
180  if (f) {
181  char line[256];
182 
183  while (fgets(line, 256, f)) {
184  int n = strlen(line) - 1;
185 
186  while (n >= 0 && isspace(line[n]))
187  line[n--] = 0;
188 
189  motd.append(new(__FILE__,__LINE__) Text(line));
190  }
191  }
192 }
193 
194 void
196 {
197  if (motd.size() < 1) return;
198 
199  char buffer[512];
200 
201  for (int i = 0; i < motd.size(); i++) {
202  Text* line = motd[i];
203 
204  sprintf_s(buffer, "id %d user \" \" msg \"%s\"",
205  motd_index++, line->data());
206 
207  SendData(user, NET_LOBBY_CHAT, buffer);
208  }
209 
210  sprintf_s(buffer, "id %d user \" \" msg \" \"", motd_index++);
211  SendData(user, NET_LOBBY_CHAT, buffer);
212 }
213 
214 void
216 {
217  char buffer[300];
218 
219  ModConfig* config = ModConfig::GetInstance();
220  List<ModInfo>& mods = config->GetModInfoList();
221 
222  if (mods.size() < 1) return;
223 
224  for (int i = 0; i < mods.size(); i++) {
225  ModInfo* info = mods[i];
226 
227  sprintf_s(buffer, "id %d user \"Enabled Mods:\" msg \"%d. '%s' ",
228  motd_index++, i+1, info->Name().data());
229 
230  Text msg = buffer;
231 
232  if (info->Version().length() > 0) {
233  msg += "version ";
234  msg += info->Version().data();
235  }
236 
237  if (info->URL().length() > 0) {
238  msg += " - ";
239  msg += info->URL().data();
240  }
241 
242  msg += "\"";
243 
244  SendData(user, NET_LOBBY_CHAT, msg);
245  }
246 
247  sprintf_s(buffer, "id %d user \" \" msg \" \"", motd_index++);
248  SendData(user, NET_LOBBY_CHAT, buffer);
249 }
250 
251 // +--------------------------------------------------------------------+
252 
253 void
255 {
257 
258  if (announce_time == 0 || Game::RealTime() - announce_time > 200000) {
259  GameOn();
261  }
262 
264  NetGame* net_game = NetGame::GetInstance();
265 
266  if (net_game && net_game->NumPlayers() > 0) {
268  }
269  }
270 
271  StarServer* star_server = StarServer::GetInstance();
272  DWORD mission_id = 0;
273 
274  // restart persistent mission?
275  if (star_server &&
276  star_server->GetGameMode() == StarServer::MENU_MODE &&
277  server_mission.length() > 0) {
278 
280 
281  if (!c || c->name != "Persistent Multiplayer") {
282  c = new(__FILE__,__LINE__) NetCampaignInfo;
284  c->name = "Persistent Multiplayer";
285  campaigns.append(c);
286  }
287  else {
288  c->missions.clear();
289  }
290 
292  while (++c_iter && !mission_id) {
293  Campaign* campaign = c_iter.value();
294 
295  if (campaign->GetCampaignId() == Campaign::MULTIPLAYER_MISSIONS) {
296  ListIter<MissionInfo> m_iter = campaign->GetMissionList();
297  while (++m_iter && !mission_id) {
298  MissionInfo* m = m_iter.value();
299 
300  if (m->script == server_mission) {
301  c->missions.append(m);
303 
304  // unlock old mission:
306 
307  SelectMission(mission_id);
308 
309  if (star_server->GetGameMode() == StarServer::MENU_MODE) {
310  star_server->SetGameMode(StarServer::LOAD_MODE);
311  }
312 
313  // lock in new mission:
315  }
316  }
317  }
318  }
319  }
320 
321  CheckSessions();
322 }
323 
324 // +-------------------------------------------------------------------+
325 
326 void
328 {
329  if (link && dst && type > 0 && type < 255) {
330  if (msg.length())
331  link->SendMessage(dst->GetNetID(), (BYTE) type, msg.data(), msg.length(), NetMsg::RELIABLE);
332  else
333  link->SendMessage(dst->GetNetID(), (BYTE) type, 0, 0, NetMsg::RELIABLE);
334  }
335 }
336 
337 // +-------------------------------------------------------------------+
338 
339 void
341 {
342  if (!link)
343  return;
344 
345  bool dropped = false;
346 
347  ListIter<NetUser> u_iter = users;
348  while (++u_iter) {
349  NetUser* u = u_iter.value();
350  NetPeer* p = link->FindPeer(u->GetNetID());
351 
352  if (p && (NetLayer::GetUTC() - p->LastReceiveTime()) > NET_DISCONNECT_TIME) {
353  // check game peer for activity:
355  NetPlayer* player = 0;
356  NetPeer* p2 = 0;
357 
358  if (game) {
359  player = game->FindPlayerByName(u->Name());
360 
361  if (player) {
362  p2 = game->GetPeer(player);
363 
364  if (p2 && (NetLayer::GetUTC() - p2->LastReceiveTime()) < NET_DISCONNECT_TIME) {
366  continue;
367  }
368  }
369  else {
370  ::Print("NetLobbyServer::CheckSessions() Could not find player for '%s'\n", u->Name().data());
371  }
372  }
373  else {
374  ::Print("NetLobbyServer::CheckSessions() Could not find net game for '%s'\n", u->Name().data());
375  }
376 
377  // announce drop:
378  char timestr[64];
379  FormatTime(timestr, Game::RealTime()/1000);
380  Print("NetLobbyServer: Dropped inactive connection '%s' %s\n",
381  u->Name().data(), timestr);
382 
383  if (u->IsHost()) {
384  Print(" User was host - ending net game.\n");
385  GameStop();
386  }
387 
388  u_iter.removeItem(); // first remove user from list
389  NetLobby::UnmapUnit(u->Name()); // then unmap unit
390  delete u; // now it is safe to discard the inactive user
391 
392  dropped = true;
393  }
394  }
395 
396  if (dropped) {
397  SendUsers();
398  SendUnits();
399  }
400 }
401 
402 // +-------------------------------------------------------------------+
403 
404 void
406 {
409 
410  if (Starshatter::GetInstance()) {
412  }
413  else {
415  if (s && s->GetGameMode() == StarServer::MENU_MODE) {
417  }
418  }
419  }
420 }
421 
422 void
424 {
427 
429  if (s && s->GetGameMode() != StarServer::MENU_MODE) {
431  }
432  }
433 }
434 
435 // +-------------------------------------------------------------------+
436 
437 void
439 {
440  if (user && !user->IsHost()) {
441  ::Print("NetLobbyServer::BanUser name '%s' addr %d.%d.%d.%d\n",
442  user->Name().data(),
443  user->GetAddress().B1(),
444  user->GetAddress().B2(),
445  user->GetAddress().B3(),
446  user->GetAddress().B4());
447 
448  SendData(user, NET_LOBBY_EXIT, Text());
449 
450  if (server_config)
451  server_config->BanUser(user);
452 
453  DelUser(user);
454  }
455 }
456 
457 void
459 {
460  if (server_config && server_config->IsUserBanned(user)) {
461  delete user;
462  return;
463  }
464 
465  NetLobby::AddUser(user);
466  SendUsers();
467 }
468 
469 void
471 {
472  NetLobby::DelUser(user);
473  SendUsers();
474 }
475 
476 void
478 {
479  Text content;
480 
481  ListIter<NetUser> u_iter = users;
482  while (++u_iter) {
483  NetUser* u = u_iter.value();
484  content += u->GetDescription();
485  }
486 
487  u_iter.reset();
488 
489  while (++u_iter) {
490  NetUser* u = u_iter.value();
491  SendData(u, NET_LOBBY_USER_LIST, content);
492  }
493 }
494 
495 // +-------------------------------------------------------------------+
496 
497 void
499 {
500  if (user) {
501  Text request = NetAuth::CreateAuthRequest(user);
502 
503  if (request.length() > 0)
504  SendData(user, NET_LOBBY_AUTH_USER, request);
505  }
506 }
507 
508 // +-------------------------------------------------------------------+
509 
510 void
511 NetLobbyServer::AddChat(NetUser* user, const char* msg, bool route)
512 {
513  NetChatEntry* entry = 0;
514 
515  if (user && msg && *msg) {
516  bool msg_ok = false;
517  const char* p = msg;
518 
519  while (*p && !msg_ok) {
520  if (!isspace(*p++))
521  msg_ok = true;
522  }
523 
524  if (msg_ok) {
525  entry = new(__FILE__,__LINE__) NetChatEntry(user, msg);
526 
527  chat_log.append(entry);
528 
529  // forward to all clients:
530  if (users.size()) {
531  char buffer[768];
532  char msg_buf[256];
533  char usr_buf[256];
534 
535  // safe quotes uses a static buffer,
536  // so make sure to save copies of the
537  // results when using more than one in
538  // a function call...
539 
540  strcpy_s(msg_buf, SafeQuotes(msg));
541  strcpy_s(usr_buf, SafeQuotes(user->Name()));
542 
543  sprintf_s(buffer, "id %d user \"%s\" msg \"%s\"",
544  entry->GetID(), usr_buf, msg_buf);
545 
546  ListIter<NetUser> iter = users;
547  while (++iter) {
548  NetUser* u = iter.value();
549  SendData(u, NET_LOBBY_CHAT, buffer);
550  }
551 
552  if (route) {
553  // send to active game:
554  NetUtil::SendChat(0xffff, usr_buf, msg_buf);
555  }
556  }
557  }
558  }
559 }
560 
561 void
563 {
565 }
566 
567 void
569 {
570  FILE* f;
571  fopen_s(&f, "chat.txt", "w");
572  if (f) {
573  for (int i = 0; i < chat_log.size(); i++) {
574  NetChatEntry* c = chat_log[i];
575  fprintf(f, "%08x [%s] %s\n",
576  c->GetTime(),
577  c->GetUser().data(),
578  c->GetMessage().data());
579  }
580 
581  fclose(f);
582  }
583 }
584 
585 // +-------------------------------------------------------------------+
586 
587 void
589 {
591  return;
592 
594 
595  // inform all users of the selection:
596  char buffer[32];
597  sprintf_s(buffer, "m_id 0x%08x", selected_mission);
598 
599  ListIter<NetUser> iter = users;
600  while (++iter) {
601  NetUser* u = iter.value();
603  }
604 }
605 
606 // +-------------------------------------------------------------------+
607 
610 {
611  if (!mission) {
612  unit_map.destroy();
613  return unit_map;
614  }
615 
616  List<NetUnitEntry> units;
618  int i = 0;
619 
620  Sim* sim = Sim::GetSim();
621  if (sim && sim->GetElements().size() > 0)
622  iter = sim->GetMissionElements();
623 
624  // create new entries for the playable elements in the mission or simulation:
625  while (++iter) {
626  MissionElement* elem = iter.value();
627 
628  if (elem->IsPlayable()) {
629  NetUnitEntry* u = 0;
630  if (elem->Count() == 1) {
631  u = new(__FILE__,__LINE__) NetUnitEntry(elem, 0);
632  u->SetLives(elem->RespawnCount() + 1);
633  u->SetMissionRole(elem->MissionRole());
634  u->SetIFF(elem->GetIFF());
635 
636  if (elem->GetDesign())
637  u->SetDesign(elem->GetDesign()->name);
638 
639  if (elem->Ships().size() > 0) {
640  MissionShip* s = elem->Ships()[0];
641  u->SetIntegrity((int) s->Integrity());
642  }
643  units.append(u);
644  }
645  else {
646  for (int i = 0; i < elem->Count(); i++) {
647  u = new(__FILE__,__LINE__) NetUnitEntry(elem, i+1);
648  u->SetMissionRole(elem->MissionRole());
649  u->SetIFF(elem->GetIFF());
650 
651  if (elem->GetDesign())
652  u->SetDesign(elem->GetDesign()->name);
653 
654  if (elem->Ships().size() > i) {
655  MissionShip* s = elem->Ships()[i];
656  u->SetLives(s->Respawns() + 1);
657  u->SetIntegrity((int) s->Integrity());
658  }
659  units.append(u);
660  }
661  }
662  }
663  }
664 
665  // match new entries with any existing map entries:
666  if (unit_map.size()) {
667  for (i = 0; i < units.size(); i++) {
668  NetUnitEntry* e_new = units[i];
669  NetUnitEntry* e_old = unit_map.find(e_new);
670 
671  if (e_old) {
672  e_new->SetUserName(e_old->GetUserName());
673  e_new->SetLock(e_old->GetLocked());
674  }
675  }
676  }
677 
678  // rewrite the unit map with the new entries:
679  ClearUnitMap();
680  for (i = 0; i < units.size(); i++) {
681  unit_map.append(units[i]);
682  }
683 
684  return unit_map;
685 }
686 
687 void
688 NetLobbyServer::MapUnit(int n, const char* user, bool lock)
689 {
690  NetLobby::MapUnit(n, user, lock);
691 
692  Text reply;
693 
694  ListIter<NetUnitEntry> map_iter = GetUnitMap();
695  while (++map_iter) {
696  NetUnitEntry* unit = map_iter.value();
697  reply += unit->GetDescription();
698  }
699 
700  ListIter<NetUser> u_iter = users;
701  while (++u_iter) {
702  NetUser* u = u_iter.value();
703  SendData(u, NET_LOBBY_UNIT_LIST, reply);
704  }
705 }
706 
707 void
708 NetLobbyServer::UnmapUnit(const char* user)
709 {
710  NetLobby::UnmapUnit(user);
711 
712  Text reply;
713 
714  ListIter<NetUnitEntry> map_iter = GetUnitMap();
715  while (++map_iter) {
716  NetUnitEntry* unit = map_iter.value();
717  reply += unit->GetDescription();
718  }
719 
720  ListIter<NetUser> u_iter = users;
721  while (++u_iter) {
722  NetUser* u = u_iter.value();
723  SendData(u, NET_LOBBY_UNIT_LIST, reply);
724  }
725 }
726 
727 void
729 {
730  Text content;
731 
732  ListIter<NetUnitEntry> map_iter = GetUnitMap();
733  while (++map_iter) {
734  NetUnitEntry* unit = map_iter.value();
735  content += unit->GetDescription();
736  }
737 
738  ListIter<NetUser> u_iter = users;
739  while (++u_iter) {
740  NetUser* u = u_iter.value();
741  SendData(u, NET_LOBBY_UNIT_LIST, content);
742  }
743 }
744 
745 // +-------------------------------------------------------------------+
746 
747 Text
749 {
750  Text s;
751 
752  if (!m || !user)
753  return s;
754 
755  NetUnitEntry* unit = 0;
756 
758  while (++u_iter && !unit) {
759  NetUnitEntry* u = u_iter.value();
760  if (u->GetUserName() == user->Name())
761  unit = u;
762  }
763 
764  if (unit)
765  s = m->Serialize(unit->GetElemName(), unit->GetIndex());
766 
767  return s;
768 }
769 
770 Mission*
772 {
773  if (mission) {
774  Text content = Serialize(mission, GetLocalUser());
775  Campaign* c = Campaign::SelectCampaign("Multiplayer Missions");
776 
777  if (c) {
778  c->LoadNetMission(99999, content.data());
779  return c->GetMission(99999);
780  }
781  }
782 
783  return mission;
784 }
785 
786 // +-------------------------------------------------------------------+
787 
788 void
790 {
791  NetHost host;
792  const char* type = "Starshatter";
793  const char* password = "No";
794  char address[32];
795 
796  strcpy_s(address, "0");
797 
798  if (server_config) {
800  return;
801 
803  type = "Starshatter-LAN";
804  sprintf_s(address, "%d.%d.%d.%d",
805  host.Address().B1(),
806  host.Address().B2(),
807  host.Address().B3(),
808  host.Address().B4());
809  }
810  else {
811  type = "Starshatter";
812  sprintf_s(address, "0.0.0.0");
813  }
814 
815  if (server_config->GetGamePass().length() > 0)
816  password = "Yes";
817  }
818 
820  type,
821  address,
822  server_addr.Port(),
823  password);
824 }
825 
826 void
828 {
829 }
830 
831 // +-------------------------------------------------------------------+
832 
833 void
835 { }
836 
837 void
839 {
840  if (peer && peer->NetID()) {
841  char buffer[1024];
842  WORD gameport = 11101;
843 
844  if (server_config)
845  gameport = server_config->GetGamePort();
846 
847  sprintf_s(buffer, "info \"%s\" version \"%s\" mode %d users %d host %s port %d",
849  versionInfo,
850  GetStatus(),
851  NumUsers(),
852  HasHost() ? "true" : "false",
853  gameport);
854 
855  link->SendMessage(peer->NetID(), (BYTE) NET_LOBBY_SERVER_INFO, buffer, strlen(buffer), NetMsg::RELIABLE);
856  }
857 }
858 
859 void
861 {
862  if (peer && peer->NetID()) {
863  Text response;
864  ModConfig* config = ModConfig::GetInstance();
865  List<ModInfo>& mods = config->GetModInfoList();
866  ListIter<ModInfo> mod_iter = mods;
867 
868  char buffer[32];
869  sprintf_s(buffer, "num %d ", mods.size());
870  response += buffer;
871 
872  while (++mod_iter) {
873  ModInfo* info = mod_iter.value();
874 
875  response += "mod \"";
876  response += info->Name();
877  response += "\" url \"";
878  response += info->URL();
879  response += "\" ver \"";
880  response += info->Version();
881  response += "\" ";
882  }
883 
884  link->SendMessage(peer->NetID(), (BYTE) NET_LOBBY_SERVER_MODS, response, response.length(), NetMsg::RELIABLE);
885  }
886 }
887 
888 // +-------------------------------------------------------------------+
889 
890 void
892 {
893  List<NetLobbyParam> params;
894  ParseMsg(msg, params);
895 
896  Text name;
897  Text pass;
898  Text host;
899  Text gamepass;
900  Text signature;
901  Text squadron;
902  Text version;
903  int rank = 0;
904  int flight_time = 0;
905  int missions = 0;
906  int kills = 0;
907  int losses = 0;
908 
909  for (int i = 0; i < params.size(); i++) {
910  NetLobbyParam* p = params[i];
911 
912  int num = 0;
913  sscanf_s(p->value, "%d", &num);
914 
915  if (p->name == "name")
916  name = p->value;
917 
918  else if (p->name == "pass")
919  pass = p->value;
920 
921  else if (p->name == "gamepass")
922  gamepass = p->value;
923 
924  else if (p->name == "host")
925  host = p->value;
926 
927  else if (p->name == "sig")
928  signature = p->value;
929 
930  else if (p->name == "squad")
931  squadron = p->value;
932 
933  else if (p->name == "version")
934  version = p->value;
935 
936  else if (p->name == "rank")
937  rank = num;
938 
939  else if (p->name == "time")
940  flight_time = num;
941 
942  else if (p->name == "miss")
943  missions = num;
944 
945  else if (p->name == "kill")
946  kills = num;
947 
948  else if (p->name == "loss")
949  losses = num;
950  }
951 
952  params.destroy();
953 
954  // first check the game version:
955  if (version != versionInfo) {
956  Print("NetLobbyServer - user '%s' tried to login with invalid game version '%s'\n",
957  name.data(), version.data());
958 
959  return;
960  }
961 
962  // next check the game password:
963  if (server_config && server_config->GetGamePass().length() > 0) {
964  if (gamepass != server_config->GetGamePass()) {
965  Print("NetLobbyServer - user '%s' tried to login with invalid game password '%s'\n",
966  name.data(), gamepass.data());
967 
968  return;
969  }
970  }
971 
972  // now try to log the user in:
973  NetUser* pre_existing = FindUserByName(name);
974 
975  // is user already logged in?
976  if (pre_existing) {
977  if (pre_existing->Pass() == pass &&
978  pre_existing->GetAddress().IPAddr() == peer->Address().IPAddr()) {
979  }
980  }
981 
982  // otherwise, create a new user:
983  else {
984  NetUser* user = new(__FILE__,__LINE__) NetUser(name);
985  user->SetAddress(peer->Address());
986  user->SetNetID(peer->NetID());
987  user->SetPass(pass);
988  user->SetSignature(signature);
989  user->SetSquadron(squadron);
990  user->SetRank(rank);
991  user->SetFlightTime(flight_time);
992  user->SetMissions(missions);
993  user->SetKills(kills);
994  user->SetLosses(losses);
995 
996  if (host == "true" && !HasHost())
997  user->SetHost(true);
998 
999  AddUser(user);
1000  RequestAuth(user);
1001  SendMOTD(user);
1002  SendMods(user);
1003  }
1004 }
1005 
1006 void
1008 {
1009  NetUser* user = FindUserByNetID(peer->NetID());
1010 
1011  if (user) {
1012  if (user->IsHost())
1013  GameStop();
1014 
1015  DelUser(user);
1016  }
1017 }
1018 
1019 void
1021 {
1022  NetUser* user = FindUserByNetID(peer->NetID());
1023 
1024  if (user) {
1025  NetAuth::AuthUser(user, msg);
1026 
1027  if (!user->IsAuthOK()) {
1028  char buffer[256];
1029 
1030  sprintf_s(buffer, "id %d user \"SERVER\" msg \"**********\"", motd_index++);
1031  SendData(user, NET_LOBBY_CHAT, buffer);
1032 
1033  sprintf_s(buffer, "id %d user \"SERVER\" msg \"*** Your game configuration does not match the server.\"", motd_index++);
1034  SendData(user, NET_LOBBY_CHAT, buffer);
1035 
1036  if (server_mods.size() > 0) {
1037  sprintf_s(buffer, "id %d user \"SERVER\" msg \"*** Please check that you have the proper mods deployed in\"", motd_index++);
1038  SendData(user, NET_LOBBY_CHAT, buffer);
1039  sprintf_s(buffer, "id %d user \"SERVER\" msg \"*** the order shown above.\"", motd_index++);
1040  SendData(user, NET_LOBBY_CHAT, buffer);
1041  }
1042 
1043  else {
1044  sprintf_s(buffer, "id %d user \"SERVER\" msg \"*** Please verify that you have no mods deployed.\"", motd_index++);
1045  SendData(user, NET_LOBBY_CHAT, buffer);
1046  }
1047 
1048  sprintf_s(buffer, "id %d user \"SERVER\" msg \"*** You will not be permitted to join the game with an invalid\"", motd_index++);
1049  SendData(user, NET_LOBBY_CHAT, buffer);
1050 
1051  sprintf_s(buffer, "id %d user \"SERVER\" msg \"*** configuration. You may reconnect to this server after you\"", motd_index++);
1052  SendData(user, NET_LOBBY_CHAT, buffer);
1053 
1054  sprintf_s(buffer, "id %d user \"SERVER\" msg \"*** have corrected your mod configuration.\"", motd_index++);
1055  SendData(user, NET_LOBBY_CHAT, buffer);
1056 
1057  sprintf_s(buffer, "id %d user \"SERVER\" msg \"**********\"", motd_index++);
1058  SendData(user, NET_LOBBY_CHAT, buffer);
1059 
1060  sprintf_s(buffer, "id %d user \" \" msg \" \"", motd_index++);
1061  SendData(user, NET_LOBBY_CHAT, buffer);
1062  }
1063  }
1064 }
1065 
1066 void
1068 {
1069  List<NetLobbyParam> params;
1070  ParseMsg(msg, params);
1071 
1072  Text chat_msg;
1073 
1074  for (int i = 0; i < params.size(); i++) {
1075  NetLobbyParam* p = params[i];
1076 
1077  int num = 0;
1078  sscanf_s(p->value, "%d", &num);
1079 
1080  if (p->name == "msg") {
1081  chat_msg = p->value;
1082  }
1083  }
1084 
1085  params.destroy();
1086 
1087  NetUser* user = FindUserByNetID(peer->NetID());
1088 
1089  if (user) {
1090  // receive chat from client:
1091  if (chat_msg.length()) {
1092  AddChat(user, chat_msg);
1093  }
1094 
1095  // request for chat log:
1096  else {
1098  while (++iter) {
1099  NetChatEntry* entry = iter.value();
1100 
1101  char buffer[512];
1102  char msg_buf[256];
1103  char usr_buf[256];
1104 
1105  // safe quotes uses a static buffer,
1106  // so make sure to save copies of the
1107  // results when using more than one in
1108  // a function call...
1109 
1110  strcpy_s(msg_buf, SafeQuotes(entry->GetMessage()));
1111  strcpy_s(usr_buf, SafeQuotes(entry->GetUser()));
1112 
1113  sprintf_s(buffer, "id %d user \"%s\" msg \"%s\"",
1114  entry->GetID(), usr_buf, msg_buf);
1115 
1116  SendData(user, NET_LOBBY_CHAT, buffer);
1117  }
1118  }
1119  }
1120 }
1121 
1122 void
1124 {
1125  NetUser* user = FindUserByNetID(peer->NetID());
1126 
1127  if (user) {
1128  Text content;
1129 
1130  if (local_user)
1131  content += local_user->GetDescription();
1132 
1133  ListIter<NetUser> iter = users;
1134  while (++iter) {
1135  NetUser* u = iter.value();
1136  content += u->GetDescription();
1137  }
1138 
1139  SendData(user, NET_LOBBY_USER_LIST, content);
1140  }
1141 }
1142 
1143 void
1145 {
1146  NetUser* user = FindUserByNetID(peer->NetID());
1147 
1148  if (user && user->IsHost() && user->IsAuthOK()) {
1149  List<NetLobbyParam> params;
1150  ParseMsg(msg, params);
1151 
1152  if (params.size() > 0) {
1153  NetLobbyParam* p = params[0];
1154 
1155  if (p->name == "user") {
1156  Text user_name = p->value;
1157 
1158  NetUser* u = FindUserByName(user_name);
1159  if (u && !u->IsHost())
1160  BanUser(u);
1161  }
1162  }
1163 
1164  params.destroy();
1165  }
1166 }
1167 
1168 void
1170 {
1171  NetUser* user = FindUserByNetID(peer->NetID());
1172 
1173  if (user) {
1174  Text reply;
1175  char buffer[4096];
1176 
1178  while (++c_iter) {
1179  Campaign* c = c_iter.value();
1180 
1182  sprintf_s(buffer, "c_id 0x%08x c_name \"%s\" ",
1183  c->GetCampaignId(),
1184  SafeQuotes(c->Name()));
1185 
1186  reply += buffer;
1187  }
1188  }
1189 
1190  c_iter.reset();
1191 
1192  while (++c_iter) {
1193  Campaign* c = c_iter.value();
1194 
1196 
1197  ListIter<MissionInfo> m_iter = c->GetMissionList();
1198  while (++m_iter) {
1199  MissionInfo* m = m_iter.value();
1200 
1201  int mission_id = (c->GetCampaignId() << NET_CAMPAIGN_SHIFT) + m->id;
1202 
1203  sprintf_s(buffer, "m_id 0x%08x ", mission_id);
1204  reply += buffer;
1205 
1206  reply += "m_name \"";
1207  reply += SafeQuotes(m->name);
1208 
1209  // long version of safe quotes:
1210  int n = 0;
1211  const char* s = m->description.data();
1212 
1213  while (*s && n < 4090) {
1214  if (*s == '"') {
1215  buffer[n++] = '\'';
1216  s++;
1217  }
1218  else if (*s == '\n') {
1219  buffer[n++] = '\\';
1220  buffer[n++] = 'n';
1221  s++;
1222  }
1223  else if (*s == '\t') {
1224  buffer[n++] = '\\';
1225  buffer[n++] = 't';
1226  s++;
1227  }
1228  else {
1229  buffer[n++] = *s++;
1230  }
1231  }
1232 
1233  // don't forget the null terminator!
1234  buffer[n] = 0;
1235 
1236  reply += "\" m_desc \"";
1237  reply += buffer;
1238 
1239  reply += "\" ";
1240  }
1241  }
1242  }
1243 
1244  SendData(user, NET_LOBBY_MISSION_LIST, reply);
1245 
1246  sprintf_s(buffer, "m_id 0x%08x", selected_mission);
1247  SendData(user, NET_LOBBY_MISSION_SELECT, buffer);
1248  }
1249 }
1250 
1251 void
1253 {
1255  return;
1256 
1257  NetUser* user = FindUserByNetID(peer->NetID());
1258 
1259  if (user && user->IsHost() && user->IsAuthOK()) {
1260  List<NetLobbyParam> params;
1261  ParseMsg(msg, params);
1262 
1263  for (int i = 0; i < params.size(); i++) {
1264  NetLobbyParam* p = params[i];
1265 
1266  int num = 0;
1267  sscanf_s(p->value, "0x%x", &num);
1268 
1269  if (p->name == "m_id") {
1270  SelectMission(num);
1271  }
1272  }
1273 
1274  params.destroy();
1275  }
1276 }
1277 
1278 void
1280 {
1281  NetUser* user = FindUserByNetID(peer->NetID());
1282 
1283  if (user && mission && user->IsAuthOK()) {
1284  Text reply = Serialize(mission, user);
1285  SendData(user, NET_LOBBY_MISSION_DATA, reply);
1286 
1287  FILE* f = ::fopen("multi_mission_send.def", "w");
1288  if (f) {
1289  ::fwrite(reply.data(), reply.length(), 1, f);
1290  ::fclose(f);
1291  }
1292  }
1293 }
1294 
1295 void
1297 {
1298  NetUser* user = FindUserByNetID(peer->NetID());
1299 
1300  if (user && unit_map.size() && user->IsAuthOK()) {
1301  Text reply;
1302 
1304  while (++iter) {
1305  NetUnitEntry* unit = iter.value();
1306  reply += unit->GetDescription();
1307  }
1308 
1309  SendData(user, NET_LOBBY_UNIT_LIST, reply);
1310  }
1311 }
1312 
1313 void
1315 {
1316  NetUser* user = FindUserByNetID(peer->NetID());
1317 
1318  if (user && unit_map.size() && user->IsAuthOK()) {
1319  List<NetLobbyParam> params;
1320  ParseMsg(msg, params);
1321 
1322  int id = 0;
1323  bool lock = false;
1324  Text user_name;
1325 
1326  for (int i = 0; i < params.size(); i++) {
1327  NetLobbyParam* p = params[i];
1328 
1329  if (p->name == "id") {
1330  sscanf_s(p->value, "%d", &id);
1331  }
1332 
1333  else if (p->name == "user") {
1334  user_name = p->value;
1335  }
1336 
1337  else if (p->name == "lock") {
1338  lock = (p->value == "true") ? true : false;
1339  }
1340  }
1341 
1342  params.destroy();
1343 
1344  MapUnit(id, user_name, lock);
1345  }
1346 }
1347 
1348 void
1350 {
1351  GameStart();
1352 }
1353 
1354 void
1356 {
1357  NetUser* user = FindUserByNetID(peer->NetID());
1358 
1359  if (user && user->IsHost() && user->IsAuthOK())
1360  GameStop();
1361 }