EvEmu  0.8.4
11 September 2021
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
LSCService.cpp
Go to the documentation of this file.
1 /*
2  ------------------------------------------------------------------------------------
3  LICENSE:
4  ------------------------------------------------------------------------------------
5  This file is part of EVEmu: EVE Online Server Emulator
6  Copyright 2006 - 2021 The EVEmu Team
7  For the latest information visit https://evemu.dev
8  ------------------------------------------------------------------------------------
9  This program is free software; you can redistribute it and/or modify it under
10  the terms of the GNU Lesser General Public License as published by the Free Software
11  Foundation; either version 2 of the License, or (at your option) any later
12  version.
13 
14  This program is distributed in the hope that it will be useful, but WITHOUT
15  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16  FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
17 
18  You should have received a copy of the GNU Lesser General Public License along with
19  this program; if not, write to the Free Software Foundation, Inc., 59 Temple
20  Place - Suite 330, Boston, MA 02111-1307, USA, or go to
21  http://www.gnu.org/copyleft/lesser.txt.
22  ------------------------------------------------------------------------------------
23  Author: Zhur, Aknor Jaden
24  Rewrite: Allan (incomplete)
25 */
26 
27 #include <boost/algorithm/string.hpp>
28 
29 #include "eve-server.h"
30 
31 #include "PyServiceCD.h"
33 #include "admin/SlashService.h"
34 #include "chat/LSCService.h"
35 #include "fleet/FleetService.h"
36 
37 
55 // Set the base (minimum) and maximum numbers for any user-created chat channel.
56 const int32 LSCService::BASE_CHANNEL_ID = 2100000000; //trial accts are spam-restricted to 1m input buffer when channelID < 2100000000
57 const uint32 LSCService::MAX_CHANNEL_ID = 0xFFFFFFFF;
58 
60 
62 : PyService(mgr, "LSC"),
63  m_dispatch(new Dispatcher(this)),
64  m_commandDispatch(cd)
65 {
66  _SetCallDispatcher(m_dispatch);
67 
68  //make sure you edit the header file too
69  PyCallable_REG_CALL(LSCService, GetChannels);
70  PyCallable_REG_CALL(LSCService, GetRookieHelpChannel);
71  PyCallable_REG_CALL(LSCService, JoinChannels);
72  PyCallable_REG_CALL(LSCService, LeaveChannels);
73  PyCallable_REG_CALL(LSCService, LeaveChannel);
74  PyCallable_REG_CALL(LSCService, CreateChannel);
76  PyCallable_REG_CALL(LSCService, DestroyChannel);
77  PyCallable_REG_CALL(LSCService, GetMembers);
78  PyCallable_REG_CALL(LSCService, GetMember);
79  PyCallable_REG_CALL(LSCService, SendMessage);
81  PyCallable_REG_CALL(LSCService, AccessControl);
82 
83  PyCallable_REG_CALL(LSCService, GetMyMessages);
84  PyCallable_REG_CALL(LSCService, GetMessageDetails);
86  PyCallable_REG_CALL(LSCService, MarkMessagesRead);
87  PyCallable_REG_CALL(LSCService, DeleteMessages);
88 
89  // sm.RemoteSvc('LSC').VoiceStatus(eveChannelID, 2) gag
90  // sm.RemoteSvc('LSC').VoiceStatus(eveChannelID, 1) ungag
91  // sm.RemoteSvc('LSC').VoiceStatus(eveChannelName, 0) leave channel
92  m_db = new LSCDB();
93 
94  CreateStaticChannels();
95 
96  // make startup msg with # of static channels created
97 }
98 
99 
101  delete m_dispatch;
102  std::map<int32, LSCChannel* >::iterator cur = m_channels.begin();
103  for(; cur != m_channels.end(); cur++) {
104  SafeDelete(cur->second);
105  }
106  SafeDelete(m_db);
107 }
108 
110 {
111 
112 }
113 
114 /*
115 LSC__ERROR=1
116 LSC__WARNING=0
117 LSC__MESSAGE=0
118 LSC__INFO=0
119 LSC__CHANNELS=0
120 LSC__CALL_DUMP=0
121 LSC__RSP_DUMP=0
122 */
123 
124 // there is no reason to hit the db for everyfuckingthing in this class!!
125 
127 //
128 // Eve Chat calls
129 //
131 
132 const int cspa = 2950; // CONCORD Spam Prevention Act
133 
134 
135 PyResult LSCService::Handle_GetChannels(PyCallArgs &call)
136 {
137  ChannelInfo info;
138  info.lines = new PyList();
139 
140  uint32 regionID = call.client->GetRegionID(), constID = call.client->GetConstellationID(), systemID = call.client->GetSystemID();
141  uint32 corpID = call.client->GetCorporationID();
142 
143  std::map<int32, LSCChannel*>::iterator cur = m_channels.begin();
144  for (; cur != m_channels.end(); cur++) {
145  switch (cur->second->GetType()) {
146  case LSC::Type::corp: {
147  if (cur->first != corpID)
148  continue;
149  } break;
150  case LSC::Type::region:
154  case LSC::Type::fleet:
155  case LSC::Type::wing:
156  case LSC::Type::squad:
159  case LSC::Type::custom: {
160  continue;
161  } break;
162  }
163 
164  info.lines->AddItem(cur->second->EncodeStaticChannel(call.client->GetCharacterID()));
165  }
166 
167  if (is_log_enabled(LSC__RSP_DUMP))
168  info.Dump(LSC__RSP_DUMP);
169  return info.Encode();
170 }
171 
172 
173 PyResult LSCService::Handle_GetRookieHelpChannel(PyCallArgs &call) {
174  if (is_log_enabled(LSC__CALL_DUMP)) {
175  sLog.Warning("LSCService::Handle_GetRookieHelpChannel()", "size=%u", call.tuple->size());
176  call.Dump(LSC__CALL_DUMP);
177  }
178 
179  return PyStatic.NewOne();
180 }
181 
182 PyResult LSCService::Handle_CreateChannel(PyCallArgs& call)
183 {
184  if (is_log_enabled(LSC__CALL_DUMP)) {
185  sLog.Warning("LSCService::Handle_CreateChannel()", "size=%u", call.tuple->size());
186  call.Dump(LSC__CALL_DUMP);
187  }
188 
189  Call_SingleStringArg name;
190  if (!name.Decode(&call.tuple)) {
191  codelog(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
192  return nullptr;
193  }
194 
195  bool create = false, temporary = false, joinExisting = false, noCallThrottling = false, memberless = false;
196  if (call.byname.find("create") != call.byname.end())
197  create = call.byname.find("create")->second->AsBool()->value();
198  if (call.byname.find("temporary") != call.byname.end())
199  temporary = call.byname.find("temporary")->second->AsBool()->value();
200  if (call.byname.find("joinExisting") != call.byname.end())
201  joinExisting = call.byname.find("joinExisting")->second->AsBool()->value();
202  if (call.byname.find("noCallThrottling") != call.byname.end())
203  noCallThrottling = call.byname.find("noCallThrottling")->second->AsBool()->value();
204  if (call.byname.find("memberless") != call.byname.end())
205  memberless = (call.byname.find("memberless")->second->AsInt()->value() ? true : false);
206 
207  Client* pClient = call.client;
208  ChannelCreateReply reply;
209 
210  // create/get channel info
211  LSCChannel* channel(nullptr);
212  if (joinExisting) {
213  channel = GetChannelByName(name.arg);
214  } else if (create) {
215  // figure out how to determine owner of this channel.....corp, ally, char. for now, use charID
217  if (nextID != 0) {
218  std::string comStr = name.arg;
219  boost::algorithm::to_lower(comStr);
220  comStr.erase(std::remove(comStr.begin(), comStr.end(), ' '), comStr.end());
221  channel = CreateChannel(nextID, pClient->GetCharacterID(), name.arg.c_str(), "motd", nullptr, comStr.c_str(), LSC::Type::normal, cspa,\
222  nextID, nextID, memberless, false, temporary, false);
223  }
224  // save non-temp channel info for new channels
225  if ((channel) and (!temporary))
226  m_db->UpdateChannelInfo(channel);
227  } else {
228  // make error here for !join and !create (should never hit)
229  }
230 
231  // test for channel info
232  if (!channel) {
233  if (joinExisting) {
234  _log(LSC__ERROR, "%s: Channel not found - %s", pClient->GetName(), name.arg.c_str());
235  reply.ChannelInfo = new PyInt(LSC::Error::errNoSuchChannel);
236  } else if (create) {
237  _log(LSC__ERROR, "%s: Channel not created - %s", pClient->GetName(), name.arg.c_str());
238  reply.ChannelInfo = new PyInt(LSC::Error::errUnspecified);
239  } else {
240  // make error here for !join and !create (should never hit)
241  }
242  return reply.Encode();
243  }
244 
245  // join channel and send response
246  if (!channel->IsJoined(pClient->GetCharacterID())) {
247  if (channel->JoinChannel(pClient)) {
248  //if ((channel->GetChannelID() < 0) or (channel->GetChannelID() > maxStaticChannel)) {
249  reply.ChannelInfo = channel->EncodeDynamicChannel(pClient->GetCharacterID());
250  //} else {
251  // reply.ChannelInfo = channel->EncodeStaticChannel(pClient->GetCharacterID());
252  //}
253  reply.ChannelChars = channel->EncodeChannelChars();
254  reply.ChannelMods = channel->EncodeChannelMods();
255  } else {
256  reply.ChannelInfo = new PyInt(LSC::Error::errUnspecified);
257  }
258  if (!temporary)
259  m_db->UpdateSubscription(channel->GetChannelID(), pClient);
260 
261  return reply.Encode();
262  } else {
263  _log(LSC__ERROR, "%s: Already joined Channel %i \"%s\".", pClient->GetName(), channel->GetChannelID(), channel->GetDisplayName().c_str());
264  reply.ChannelInfo = new PyInt(LSC::Error::errUnspecified);
265  return reply.Encode();
266  }
267 
268  if (is_log_enabled(LSC__RSP_DUMP))
269  reply.Dump(LSC__RSP_DUMP);
270 
271  /*
272  * ret = sm.RemoteSvc('LSC').CreateChannel(displayName, joinExisting=False, memberless=0, create=True)
273  * if ret:
274  * info, acl, memberList = ret
275  * // on fail, ChannelInfo is pyint(lsc::type::error), others are null
276  * if info == CHTERR_ALREADYEXISTS:
277  * if info == CHTERR_NOSUCHCHANNEL:
278  */
279  return nullptr;
280 }
281 
282 PyResult LSCService::Handle_JoinChannels(PyCallArgs &call) {
283  if (is_log_enabled(LSC__CALL_DUMP)) {
284  sLog.Warning("LSCService::Handle_JoinChannels()", "size=%u", call.tuple->size());
285  call.Dump(LSC__CALL_DUMP);
286  }
287 
288  CallJoinChannels args;
289  if (!args.Decode(&call.tuple)) {
290  codelog(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
291  return nullptr;
292  }
293 
294  std::set<int32> toJoin;
295 
296  PyList::const_iterator cur = args.channels->begin();
297  for (; cur != args.channels->end(); cur++) {
298  if ((*cur)->IsInt()) {
299  toJoin.insert((*cur)->AsInt()->value());
300  } else if ((*cur)->IsTuple()) {
301  PyTuple* prt = (*cur)->AsTuple();
302  if (prt->items.size() != 1 or !prt->items[0]->IsTuple()) {
303  _log(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
304  continue;
305  }
306  prt = prt->items[0]->AsTuple();
307 
308  if (prt->items.size() != 2 or /* !prt->items[0]->IsString() or unnessecary */ !prt->items[1]->IsInt()) {
309  _log(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
310  continue;
311  }
312  toJoin.insert(prt->items[1]->AsInt()->value());
313  } else {
314  codelog(SERVICE__ERROR, "%s: Failed to decode argument ", call.client->GetName());
315  return nullptr;
316  }
317  }
318 
319  PyList *ml = new PyList();
320  LSCChannel* channel(nullptr);
321  uint32 charID = call.client->GetCharacterID();
322 
323  std::set<int32>::iterator curs = toJoin.begin();
324  for (; curs != toJoin.end(); curs++) {
325  int32 channelID = *curs;
326  if (channelID == 0)
327  continue;
328  if (sConfig.chat.EnforceRookieInHelp)
329  if ((channelID == 1) or (channelID == 2))
330  if (((args.role & Acct::Role::NEWBIE) != Acct::Role::NEWBIE) or ((args.role & Acct::Role::EPLAYER) != Acct::Role::EPLAYER))
331  continue;
332 
333  channel = GetChannelByID(channelID);
334  if (channel == nullptr)
335  continue;
336  ChannelJoinReply chjr;
337  chjr.ChannelID = channel->EncodeID();
338 
340  if (!channel->IsJoined(charID)) {
341  if (channel->JoinChannel(call.client)) {
342  ChannelJoinOK cjok;
343  //if ((channelID < 0) or (channelID > maxStaticChannel)) {
344  cjok.ChannelInfo = channel->EncodeDynamicChannel(charID);
345  //} else {
346  // cjok.ChannelInfo = channel->EncodeStaticChannel(charID);
347  //}
348  cjok.ChannelMods = channel->EncodeChannelMods();
349  cjok.ChannelChars = channel->EncodeChannelChars();
350  chjr.JoinRsp = cjok.Encode();
351  chjr.ok = 1;
352  } else {
353  ChannelJoinNotOK cjnok;
354  cjnok.Error = "LSCCannotJoin";
355  cjnok.rspDict = new PyDict(); // dunno what goes here...
356  chjr.JoinRsp = cjnok.Encode();
357  chjr.ok = 0;
358  }
359  } else {
360  ChannelJoinNotOK cjnok;
361  //{'FullPath': u'UI/Messages', 'messageID': 256739, 'label': u'LSCChannelIsJoinedBody'}(u'You are already in the channel ({displayName})', None, {u'{displayName}': {'conditionalValues': [], 'variableType': 10, 'propertyName': None, 'args': 0, 'kwargs': {}, 'variableName': 'displayName'}})
362  cjnok.Error = "LSCChannelIsJoined";
363  cjnok.rspDict = new PyDict(); // dunno what goes here...
364  chjr.JoinRsp = cjnok.Encode();
365  chjr.ok = 0;
366  }
367  ml->AddItem(chjr.Encode());
368  }
369 
370  if (is_log_enabled(LSC__RSP_DUMP))
371  ml->Dump(LSC__RSP_DUMP, " ");
372  return ml;
373 }
374 
375 PyResult LSCService::Handle_SendMessage(PyCallArgs& call)
376 {
377  if (is_log_enabled(LSC__CALL_DUMP)) {
378  sLog.Warning("LSCService::Handle_SendMessage()", "size=%u", call.tuple->size());
379  call.Dump(LSC__CALL_DUMP);
380  }
381 
382  int32 channel_id = 0;
383  std::string message = "";
384 
385  if ((call.tuple->IsTuple()) and (call.tuple->AsTuple()->items[0]->IsInt())) {
386  // Decode All User-created chat channel messages here:
387  if (!call.tuple->IsTuple()) {
388  _log(LSC__ERROR, "LSCService::Handle_SendMessage failed: tuple0 is the wrong type: %s", call.tuple->TypeString());
389  return PyStatic.NewNone();
390  }
391  PyTuple* tuple0 = call.tuple->AsTuple();
392 
393  if (tuple0->size() != 2) {
394  _log(LSC__ERROR, "LSCService::Handle_SendMessage failed: tuple0 is the wrong size: expected 2, but got %u", tuple0->size());
395  return PyStatic.NewNone();
396  }
397 
398  channel_id = call.tuple->AsTuple()->items[0]->AsInt()->value();
399  message = call.tuple->AsTuple()->items[1]->AsWString()->content();
400  _log(LSC__INFO, "Handle_SendMessage: call is player channel chat.");
401  } else {
402  Call_SendMessage args;
403  if (!args.Decode(&call.tuple)) {
404  codelog(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
405  return PyStatic.NewNone();
406  }
407  channel_id = args.channel.id;
408  message = args.message;
409  _log(LSC__INFO, "Handle_SendMessage: call is system channel chat.");
410  }
411 
412  std::map<int32, LSCChannel*>::iterator itr = m_channels.find(channel_id);
413  if (itr == m_channels.end()) {
414  _log(LSC__ERROR, "%s: Couldn't find channel %u", call.client->GetName(), channel_id);
415  return PyStatic.NewNone();
416  }
417 
418  if (message.at(0) == '.') {
419  _log(LSC__INFO, "SlashService->SlashCmd() called via LSC Service");
420  static_cast<SlashService *>(m_manager->LookupService("slash"))->SlashCommand(call.client, message);
421  itr->second->SendMessage(call.client, message.c_str(), true);
422  } else {
423  itr->second->SendMessage(call.client, message.c_str());
424  }
425 
426  return PyStatic.NewNone();
427 }
428 
429 PyResult LSCService::Handle_AccessControl(PyCallArgs& call)
430 {
431  if (is_log_enabled(LSC__CALL_DUMP)) {
432  sLog.Warning("LSCService::Handle_AccessControl()", "size=%u", call.tuple->size());
433  call.Dump(LSC__CALL_DUMP);
434  }
435  /* args passed as channelID, charID, mode
436  *
437  * 20:43:44 W LSCService::Handle_AccessControl(): size=3
438  * 20:43:44 [LSC_CDump] Call Arguments:
439  * 20:43:44 [LSC_CDump] Tuple: 3 elements
440  * 20:43:44 [LSC_CDump] [ 0] Integer field: 2100000000
441  * 20:43:44 [LSC_CDump] [ 1] (None)
442  * 20:43:44 [LSC_CDump] [ 2] Integer field: 1
443  * 20:43:44 [LSC_CDump] Call Named Arguments:
444  * 20:43:44 [LSC_CDump] Argument 'machoVersion':
445  * 20:43:44 [LSC_CDump] Integer field: 1
446  */
447 
448  // WARNING: This call contains manual packet decoding to handle Access Control since I didn't want to monkey around with the LSCPkts.xmlp.
449  // -- Aknor Jaden (2010-11-26)
450 
451  int32 channel_id = 0;
452 
453  //m_db->UpdateChannelInfo(channel);
454 
455  // BIG TODO: The whole reason why normal players cannot post chats in other channels has to do with the Access Mode
456  // in the channel settings dialog in the client. Now, I don't know why chatting in the Help/Rookie Help is not allowed
457  // for ANY normal players, however, at the very least, implementing the change in Access Mode to 3 = Allowed may fix
458  // the issue. The only thing to figure out is how to format a packet to be sent to the client(s) to inform of the change
459  // in access mode. Is this really needed though, since the owner will change the mode and the owner's client will know
460  // immediately, and anyone wanting to join will get that mode value when the JoinChannel has been called.
461 
462  // call.tuple->GetItem(0)->AsInt()->value() = channel ID
463  // call.tuple->GetItem(1)->IsNone() == true <---- change made to "" field
464  // call.tuple->GetItem(2)->AsInt()->value() =
465  // 0 = ??
466  // 1 = Moderated
467  // 2 = ??
468  // 3 = Allowed
469 
470  // call.tuple->GetItem(1)->IsInt() == true <---- character ID for character add to one of the lists specified by GetItem(2):
471  // call.tuple->GetItem(2)->AsInt()->value() =
472  // 3 = Add to Allowed List
473  // -2 = Add to Blocked List
474  // 7 = Add to Moderators List
475 
476  //channel->UpdateConfig();
477 
478  return PyStatic.NewOne();
479 }
480 
481 PyResult LSCService::Handle_Invite(PyCallArgs &call)
482 {
483  if (is_log_enabled(LSC__CALL_DUMP)) {
484  sLog.Warning("LSCService::Handle_Invite()", "size=%u", call.tuple->size());
485  call.Dump(LSC__CALL_DUMP);
486  }
487 
488  // WARNING: This call contains manual packet decoding to handle chat messages sent inside user-created
489  // chat channels since I didn't want to monkey around with the LSCPkts.xmlp.
490  // -- Aknor Jaden (2010-11-19)
491 
492  LSCChannel* channel(nullptr);
493 
494  uint32 channel_ID;
495  uint32 char_ID = call.client->GetCharacterID();
496  uint32 invited_char_ID;
497 
498  // Decode the call:
499  if (call.tuple->IsTuple()) {
500  if (call.tuple->GetItem(1)->IsInt()) {
501  channel_ID = call.tuple->GetItem(1)->AsInt()->value();
502  } else {
503  _log(LSC__ERROR, "%s: call.tuple->GetItem(1) is of the wrong type: '%s'. Expected PyInt type.", call.client->GetName(), call.tuple->TypeString());
504  return nullptr;
505  }
506 
507  if (call.tuple->GetItem(0)->IsInt()) {
508  invited_char_ID = call.tuple->GetItem(0)->AsInt()->value();
509  } else {
510  _log(LSC__ERROR, "%s: call.tuple->GetItem(0) is of the wrong type: '%s'. Expected PyInt type.", call.client->GetName(), call.tuple->TypeString());
511  return nullptr;
512  }
513  } else {
514  _log(LSC__ERROR, "%s: call.tuple is of the wrong type: '%s'. Expected PyTuple type.", call.client->GetName(), call.tuple->TypeString());
515  return nullptr;
516  }
517 
518  if (m_channels.find(channel_ID) != m_channels.end()) {
519  channel = m_channels[channel_ID];
520 
521  if (!channel->IsJoined(invited_char_ID)) {
522  // SOMEHOW SEND A JOIN COMMAND/REQUEST TO THE TARGET CLIENT FOR invited_char_ID
523  /* OnLSC_JoinChannel join;
524  * join.sender = channel->_MakeSenderInfo(call.client);
525  * join.member_count = 1;
526  * join.channelID = channel->EncodeID();
527  * PyTuple *answer = join.Encode();
528  * MulticastTarget mct;
529  * //LSCChannelChar *invitor;
530  * //LSCChannelChar *invitee;
531  * if (!channel->IsJoined(char_ID))
532  * {
533  * //invitor = new LSCChannelChar(channel,0,char_ID,call.client->GetCharName(),0,0,0,0);
534  * mct.characters.insert(char_ID);
535  }
536  //invitee = new LSCChannelChar(channel,0,invited_char_ID,entityList().FindCharacter(invited_char_ID)->GetCharName(),0,0,0,0);
537  mct.characters.insert(invited_char_ID);
538  entityList().Multicast("OnLSC", channel->GetTypeString(), &answer, mct);
539  //entityList().Unicast(invited_char_ID,"OnLSC",channel->GetTypeString(),&answer,false);
540  */
541 
542  // ********** TODO **********
543  // Figure out how to send the ChatInvite packet to the client running the character with id = 'invited_char_ID'
544  // in order for that character's client to then issue the JoinChannels call to the server with the chat channel
545  // ID equal to that of this channel, be it either a private convo (temporary==1) or an existing user-created chat.
546  // **************************
547 
548  //ChatInvite chatInvitePacket;
549  //chatInvitePacket.integer1 = 1;
550  //chatInvitePacket.integer2 = invited_char_ID;
551  //chatInvitePacket.boolean = true;
552  //chatInvitePacket.displayName = call.tuple->GetItem(2)->AsString()->content();
553  //chatInvitePacket.integer3 = 1;
554  //chatInvitePacket.integer4 = 0;
555  //chatInvitePacket.integer5 = 1;
556  //PyTuple *tuple = chatInvitePacket.Encode();
557  //entityList().Unicast(invited_char_ID, "", "", &tuple, false);
558  } else {
559  _log(LSC__ERROR, "%s: Character %u is already joined to channel %u.", call.client->GetName(), invited_char_ID, channel_ID);
560  return nullptr;
561  }
562  } else {
563  _log(LSC__ERROR, "%s: Cannot find channel %u.", call.client->GetName(), channel_ID);
564  return nullptr;
565  }
566 
567  return PyStatic.NewOne();
568 }
569 
570 PyResult LSCService::Handle_Configure(PyCallArgs& call)
571 {
572  if (is_log_enabled(LSC__CALL_DUMP)) {
573  sLog.Warning("LSCService::Handle_Configure()", "size=%u", call.tuple->size());
574  call.Dump(LSC__CALL_DUMP);
575  }
576  /*
577  * 20:43:44 W LSCService::Handle_Configure(): size=1
578  * 20:43:44 [LSC_CDump] Call Arguments:
579  * 20:43:44 [LSC_CDump] Tuple: 1 elements
580  * 20:43:44 [LSC_CDump] [ 0] Integer field: 2100000000
581  * 20:43:44 [LSC_CDump] Call Named Arguments:
582  * 20:43:44 [LSC_CDump] Argument 'machoVersion':
583  * 20:43:44 [LSC_CDump] Integer field: 1
584  * 20:43:44 [LSC_CDump] Argument 'motd':
585  * 20:43:44 [LSC_CDump] WString: 'test MOTD'
586  *
587  * 21:13:02 W LSCService::Handle_Configure(): size=1
588  * 21:13:02 [LSC_CDump] Call Arguments:
589  * 21:13:02 [LSC_CDump] Tuple: 1 elements
590  * 21:13:02 [LSC_CDump] [ 0] Integer field: 2100000000
591  * 21:13:02 [LSC_CDump] Call Named Arguments:
592  * 21:13:02 [LSC_CDump] Argument 'creator':
593  * 21:13:02 [LSC_CDump] Integer field: 140000130
594  * 21:13:02 [LSC_CDump] Argument 'machoVersion':
595  * 21:13:02 [LSC_CDump] Integer field: 1
596  *
597  */
598 
599  // WARNING: This call contains manual packet decoding to handle configuring parameters for
600  // user-created chat channels since I didn't want to monkey around with the LSCPkts.xmlp.
601  // -- Aknor Jaden (2010-11-26)
602 
603  LSCChannel* channel(nullptr);
604  int32 channel_id = 0;
605 
606  //ChannelInfo args;
607  //if (!args.Decode(&call.tuple) {
608  //codelog(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
609  // return nullptr;
610  //}
611 
612  // Get Tuple which contains channel number to modify:
613  if (call.tuple->AsTuple()->GetItem(0)->IsInt()) {
614  channel_id = call.tuple->AsTuple()->GetItem(0)->AsInt()->value();
615  } else {
616  _log(LSC__ERROR, "%s: Tuple contained wrong type: '%s'", call.client->GetName(), call.tuple->TypeString());
617  return nullptr;
618  }
619 
620  // Get count of parameters or just loop through the std::map until you've reached the end
621  if (call.byname.size() == 0) {
622  _log(LSC__ERROR, "%s: byname std::map contained zero elements, expected at least one.", call.client->GetName());
623  return nullptr;
624  }
625 
626  // Find channel in existing channels:
627  std::map<int32, LSCChannel*>::iterator res = m_channels.find(channel_id);
628  if (m_channels.end() == res) {
629  _log(LSC__ERROR, "%s: Handle_Configure Couldn't find channel %u", call.client->GetName(), channel_id);
630  return nullptr;
631  }
632 
633  channel = m_channels.find(channel_id)->second;
634  if (call.byname.find("displayName") != call.byname.end()) {
635  if (call.byname.find("displayName")->second->IsWString()) {
636  channel->SetDisplayName(call.byname.find("displayName")->second->AsWString()->content());
637  } else {
638  _log(LSC__ERROR, "%s: displayName contained wrong type: '%s'", call.client->GetName(), call.byname.find("displayName")->second->TypeString());
639  return nullptr;
640  }
641  }
642 
643  if (call.byname.find("memberless") != call.byname.end()) {
644  if (call.byname.find("memberless")->second->IsInt()) {
645  channel->SetMemberless(call.byname.find("memberless")->second->AsInt()->value() ? true : false);
646  } else {
647  _log(LSC__ERROR, "%s: memberless contained wrong type: '%s'", call.client->GetName(), call.byname.find("memberless")->second->TypeString());
648  return nullptr;
649  }
650  }
651 
652  if (call.byname.find("motd") != call.byname.end()) {
653  if (call.byname.find("motd")->second->IsWString()) {
654  channel->SetMOTD(call.byname.find("motd")->second->AsWString()->content());
655  } else {
656  _log(LSC__ERROR, "%s: motd contained wrong type: '%s'", call.client->GetName(), call.byname.find("motd")->second->TypeString());
657  return nullptr;
658  }
659  }
660 
661  if (call.byname.find("oldPassword") != call.byname.end()) {
662  if (call.byname.find("oldPassword")->second->IsWString()) {
663  if (channel->GetPassword() == call.byname.find("oldPassword")->second->AsWString()->content()) {
664  if (call.byname.find("newPassword") != call.byname.end()) {
665  if (call.byname.find("newPassword")->second->IsWString()) {
666  channel->SetPassword(call.byname.find("newPassword")->second->AsWString()->content());
667  } else {
668  _log(LSC__ERROR, "%s: newPassword contained wrong type: '%s'", call.client->GetName(), call.byname.find("newPassword")->second->TypeString());
669  return nullptr;
670  }
671  }
672  } else {
673  _log(LSC__ERROR, "%s: incorrect oldPassword supplied. Password NOT changed.", call.client->GetName());
674  return nullptr;
675  }
676  } else if (call.byname.find("oldPassword")->second->IsNone()) {
677  if (call.byname.find("newPassword") != call.byname.end()) {
678  if (call.byname.find("newPassword")->second->IsWString()) {
679  channel->SetPassword(call.byname.find("newPassword")->second->AsWString()->content());
680  } else {
681  _log(LSC__ERROR, "%s: newPassword contained wrong type: '%s'", call.client->GetName(), call.byname.find("newPassword")->second->TypeString());
682  return nullptr;
683  }
684  }
685  } else {
686  _log(LSC__ERROR, "%s: oldPassword is of an unexpected type: '%s'", call.client->GetName(), call.byname.find("newPassword")->second->TypeString());
687  return nullptr;
688  }
689  }
690 
691  m_db->UpdateChannelInfo(channel);
692 
693  channel->UpdateConfig();
694 
695  return PyStatic.NewNone();
696 }
697 
698 
699 PyResult LSCService::Handle_LeaveChannel(PyCallArgs &call) {
700  if (is_log_enabled(LSC__CALL_DUMP)) {
701  sLog.Warning("LSCService::Handle_LeaveChannel()", "size=%u", call.tuple->size());
702  call.Dump(LSC__CALL_DUMP);
703  }
704 
705  CallLeaveChannel arg;
706  if (!arg.Decode(&call.tuple)) {
707  codelog(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
708  return PyStatic.NewNone();
709  }
710 
711  uint32 toLeave = 0;
712 
713  if (arg.channel->IsInt()) {
714  toLeave = arg.channel->AsInt()->value();
715  } else if (arg.channel->IsTuple()) {
716  PyTuple* prt = arg.channel->AsTuple();
717 
718  if (prt->GetItem(0)->IsInt()) {
719  toLeave = prt->GetItem(0)->AsInt()->value();
720  } else if (prt->GetItem(0)->IsTuple()) {
721  prt = prt->GetItem(0)->AsTuple();
722 
723  if (prt->items.size() != 2 or !prt->GetItem(1)->IsInt()) {
724  _log(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
725  return PyStatic.NewNone();
726  }
727 
728  toLeave = prt->GetItem(1)->AsInt()->value();
729  } else {
730  _log(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
731  return PyStatic.NewNone();
732  }
733  } else {
734  _log(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
735  return PyStatic.NewNone();
736  }
737 
738  if (arg.unsubscribe)
739  m_db->DeleteSubscription(toLeave,call.client->GetCharacterID());
740 
741  std::map<int32, LSCChannel*>::iterator itr = m_channels.find(toLeave);
742  if (itr != m_channels.end()) {
743  itr->second->LeaveChannel(call.client);
744  if ((itr->second->GetMemberCount() < 1) and (itr->second->GetTemporary())) {
745  m_db->DeleteChannel(toLeave);
746  SafeDelete(itr->second);
747  m_channels.erase(itr);
748  }
749  }
750 
751  return PyStatic.NewNone();
752 }
753 
754 
755 PyResult LSCService::Handle_LeaveChannels(PyCallArgs &call) {
756  if (is_log_enabled(LSC__CALL_DUMP)) {
757  sLog.Warning("LSCService::Handle_LeaveChannels()", "size=%u", call.tuple->size());
758  call.Dump(LSC__CALL_DUMP);
759  }
760 
761  CallLeaveChannels args;
762 
763  if (!args.Decode(&call.tuple)) {
764  codelog(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
765  return PyStatic.NewNone();
766  }
767 
768  std::set<uint32> toLeave;
769  toLeave.clear();
770 
771  PyList::const_iterator cur = args.channels->begin();
772  for (; cur != args.channels->end(); cur++) {
773  if ((*cur)->IsInt()) {
774  toLeave.insert((*cur)->AsInt()->value());
775  } else if ((*cur)->IsTuple()) {
776  PyTuple* prt = (*cur)->AsTuple();
777 
778  if (prt->GetItem(0)->IsInt()) {
779  toLeave.insert(prt->GetItem(0)->AsInt()->value());
780  continue;
781  }
782 
783  if (!prt->GetItem(0)->IsTuple()) {
784  _log(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
785  continue;
786  }
787  prt = prt->GetItem(0)->AsTuple();
788 
789  if (prt->GetItem(0)->IsTuple())
790  prt = prt->GetItem(0)->AsTuple();
791 
792  if (prt->size() != 2 or !prt->GetItem(1)->IsInt()) {
793  _log(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
794  continue;
795  }
796 
797  toLeave.insert(prt->GetItem(1)->AsInt()->value());
798  } else {
799  _log(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
800  continue;
801  }
802  }
803 
804  std::set<uint32>::iterator itr = toLeave.begin();
805  std::map<int32, LSCChannel*>::iterator itr2;
806  for (; itr!=toLeave.end(); itr++) {
807  itr2 = m_channels.find(*itr);
808  if (itr2 != m_channels.end()) {
809  itr2->second->LeaveChannel(call.client);
810  if (args.unsubscribe)
812 
813  if ((itr2->second->GetMemberCount() < 1) and (itr2->second->GetTemporary())) {
814  m_db->DeleteChannel(*itr);
815  SafeDelete(itr2->second);
816  m_channels.erase(itr2);
817  }
818  }
819  }
820 
821  return PyStatic.NewNone();
822 }
823 
824 PyResult LSCService::Handle_DestroyChannel(PyCallArgs& call)
825 {
826  if (is_log_enabled(LSC__CALL_DUMP)) {
827  sLog.Warning("LSCService::Handle_DestroyChannel()", "size=%u", call.tuple->size());
828  call.Dump(LSC__CALL_DUMP);
829  }
830 
831  Call_SingleIntegerArg arg;
832  if (!arg.Decode(&call.tuple)) {
833  codelog(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
834  return PyStatic.NewNone();
835  }
836 
837  std::map<int32, LSCChannel*>::iterator itr = m_channels.find(arg.arg);
838  if (itr == m_channels.end()) {
839  _log(LSC__ERROR, "%s: Couldn't find channel %u", call.client->GetName(), arg.arg);
840  return PyStatic.NewNone();
841  }
842 
843  // ********** TODO **********
844  // Figure out how to validate whether this character (call.client->GetCharacterID()) is allowed
845  // to destroy this chat channel, and proceed if they are, otherwise, do not. And, is there an error
846  // packet sent back to the client?
847  // **************************
848 
849  // Now, remove the channel from the database:
850  m_db->DeleteChannel(itr->second->GetChannelID());
851 
852  // Finally, remove the channel from the server dynamic objects:
853  itr->second->Evacuate(call.client);
854  SafeDelete(itr->second);
855  m_channels.erase(itr);
856 
857  return PyStatic.NewNone();
858 }
859 
860 
861 PyResult LSCService::Handle_GetMembers(PyCallArgs &call) {
862  CallGetMembers arg;
863  if (!arg.Decode(&call.tuple)) {
864  codelog(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
865  return nullptr;
866  }
867 
868  uint32 channelID;
869  if (arg.channel->IsInt()) {
870  channelID = arg.channel->AsInt()->value();
871  } else if (arg.channel->IsTuple()) {
872  PyTuple* prt = arg.channel->AsTuple();
873 
874  if (prt->GetItem(0)->IsInt()) {
875  channelID = prt->GetItem(0)->AsInt()->value();
876  } else if (prt->GetItem(0)->IsTuple()) {
877  prt = prt->GetItem(0)->AsTuple();
878 
879  if (prt->items.size() != 2 or !prt->GetItem(1)->IsInt())
880  {
881  _log(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
882  return nullptr;
883  }
884 
885  channelID = prt->GetItem(1)->AsInt()->value();
886  } else {
887  _log(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
888  return nullptr;
889  }
890  } else {
891  _log(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
892  return nullptr;
893  }
894 
895  if (m_channels.find(channelID) != m_channels.end())
896  return m_channels[channelID]->EncodeChannelChars();
897 
898  return nullptr;
899 }
900 
901 
902 PyResult LSCService::Handle_GetMember(PyCallArgs &call) {
903  return nullptr;
904 }
905 
906 
908 {
911 }
912 
913 void LSCService::SystemUnload(uint32 systemID, uint32 constID, uint32 regionID)
914 {
915  std::map<int32, LSCChannel*>::iterator itr = m_channels.find(systemID);
916  if (itr != m_channels.end()) {
917  SafeDelete(itr->second);
918  m_channels.erase(itr);
919  }
921  // is this needed?
922 }
923 
924 LSCChannel* LSCService::CreateChannel(int32 channelID, uint32 ownerID, const char *name, std::string motd, const char *password, const char *compkey,
925  LSC::Type type/*LSC::Type::normal*/, uint32 cspa/*0*/, int32 groupMessageID/*0*/, int32 channelMessageID/*0*/, bool memberless/*false*/,
926  bool maillist/*false*/, bool temporary/*false*/, bool languageRestriction/*false*/) {
927  // test for invalid channelID (alliance not implemented yet)
928  if (channelID == 0)
929  return nullptr;
930 
931  LSCChannel* channel = new LSCChannel(this, channelID, type, ownerID, name, compkey, motd, memberless, password, maillist, cspa, temporary, languageRestriction, groupMessageID, channelMessageID);
932  return (m_channels[channelID] = channel);
933 }
934 
936 {
937  std::map<int32, LSCChannel*>::iterator itr = m_channels.find(channelID);
938  if (itr != m_channels.end())
939  return itr->second;
940  return nullptr;
941 }
942 
943 LSCChannel* LSCService::GetChannelByName(std::string channelName)
944 {
945  for (auto cur : m_channels)
946  if (cur.second->GetDisplayName() == channelName)
947  return cur.second;
948  return nullptr;
949 }
950 
952 {
953  if (channelID == 0)
954  return;
955  if (m_channels.find(channelID) != m_channels.end())
956  return;
957 
959  std::string name= "", motd = "";
960  int32 messageID = -1, grpMsgID = 0;
961  uint32 ownerID = channelID;
962 
964  if (IsRegionID(channelID)) {
965  type = LSC::Type::region;
966  name = "Region";
967  motd = m_db->GetRegionName(channelID);
968  grpMsgID = 1;
969  } else if (IsConstellationID(channelID)) {
971  name = "Constellation";
972  motd = m_db->GetConstellationName(channelID);
973  grpMsgID = 2;
974  } else if (IsKSpaceID(channelID)) {
976  name = "Local";
977  motd = m_db->GetSolarSystemName(channelID);
978  grpMsgID = 3;
979  } else if (IsWSpaceID(channelID)) {
980  type = LSC::Type::solarsystem;
981  name = "System";
982  motd = m_db->GetSolarSystemName(channelID);
983  grpMsgID = 3;
984  } else if (IsNPCCorp(channelID)) {
985  type = LSC::Type::corp;
986  name = "Corp";
987  motd = m_db->GetCorporationName(channelID);
988  grpMsgID = 263235;
989  } else if (IsPlayerCorp(channelID)) {
990  type = LSC::Type::corp;
991  name = "Corp";
992  motd = m_db->GetCorporationName(channelID);
993  grpMsgID = 263235;
994  messageID = 0;
995  } else if (IsAlliance(channelID)) {
996  type = LSC::Type::alliance;
997  name = "Alliance";
998  motd = m_db->GetAllianceName(channelID);
999  grpMsgID = 5;
1000  messageID = 0;
1001  } else if (IsFleetID(channelID)) {
1002  type = LSC::Type::fleet;
1003  name = sFltSvc.GetFleetName(channelID);
1004  motd = sFltSvc.GetFleetDescription(channelID);
1005  messageID = 0;
1006  ownerID = sFltSvc.GetFleetLeaderID(channelID);
1007  } else if (IsWingID(channelID)) {
1008  type = LSC::Type::wing;
1009  name = sFltSvc.GetWingName(channelID);
1010  motd = name;
1011  motd += "<br>";
1012  motd += sFltSvc.GetFleetDescription(channelID);
1013  messageID = 0;
1014  //ownerID = sFltSvc.GetWingLeaderID(channelID);
1015  ownerID = sFltSvc.GetFleetLeaderID(channelID);
1016  } else if (IsSquadID(channelID)) {
1017  type = LSC::Type::squad;
1018  name = sFltSvc.GetSquadName(channelID);
1019  motd = name;
1020  motd += "<br>";
1021  motd += sFltSvc.GetFleetDescription(channelID);
1022  messageID = 0;
1023  //ownerID = sFltSvc.GetSquadLeaderID(channelID);
1024  ownerID = sFltSvc.GetFleetLeaderID(channelID);
1025  } else {
1026  // not sure what to do here....should never hit
1027  }
1028  std::string comStr = motd;
1029  boost::algorithm::to_lower(comStr);
1030  comStr.erase(std::remove(comStr.begin(), comStr.end(), ' '), comStr.end());
1031  CreateChannel(channelID, ownerID, name.c_str(), motd, nullptr, comStr.c_str(), type, cspa, grpMsgID, messageID);
1032 }
1033 
1035  // hardcode creating server static channels during server startup
1036  // these are all set to memberless to avoid constant updates
1037  std::ostringstream str;
1038 
1039 // basic template
1040  //CreateChannel(channelID, ownerID, "name", "motd", "password" or nullptr, "*title*", LSC::Type::normal, cspa, 0, 0, true);
1041 
1042 //Help
1043 // Incursion Rookie Help MOTD
1044  str.str("");
1045  str << "<br><color=0xff007fff><b>Welcome to the EVEmu <u>EVE Online: Crucible</u> Emulator</b></color><br><br>";
1046  str << "<color=0xff00ff00><b>Topic:</b></color> ";
1047  str << "<color=0xffffffff>EVE-Online related rookie help.</color><br><br>";
1048  str << "<color=0xff00ff00><b>Rules:</b></color> ";
1049  str << "<color=0xffffffff>No WTB, WTS, WTT, PC, advertising, recruiting, scamming, offering private help in any form or begging in this channel.<br>";
1050  str << "No CAPS or text-decoration.</color><br><br>";
1051  str << "<color=0xff00ff00><b>Language:</b></color> ";
1052  str << "<color=0xffffffff>This channel is ENGLISH ONLY.</color><br><br>";
1053  str << "<color=0xff00ff00><b>How to contact a GM:</b> </color> ";
1054  str << "<color=0xffffffff>Right now, our petition service isnt operational, so to contact a GM, post on the forums.</color><br><br>";
1055  //str << "<color=0xffffffff>File a petition (F12 - Petitions - New Petition)</color><br><br>";
1056  str << "<color=0xff00ff00><b>ISK Advertising:</b></color> ";
1057  str << "<color=0xffff0000>Contrary to what they spam, EVEmu does not authorize any person or site to sell ISK for RL cash.</color><br><br>";
1058  str << "<color=0xff00ff00><b>Please Note:</b></color><br>";
1059  str << "<color=0xffffffff>There are no third party applications (.exe) that will magically give you any type of ship you wish or hack your wallet. Please report characters advertising these types of links IMMEDIATELY via petition and DO NOT download and try them. <br><br>";
1060  // str << "Sister of EVE storyline starts in <url=showinfo:5//30005001><u>Arnon</url></b></u> <b>with <url=showinfo:1378//3019356><u>Sister Alitura</url></b></u>. <br><br></color>";
1061  CreateChannel(1, 1, "Rookie Help", str.str().c_str(), nullptr, "help", LSC::Type::normal, cspa, 263238, -1, true);
1062 // Incursion Help MOTD
1063  str.str("");
1064  str << "<br><color=0xff007fff><b>Welcome to the EVEmu <u>EVE Online: Crucible</u> Emulator</color><br><br>";
1065  str << "<color=0xff00ff00><b>Topic:</b></color> ";
1066  str << "<color=0xffffffff>EVE-Online related help.</color><br><br>";
1067  str << "<color=0xff00ff00><b>Rules:</b></color> ";
1068  str << "<color=0xffffffff>No WTB, WTS, WTT, PC, advertising, recruiting, scamming, offering private help in any form or begging in this channel.<br>";
1069  str << "No CAPS or text-decoration.</color><br><br>";
1070  str << "<color=0xff00ff00><b>Language:</b></color> ";
1071  str << "<color=0xffffffff>This channel is ENGLISH ONLY.</color><br><br>";
1072  str << "<color=0xff00ff00><b>How to contact a GM:</b> </color> ";
1073  str << "<color=0xffffffff>Right now, our petition service isnt operational, so to contact a GM, post on the forums.</color><br><br>";
1074  //str << "<color=0xffffffff>File a petition (F12 - Petitions - New Petition)</color><br><br>";
1075  str << "<color=0xff00ff00><b>ISK Advertising:</b></color> ";
1076  str << "<color=0xffff0000>Contrary to what they spam, EVEmu does not authorize any person or site to sell ISK for RL cash.</color><br><br>";
1077  CreateChannel(2, 1, "Help", str.str().c_str(), nullptr, "help", LSC::Type::normal, cspa, 263238, -1/*263262*/, true);
1078 //Empires/Factions
1079  CreateChannel(10, 1, "Caldari", "Caldari Faction", nullptr, "caldari", LSC::Type::normal, cspa, 263329, -1/*263268*/, true);
1080  CreateChannel(11, 1, "Amarr", "Amarr Faction", nullptr, "amarr", LSC::Type::normal, cspa, 263329, -1/*263246*/, true);
1081  CreateChannel(12, 1, "Minmatar", "Minmatar Faction", nullptr, "minmatar", LSC::Type::normal, cspa, 263329, -1/*263281*/, true);
1082  CreateChannel(13, 1, "Gallente", "Gallente Faction", nullptr, "gallente", LSC::Type::normal, cspa, 263329, -1/*263271*/, true);
1083  CreateChannel(14, 1, "Jove", "Jove Faction", nullptr, "jove", LSC::Type::normal, cspa, 263329, -1/*263258*/, true);
1084 // Incursion recruitment MOTD...
1085  str.str("");
1086  str << "<br><color=0xffffffff>Welcome to the recruitment channel.<br><br>";
1087  str << "This channel is intended for those players looking to find a new corporation, as well as those looking to enlist new players.<br>";
1088  str << "Other activities, such as non-recruitment discussion and scamming, are not permitted in this channel.";
1089 //Corporate
1090  CreateChannel(20, 9, "Recruitment", str.str().c_str(), nullptr, "recruitment", LSC::Type::normal, cspa, 263235, -1/*263286*/, true);
1091  str.str("");
1092  str << "<br><color=0xffffffff>Welcome to this</color> <color=0xff00ffff>Corporate CEO</color><color=0xffffffff> channel.<br><br>";
1093  str << "This channel is intended for corp CEOs to discuss business as they see fit.</color>";
1094  CreateChannel(21, 9, "CEO", str.str().c_str(), nullptr, "ceo", LSC::Type::normal, cspa, 263235, -1/*263287*/, true);
1095 //Alliance
1096  /*
1097  str.str("");
1098  str << "<color=0xffffffff>Welcome to this</color> <color=0xff00ffff>Alliance</color><color=0xffffffff> channel. This channel is intended for corp CEOs to discuss business as they see fit.</color>";
1099  CreateChannel(31, 1, "Smacktalk", str.str().c_str(), nullptr, "smacktalk", LSC::Type::normal, cspa, 263330, -1, true);
1100  CreateChannel(32, 1, "Rumour Mill", str.str().c_str(), nullptr, "rumourmill", LSC::Type::normal, cspa, 263330, -1, true);
1101  CreateChannel(33, 1, "Freelancer", str.str().c_str(), nullptr, "freelancer", LSC::Type::normal, cspa, 263330, -1, true);
1102  */
1103 //Trade
1104  str.str("");
1105  str << "<br><color=0xffffffff>Welcome to this</color> <color=0xff00ffff>Trade</color><color=0xffffffff> channel.<br><br>";
1106  str << "This channel is intended for those players looking to trade the various items as referenced in the channel title.</color>";
1107  CreateChannel(40, 1, "Other", str.str().c_str(), nullptr, "other", LSC::Type::normal, cspa, 263240, -1/*263277*/, true);
1108  CreateChannel(41, 1, "Ships", str.str().c_str(), nullptr, "ships", LSC::Type::normal, cspa, 263240, -1/*263245*/, true);
1109  CreateChannel(42, 1, "Blueprints", str.str().c_str(), nullptr, "blueprints", LSC::Type::normal, cspa, 263240, -1/*263292*/, true);
1110  CreateChannel(43, 1, "Modules and Munitions", str.str().c_str(), nullptr, "modulesandmunitions", LSC::Type::normal, cspa, 263240, -1/*263254*/, true);
1111  CreateChannel(44, 1, "Minerals and Manufacturing", str.str().c_str(), nullptr, "mineralsandmanufacturing", LSC::Type::normal, cspa, 263240, -1/*263275*/, true);
1112 //Science and Industry
1113  str.str("");
1114  str << "<br><color=0xffffffff>Welcome to this</color> <color=0xff00ffff>Science and Industry</color><color=0xffffffff> channel.<br><br>";
1115  str << "This channel is intended for those players looking to discuss the various items as referenced in the channel title.</color>";
1116  CreateChannel(50, 1, "Boosters", str.str().c_str(), nullptr, "boosters", LSC::Type::normal, cspa, 263331, -1/*263365*/, true);
1117  CreateChannel(51, 1, "Invention", str.str().c_str(), nullptr, "invention", LSC::Type::normal, cspa, 263331, -1/*263366*/, true);
1118  CreateChannel(52, 1, "Manufacturing", str.str().c_str(), nullptr, "manufacturing", LSC::Type::normal, cspa, 263331, -1/*263367*/, true);
1119  CreateChannel(53, 1, "Mining", str.str().c_str(), nullptr, "mining", LSC::Type::normal, cspa, 263331, -1/*263368*/, true);
1120  CreateChannel(54, 1, "Planetary Interaction", str.str().c_str(), nullptr, "planetaryinteraction", LSC::Type::normal, cspa, 263331, -1/*263369*/, true);
1121  CreateChannel(55, 1, "Research", str.str().c_str(), nullptr, "research", LSC::Type::normal, cspa, 263331, -1/*263370*/, true);
1122 //Groups/Content
1123  str.str("");
1124  str << "<br><color=0xffffffff>Welcome to this</color> <color=0xff00ffff>Content</color><color=0xffffffff> channel.<br><br>";
1125  str << "This channel is intended for those players looking to discuss the various items as referenced in the channel title.</color>";
1126  CreateChannel(60, 1, "Incursions", str.str().c_str(), nullptr, "incursions", LSC::Type::normal, cspa, 263328, -1/*263289*/, true);
1127  CreateChannel(61, 1, "Ratting", str.str().c_str(), nullptr, "ratting", LSC::Type::normal, cspa, 263328, -1/*263338*/, true);
1128  CreateChannel(62, 1, "Scanning", str.str().c_str(), nullptr, "scanning", LSC::Type::normal, cspa, 263328, -1/*263339*/, true);
1129  CreateChannel(63, 1, "Wormholes", str.str().c_str(), nullptr, "wormholes", LSC::Type::normal, cspa, 263328, -1/*263340*/, true);
1130 //Misc
1131  str.str("");
1132  str << "<br><color=0xffffffff>Welcome to the <url=https://evemu.dev>Free Wrecks</url> channel.<br>";
1133  str << "Here you can offer your abandoned mission wrecks to any willing freelance salvager in New Eden.</color><br><br>";
1134  str << "<b><u><color=0xff00ffff>Salvagers</color></u><br><color=0xff00ff00>Alphas</color></b>";
1135  str << "<color=0xffffffff> - Basic salvage fits by race: </color><br>";
1136  str << "<url=fitting:16236:31083;2:25861;4:8135;1:31370;1:1319;2:4435;1:5973;1:24348;4::>Amarr</url><color=0xffffffff> - </color>";
1137  str << "<url=fitting:16238:25861;4:1319;2:31370;1:31083;2:4435;2:5973;1:24348;4::>Caldari</url><color=0xffffffff> - </color>";
1138  str << "<url=fitting:16240:31083;2:25861;4:8135;1:31370;1:1319;2:4435;1:5973;1:24348;4::>Gallente</url><color=0xffffffff> - </color>";
1139  str << "<url=fitting:16242:25861;4:1319;2:31370;1:31083;2:6001;1:4435;2:24348;4::>Minmatar</url><color=0xffffffff> </color><br><br>";
1140  /* this suggests t2 shit which isnt available yet
1141  str << "<b><color=0xff00ff00>Omegas</color></b><color=0xffffffff> - You should be able to use a </color><url=showinfo:2998>Noctis</url>";
1142  str << "<color=0xffffffff>, </color><url=showinfo:30836>Salvager II's</url><color=0xffffffff> &amp; </color><url=showinfo:4250>Tractor Beam II's</url><br>";
1143  */
1144  str << "<b><u><color=0xff00ffff>Mission Runners</color></b></u><br><color=0xffffffff>";
1145  str << "Please state where your bookmark will be traded, contracted or if you're hoping to fleet with the salvager looking for work. <br>";
1146  str << "If you are contracting or trading bookmarks dont forget to</color> <color=0xff007fff>Abandon all wrecks and containers</color><color=0xffffffff>.</color><br><br>";
1147  str << "<b><u><color=0xff00ff00>Useful Links.</color></u><br>";
1148  str << "<loc><url=http://evemaps.dotlan.net/>DOTLAN</url></loc></b><color=0xffffffff> - A database of everything you need to know about New Eden; maps, corporations, navigations and much more.</color><color=0xff0000ff>NOTE:</color><color=0xffffffff> While this site is specific for Tranquility, the maps and navigation are the same here on EVEmu.</color><br>";
1149  str << "<loc><url=http://o.smium.org>Osmium</url></loc><color=0xffffffff> - A site where pilots post their ship fittings to help players get the most out of their ship class.</color><br>";
1150  str << "<loc><url=http://eve-survival.org/wikka.php?wakka=MissionReports>EVE Survival</url></loc><color=0xffffffff> - A database of missions within New Eden. Here you can find information about gaining the upper hand on those sneaky NPCs and how to perfectly run the mission in question.</color><br>";
1151  str << "<loc><url=http://www.fuzzwork.co.uk/>Fuzz Work</url></loc><color=0xffffffff> - A brilliant site that has many awesome calculators for LP stores, Blueprints, Invention, Ore and much more!</color><br>";
1152  CreateChannel(100, 2, "Free Wrecks", str.str().c_str(), nullptr, "freewrecks", LSC::Type::normal, cspa, 0, 0, true); //256739 <-- this was messageID from error about "channel already joined"
1153  //CreateChannel(101, 1, "", "motd", nullptr, "*title*", LSC::Type::normal, cspa, 0, 0, true);
1154 
1155 //GM Command channel
1156  str.str("");
1157  str << "<br><color=0xffffffff>Welcome to the</color> <color=0xff00ffff>GM Command</color><color=0xffffffff> channel.<br><br>";
1158  str << "This channel is intended for using dot commands.</color>";
1159  CreateChannel(2900000000, 1, "Command", str.str().c_str(), nullptr, "command", LSC::Type::custom, cspa, 0, 0, true);
1160 }
1161 
1163 {
1164  std::map<int32, LSCChannel*>::iterator itr = m_channels.find(pClient->GetSystemID());
1165  if (itr != m_channels.end())
1166  itr->second->SendServerMOTD(pClient);
1167 }
1168 
1170 //
1171 // EveMail calls:
1172 //
1174 
1175 PyResult LSCService::Handle_GetMyMessages(PyCallArgs &call) {
1176  return(m_db->GetMailHeaders(call.client->GetCharacterID()));
1177 }
1178 
1179 
1180 PyResult LSCService::Handle_GetMessageDetails(PyCallArgs &call) {
1181  Call_TwoIntegerArgs args;
1182  if (!args.Decode(&call.tuple)) {
1183  codelog(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
1184  return nullptr;
1185  }
1186 
1187  //TODO: verify ability to read this message...
1188 
1189  return(m_db->GetMailDetails(args.arg2, args.arg1));
1190 }
1191 
1192 
1193 PyResult LSCService::Handle_Page(PyCallArgs &call) {
1194  Call_Page args;
1195  if (!args.Decode(&call.tuple)) {
1196  codelog(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
1197  return nullptr;
1198  }
1199 
1200  _log(SERVICE__MESSAGE, "%s: Received evemail msg with subject '%s': %s", call.client->GetName(), args.subject.c_str(), args.body.c_str());
1201 
1202  SendMail(call.client->GetCharacterID(), args.recipients, args.subject, args.body);
1203 
1204  return nullptr;
1205 }
1206 
1207 
1208 //stuck here to be close to related functionality
1209 void LSCService::SendMail(uint32 sender, const std::vector<int32> &recipients, const std::string &subject, const std::string &content) {
1210  NotifyOnMessage notify;
1211  std::set<uint32> successful_recipients;
1212 
1213  notify.subject = subject;
1214  notify.sentTime = Win32TimeNow();
1215  notify.senderID = sender;
1216 
1217  // there's attachmentID and messageID... does this means a single message can contain multiple attachments?
1218  // eg. text/plain and text/html? we should be watching for this at reading mails...
1219  // created should be creation time. But Win32TimeNow returns int64, and is stored as bigint(20),
1220  // so change in the db is needed
1221  std::vector<int32>::const_iterator cur, end;
1222  cur = recipients.begin();
1223  end = recipients.end();
1224 
1225  for(; cur != end; cur++) {
1226  uint32 messageID = m_db->StoreMail(sender, *cur, subject.c_str(), content.c_str(), notify.sentTime);
1227  if(messageID == 0) {
1228  _log(SERVICE__ERROR, "Failed to store message from %u for recipient %u", sender, *cur);
1229  continue;
1230  }
1231  //TODO: supposed to have a different messageID in each notify I suspect..
1232  notify.messageID = messageID;
1233 
1234  _log(SERVICE__MESSAGE, "Delivered message from %u to recipient %u", sender, *cur);
1235  //record this person in the 'delivered to' list:
1236  notify.recipients.push_back(*cur);
1237  successful_recipients.insert(*cur);
1238  }
1239 
1240  //now, send a notification to each successful recipient
1241  PyTuple *answer = notify.Encode();
1242  sEntityList.Multicast(successful_recipients, "OnMessage", "*multicastID", &answer, false);
1243 }
1244 
1245 
1246 //stuck here to be close to related functionality
1247 //theres a lot of duplicated crap in here...
1248 //this could be replaced by the SendNewEveMail if it weren't in the Client
1249 void Client::SelfEveMail(const char* subject, const char* fmt, ...)
1250 {
1251  va_list args;
1252  va_start(args, fmt);
1253 
1254  char* str = nullptr;
1255  vasprintf(&str, fmt, args);
1256  assert(str);
1257 
1258  va_end(args);
1259 
1261  SafeFree(str);
1262 }
1263 
1264 
1265 PyResult LSCService::Handle_MarkMessagesRead(PyCallArgs &call) {
1266  Call_SingleIntList args;
1267  if (!args.Decode(&call.tuple)) {
1268  codelog(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
1269  return nullptr;
1270  }
1271 
1272  std::vector<int32>::iterator cur, end;
1273  cur = args.ints.begin();
1274  end = args.ints.end();
1275  for(; cur != end; cur++) {
1276  m_db->MarkMessageRead(*cur);
1277  }
1278  return nullptr;
1279 }
1280 
1281 
1282 PyResult LSCService::Handle_DeleteMessages(PyCallArgs &call) {
1283  Call_DeleteMessages args;
1284  if (!args.Decode(&call.tuple)) {
1285  codelog(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
1286  return nullptr;
1287  }
1288 
1289  if(args.channelID != (int32)call.client->GetCharacterID()) {
1290  _log(SERVICE__ERROR, "%s (%d) tried to delete messages in channel %u. Denied.", call.client->GetName(), call.client->GetCharacterID(), args.channelID);
1291  return nullptr;
1292  }
1293 
1294  std::vector<int32>::iterator cur, end;
1295  cur = args.messages.begin();
1296  end = args.messages.end();
1297  for(; cur != end; cur++) {
1298  m_db->DeleteMessage(*cur, args.channelID);
1299  }
1300 
1301  return nullptr;
1302 }
1303 
1304 PyResult LSCService::ExecuteCommand(Client *from, const char *msg) {
1305  return(m_commandDispatch->Execute(from, msg));
1306 }
LSCChannel * GetChannelByID(int32 channelID)
Definition: LSCService.cpp:935
int32 GetNextAvailableChannelID()
Definition: LSCDB.cpp:58
#define sConfig
A macro for easier access to the singleton.
PyTuple * AsTuple()
Definition: PyRep.h:138
Dispatcher *const m_dispatch
std::string GetRegionName(uint32 id)
Definition: LSCDB.h:52
#define IsNPCCorp(itemID)
Definition: EVE_Defines.h:238
bool MarkMessageRead(uint32 messageID)
Definition: LSCDB.cpp:505
#define IsConstellationID(itemID)
Definition: EVE_Defines.h:276
Definition: EVE_LSC.h:55
uint32 GetSystemID() const
Definition: Client.h:152
#define _log(type, fmt,...)
Definition: logsys.h:124
PyRep * GetItem(size_t index) const
Returns Python object.
Definition: PyRep.h:602
int32 value() const
Definition: PyRep.h:247
Python's dictionary.
Definition: PyRep.h:719
void CreateStaticChannels()
std::map< std::string, PyRep * > byname
Definition: PyCallable.h:51
size_t size() const
Definition: PyRep.h:591
bool IsTuple() const
Definition: PyRep.h:108
PyService * LookupService(const std::string &name)
void DeleteChannel(int32 channelID)
Definition: LSCDB.cpp:130
void UpdateSubscription(int32 channelID, Client *pClient)
Definition: LSCDB.cpp:121
uint32 GetRegionID() const
Definition: Client.h:154
std::string GetSolarSystemName(uint32 id)
Definition: LSCDB.h:54
void SendMail(uint32 sender, uint32 recipient, const std::string &subject, const std::string &content)
Definition: LSCService.h:64
PyCallable_Make_InnerDispatcher(LSCService) LSCService
Definition: LSCService.cpp:59
void UpdateChannelInfo(LSCChannel *channel)
Definition: LSCDB.cpp:88
std::string GetConstellationName(uint32 id)
Definition: LSCDB.h:53
void DeleteSubscription(int32 channelID, uint32 charID)
Definition: LSCDB.cpp:136
int32 GetCharacterID() const
Definition: Client.h:113
int32 GetCorporationID() const
Definition: Client.h:123
PyResult Execute(Client *from, const char *msg)
#define sEntityList
Definition: EntityList.h:208
storage_type::const_iterator const_iterator
Definition: PyRep.h:644
uint32 StoreMail(uint32 senderID, uint32 recipID, const char *subject, const char *message, int64 sentTime)
Definition: LSCDB.cpp:399
Dispatcher *const m_dispatch
Definition: LSCService.h:71
PyRep * GetMailDetails(uint32 messageID, uint32 readerID)
Definition: LSCDB.cpp:462
std::string GetAllianceName(uint32 id)
Definition: LSCDB.h:56
Python tuple.
Definition: PyRep.h:567
const char * GetName() const
Definition: PyService.h:54
void Dump(FILE *into, const char *pfx) const
Dumps object to file.
Definition: PyRep.cpp:84
void SelfEveMail(const char *subject, const char *fmt,...)
int32 GetAllianceID() const
Definition: Client.h:125
void AddItem(PyRep *i)
Definition: PyRep.h:701
void SafeDelete(T *&p)
Deletes and nullifies a pointer.
Definition: SafeMem.h:83
signed __int32 int32
Definition: eve-compat.h:49
* args
int vasprintf(char **strp, const char *fmt, va_list ap)
Definition: eve-compat.cpp:70
#define is_log_enabled(type)
Definition: logsys.h:78
#define sFltSvc
Definition: FleetService.h:147
#define sLog
Evaluates to a NewLog instance.
Definition: LogNew.h:250
void SafeFree(T *&p)
Frees and nullifies an array pointer.
Definition: SafeMem.h:111
void CreateSystemChannel(int32 channelID)
Definition: LSCService.cpp:951
std::map< int32, LSCChannel * > m_channels
Definition: LSCService.h:77
#define codelog(type, fmt,...)
Definition: logsys.h:128
#define IsKSpaceID(itemID)
Definition: EVE_Defines.h:285
Python integer.
Definition: PyRep.h:231
void CharacterLogin(Client *pClient)
Definition: LSCService.cpp:907
PyServiceMgr & m_services
Definition: Client.h:341
std::string GetCorporationName(uint32 id)
Definition: LSCDB.h:55
PyServiceMgr *const m_manager
Definition: PyService.h:91
uint32 GetConstellationID() const
Definition: Client.h:153
#define PyStatic
Definition: PyRep.h:1209
const char * GetName() const
Definition: Client.h:94
#define IsPlayerCorp(itemID)
Definition: EVE_Defines.h:241
int64 Win32TimeNow()
Definition: utils_time.cpp:70
Definition: LSCDB.h:36
Client *const client
Definition: PyCallable.h:49
#define IsSquadID(itemID)
Definition: EVE_Defines.h:231
PyResult ExecuteCommand(Client *from, const char *msg)
#define PyCallable_REG_CALL(c, m)
Definition: PyServiceCD.h:78
Definition: Client.h:66
LSCService * lsc_service
Definition: PyServiceMgr.h:77
unsigned __int32 uint32
Definition: eve-compat.h:50
Type
Definition: EVE_LSC.h:71
void Init(CommandDispatcher *cd)
Definition: LSCService.cpp:109
#define IsWingID(itemID)
Definition: EVE_Defines.h:228
LSCChannel * CreateChannel(int32 channelID, uint32 ownerID, const char *name, std::string motd, const char *password, const char *compkey, LSC::Type type=LSC::Type::normal, uint32 cspa=0, int32 groupMessageID=0, int32 channelMessageID=0, bool memberless=false, bool maillist=false, bool temporary=false, bool languageRestriction=false)
Definition: LSCService.cpp:924
#define IsFleetID(itemID)
Definition: EVE_Defines.h:225
const int cspa
Definition: LSCService.cpp:132
void Dump(LogType type) const
Definition: PyCallable.cpp:81
static const int32 BASE_CHANNEL_ID
Definition: LSCService.h:48
void SendServerMOTD(Client *pClient)
bool IsInt() const
Definition: PyRep.h:100
#define IsAlliance(itemID)
Definition: EVE_Defines.h:244
storage_type items
Definition: PyRep.h:628
LSCChannel * GetChannelByName(std::string channelName)
Definition: LSCService.cpp:943
bool DeleteMessage(uint32 messageID, uint32 readerID)
Definition: LSCDB.cpp:522
void SystemUnload(uint32 systemID, uint32 constID, uint32 regionID)
Definition: LSCService.cpp:913
#define IsRegionID(itemID)
Definition: EVE_Defines.h:273
PyInt * AsInt()
Definition: PyRep.h:122
#define IsWSpaceID(itemID)
Definition: EVE_Defines.h:282
static const uint32 MAX_CHANNEL_ID
Definition: LSCService.h:49
const char * TypeString() const
Definition: PyRep.cpp:76
PyObject * GetMailHeaders(uint32 recID)
Definition: LSCDB.cpp:446
Python list.
Definition: PyRep.h:639
CommandDispatcher *const m_commandDispatch
Definition: LSCService.h:73
PyTuple * tuple
Definition: PyCallable.h:50
LSCDB * m_db
Definition: LSCService.h:75