EvEmu  0.8.4
11 September 2021
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
CorpRegistryBound.cpp
Go to the documentation of this file.
1 /* CorpRegistryBound.cpp
2  * bound object to access functions for specific corp
3  *
4  *
5  */
6 
7 #include <string>
8 
9 #include "EVE_Corp.h"
10 #include "EVE_Mail.h"
11 #include "CorpData.h"
12 #include "StaticDataMgr.h"
13 #include "account/AccountService.h"
14 #include "cache/ObjCacheService.h"
15 #include "chat/LSCService.h"
18 #include "station/StationDB.h"
19 #include "station/StationDataMgr.h"
20 #include "alliance/AllianceDB.h"
21 #include "alliance/AllianceBound.h"
22 
23 /*
24  * CORP__ERROR
25  * CORP__WARNING
26  * CORP__INFO
27  * CORP__MESSAGE
28  * CORP__TRACE
29  * CORP__CALL
30  * CORP__CALL_DUMP
31  * CORP__RSP_DUMP
32  * CORP__DB_ERROR
33  * CORP__DB_WARNING
34  * CORP__DB_INFO
35  * CORP__DB_MESSAGE
36  */
37 
38 CorpRegistryBound::CorpRegistryBound(PyServiceMgr *mgr, CorporationDB& db, uint32 corpID)
39 : PyBoundObject(mgr),
40  m_db(db),
41  m_dispatch(new Dispatcher(this))
42 {
44 
45  m_strBoundObjectName = "CorpRegistryBound";
46 
48  PyCallable_REG_CALL(CorpRegistryBound, GetCorporation);
49  PyCallable_REG_CALL(CorpRegistryBound, GetCorporations);
50  PyCallable_REG_CALL(CorpRegistryBound, GetInfoWindowDataForChar);
51  PyCallable_REG_CALL(CorpRegistryBound, GetLockedItemLocations);
52  PyCallable_REG_CALL(CorpRegistryBound, AddCorporation);
53  PyCallable_REG_CALL(CorpRegistryBound, GetSuggestedTickerNames);
56 
57  PyCallable_REG_CALL(CorpRegistryBound, CreateRecruitmentAd);
58  PyCallable_REG_CALL(CorpRegistryBound, UpdateRecruitmentAd);
59  PyCallable_REG_CALL(CorpRegistryBound, DeleteRecruitmentAd);
60  PyCallable_REG_CALL(CorpRegistryBound, GetRecruiters);
61  PyCallable_REG_CALL(CorpRegistryBound, GetRecruitmentAdsForCorporation);
62  PyCallable_REG_CALL(CorpRegistryBound, GetMyApplications);
63  PyCallable_REG_CALL(CorpRegistryBound, InsertApplication);
64  PyCallable_REG_CALL(CorpRegistryBound, GetApplications);
65  PyCallable_REG_CALL(CorpRegistryBound, UpdateApplicationOffer);
66  PyCallable_REG_CALL(CorpRegistryBound, DeleteApplication);
67  PyCallable_REG_CALL(CorpRegistryBound, UpdateDivisionNames);
68  PyCallable_REG_CALL(CorpRegistryBound, UpdateCorporation);
70  PyCallable_REG_CALL(CorpRegistryBound, SetAccountKey);
74 
75  PyCallable_REG_CALL(CorpRegistryBound, MoveCompanyShares);
76  PyCallable_REG_CALL(CorpRegistryBound, MovePrivateShares);
77  PyCallable_REG_CALL(CorpRegistryBound, GetSharesByShareholder);
78  PyCallable_REG_CALL(CorpRegistryBound, GetShareholders);
79  PyCallable_REG_CALL(CorpRegistryBound, PayoutDividend);
80 
82  PyCallable_REG_CALL(CorpRegistryBound, InsertVoteCase);
86  PyCallable_REG_CALL(CorpRegistryBound, GetVoteCasesByCorporation);
87  PyCallable_REG_CALL(CorpRegistryBound, GetVoteCaseOptions);
88  PyCallable_REG_CALL(CorpRegistryBound, GetSanctionedActionsByCorporation);
89 
92  PyCallable_REG_CALL(CorpRegistryBound, DeleteBulletin);
93 
100 
101  PyCallable_REG_CALL(CorpRegistryBound, GetRecentKillsAndLosses);
102  PyCallable_REG_CALL(CorpRegistryBound, GetRoleGroups);
104  PyCallable_REG_CALL(CorpRegistryBound, GetLocationalRoles);
105 
108  PyCallable_REG_CALL(CorpRegistryBound, UpdateTitles);
110  PyCallable_REG_CALL(CorpRegistryBound, ExecuteActions);
111 
112  PyCallable_REG_CALL(CorpRegistryBound, GetCorporateContacts);
113  PyCallable_REG_CALL(CorpRegistryBound, AddCorporateContact);
114  PyCallable_REG_CALL(CorpRegistryBound, EditContactsRelationshipID);
115  PyCallable_REG_CALL(CorpRegistryBound, RemoveCorporateContacts);
116  PyCallable_REG_CALL(CorpRegistryBound, EditCorporateContact);
117 
118  PyCallable_REG_CALL(CorpRegistryBound, CreateAlliance);
119  PyCallable_REG_CALL(CorpRegistryBound, ApplyToJoinAlliance);
120  PyCallable_REG_CALL(CorpRegistryBound, DeleteAllianceApplication);
121  PyCallable_REG_CALL(CorpRegistryBound, GetAllianceApplications);
122  PyCallable_REG_CALL(CorpRegistryBound, GetSuggestedAllianceShortNames);
123 
124  PyCallable_REG_CALL(CorpRegistryBound, GetMembersPaged);
125  PyCallable_REG_CALL(CorpRegistryBound, GetMembersByIds);
126  PyCallable_REG_CALL(CorpRegistryBound, GetMemberIDsWithMoreThanAvgShares);
127  PyCallable_REG_CALL(CorpRegistryBound, GetMemberIDsByQuery);
128  PyCallable_REG_CALL(CorpRegistryBound, GetMemberTrackingInfo);
129  PyCallable_REG_CALL(CorpRegistryBound, GetMemberTrackingInfoSimple);
130  PyCallable_REG_CALL(CorpRegistryBound, GetRentalDetailsPlayer);
131  PyCallable_REG_CALL(CorpRegistryBound, GetRentalDetailsCorp);
132 
133  PyCallable_REG_CALL(CorpRegistryBound, UpdateCorporationAbilities);
134  PyCallable_REG_CALL(CorpRegistryBound, UpdateStationManagementSettings);
135  PyCallable_REG_CALL(CorpRegistryBound, GetNumberOfPotentialCEOs);
136 
137  PyCallable_REG_CALL(CorpRegistryBound, CanLeaveCurrentCorporation);
138 
139  m_corpID = corpID;
140 }
141 
142 PyResult CorpRegistryBound::Handle_GetLocationalRoles(PyCallArgs &call)
143 { // not sure if this is used...
144  PyList* list = new PyList();
166 
167  return list;
168 }
169 
170 PyResult CorpRegistryBound::Handle_GetEveOwners(PyCallArgs &call) {
171  /* this is a method-chaining call.
172  * it comes with the bind request for a particular corp.
173  *
174  * the client wants a member list for given corp
175  */
176  return m_db.GetEveOwners(m_corpID);
177 }
178 
179 PyResult CorpRegistryBound::Handle_GetInfoWindowDataForChar( PyCallArgs& call )
180 {
181  // takes characterID
182  // returns corpID, allianceID, title
183  Call_SingleIntegerArg args;
184 
185  // if no characterID is specified, just return information for current character
186  if (args.Decode (call.tuple) == false)
188 
189  return CharacterDB::GetInfoWindowDataForChar (args.arg);
190 }
191 
192 PyResult CorpRegistryBound::Handle_GetCorporation(PyCallArgs &call) {
193  // called by member of this corp
194  return m_db.GetCorporation(m_corpID);
195 }
196 
197 PyResult CorpRegistryBound::Handle_GetRoles(PyCallArgs &call)
198 { // working
199  return m_db.GetCorpRoles();
200 }
201 
202 PyResult CorpRegistryBound::Handle_GetRoleGroups(PyCallArgs &call)
203 { // working
204  return m_db.GetCorpRoleGroups();
205 }
206 
207 PyResult CorpRegistryBound::Handle_GetTitles(PyCallArgs &call)
208 { // working
209  return m_db.GetTitles(m_corpID);
210 }
211 
212 PyResult CorpRegistryBound::Handle_GetBulletins(PyCallArgs &call)
213 { // working
214  return m_db.GetBulletins(m_corpID);
215 }
216 
217 PyResult CorpRegistryBound::Handle_GetCorporateContacts(PyCallArgs &call)
218 { // working
219  return m_db.GetContacts(m_corpID);
220 }
221 
222 PyResult CorpRegistryBound::Handle_GetApplications(PyCallArgs &call)
223 { // working
224  return m_db.GetApplications(m_corpID);
225 }
226 
227 PyResult CorpRegistryBound::Handle_GetRecruitmentAdsForCorporation(PyCallArgs &call)
228 { // recruitments = self.GetCorpRegistry().GetRecruitmentAdsForCorporation()
229  return m_db.GetAdRegistryData();
230 }
231 
232 PyResult CorpRegistryBound::Handle_GetMyApplications(PyCallArgs &call)
233 { // working
235 }
236 
237 PyResult CorpRegistryBound::Handle_GetMemberTrackingInfo(PyCallArgs &call)
238 { // working
240 }
241 
242 PyResult CorpRegistryBound::Handle_GetMemberTrackingInfoSimple(PyCallArgs &call)
243 { // working
245 }
246 
247 PyResult CorpRegistryBound::Handle_GetShareholders(PyCallArgs &call)
248 { // working
249  return m_db.GetShares(m_corpID);
250 }
251 
252 PyResult CorpRegistryBound::Handle_GetLabels(PyCallArgs &call)
253 { // working
254  return m_db.GetLabels(call.client->GetCorporationID());
255 }
256 
257 PyResult CorpRegistryBound::Handle_CanViewVotes(PyCallArgs &call)
258 { // working
259  return m_db.PyHasShares(call.client->GetCharacterID(), m_corpID);
260 }
261 
262 PyResult CorpRegistryBound::Handle_GetMemberIDsWithMoreThanAvgShares(PyCallArgs &call)
263 { // working
265 }
266 
267 PyResult CorpRegistryBound::Handle_GetRecruiters(PyCallArgs &call)
268 { // working
269  Call_TwoIntegerArgs args;
270  if (!args.Decode(&call.tuple)) {
271  codelog(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
272  return nullptr;
273  }
274 
275  return m_db.GetRecruiters(args.arg1, args.arg2);
276 }
277 
278 PyResult CorpRegistryBound::Handle_DeleteTitle(PyCallArgs &call)
279 { // working
280  Call_SingleIntegerArg arg;
281  if (!arg.Decode(&call.tuple)) {
282  codelog(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
283  return nullptr;
284  }
285 
286  m_db.DeleteTitle(call.client->GetCorporationID(), arg.arg);
287  return nullptr;
288 }
289 
290 PyResult CorpRegistryBound::Handle_DeleteRecruitmentAd(PyCallArgs &call)
291 { // working
292  Call_SingleIntegerArg arg;
293  if (!arg.Decode(&call.tuple)) {
294  codelog(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
295  return nullptr;
296  }
297 
298  m_db.DeleteAdvert(arg.arg);
299  return nullptr;
300 }
301 
302 PyResult CorpRegistryBound::Handle_GetSharesByShareholder(PyCallArgs &call)
303 { // working
304  Call_SingleBoolArg arg;
305  if (!arg.Decode(&call.tuple)) {
306  codelog(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
307  return nullptr;
308  }
309 
310  uint32 owner = (arg.arg ? call.client->GetCorporationID() : call.client->GetCharacterID());
311  return m_db.GetMyShares(owner);
312 }
313 
314 PyResult CorpRegistryBound::Handle_GetCorporations(PyCallArgs &call) {
315  // working
316  Call_SingleIntegerArg args;
317  if (!args.Decode(&call.tuple)) {
318  codelog(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
319  return nullptr;
320  }
321  return m_db.GetCorporations(args.arg);
322 }
323 
324 PyResult CorpRegistryBound::Handle_GetRecentKillsAndLosses(PyCallArgs &call)
325 { // working
326  Call_GetRecentKillsAndLosses args;
327  if (!args.Decode(&call.tuple)) {
328  codelog(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
329  return nullptr;
330  }
331 
332  return m_db.GetKillsAndLosses(m_corpID, args.number, args.offset);
333 }
334 
335 PyResult CorpRegistryBound::Handle_GetMember(PyCallArgs &call)
336 { // not working
337  _log(CORP__CALL, "CorpRegistryBound::Handle_GetMember()");
338  Call_SingleIntegerArg args;
339  if (!args.Decode(&call.tuple)) {
340  codelog(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
341  return nullptr;
342  }
343 
344  PyRep* rep = m_db.GetMember(args.arg);
345 
346  if (is_log_enabled(CORP__RSP_DUMP))
347  rep->Dump(CORP__RSP_DUMP, "");
348 
349  return rep;
350 }
351 
352 PyResult CorpRegistryBound::Handle_SetAccountKey(PyCallArgs &call)
353 { // working
354  Call_SingleIntegerArg args;
355  if (!args.Decode(&call.tuple)) {
356  codelog(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
357  return nullptr;
358  }
359 
360  call.client->GetChar()->SetAccountKey(args.arg);
361  // returns nodeID and timestamp
362  PyTuple* tuple = new PyTuple(2);
363  tuple->SetItem(0, new PyString(GetBindStr())); // node info here
364  tuple->SetItem(1, new PyLong(GetFileTimeNow()));
365  return tuple;
366 }
367 
368 PyResult CorpRegistryBound::Handle_GetSuggestedTickerNames(PyCallArgs &call)
369 {
370  Call_SingleWStringArg args;
371  if (!args.Decode(&call.tuple)) {
372  codelog(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
373  return nullptr;
374  }
375 
376  PyList* result = new PyList();
377  SuggestedTickerName sTN;
378  sTN.tName.clear();
379  uint32 cnLen = args.arg.length();
380  // Easiest ticker-generation method: get the capital letters.
381  for (uint32 i=0; i < cnLen; ++i)
382  if (args.arg[i] >= 'A' && args.arg[i] <= 'Z')
383  sTN.tName += args.arg[i];
384 
385  result->AddItem( sTN.Encode() );
386  return result;
387 }
388 
389 PyResult CorpRegistryBound::Handle_GetSuggestedAllianceShortNames(PyCallArgs &call)
390 {
391  Call_SingleWStringArg args;
392  if (!args.Decode(&call.tuple)) {
393  codelog(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
394  return nullptr;
395  }
396  PyList* result = new PyList();
397  SuggestedShortName sSN;
398  sSN.sName.clear();
399  uint32 cnLen = args.arg.length();
400  // Easiest ticker-generation method: get the capital letters.
401  for (uint32 i=0; i < cnLen; ++i)
402  if (args.arg[i] >= 'A' && args.arg[i] <= 'Z')
403  sSN.sName += args.arg[i];
404 
405  result->AddItem( sSN.Encode() );
406  return result;
407 }
408 
409 PyResult CorpRegistryBound::Handle_GetMembers(PyCallArgs &call)
410 { // working
411  // this just wants a member count and time (and headers)
412  uint16 rowCount = m_db.GetMemberCount(m_corpID);
413 
414  /* update....do we need to send header also??
415  *
416  [PyObjectData Name: util.SparseRowset]
417  [PyTuple 3 items]
418  [PyList 19 items]
419  [PyString "characterID"]
420  [PyString "corporationID"]
421  [PyString "divisionID"]
422  [PyString "squadronID"]
423  [PyString "title"]
424  [PyString "roles"]
425  [PyString "grantableRoles"]
426  [PyString "startDateTime"]
427  [PyString "baseID"]
428  [PyString "rolesAtHQ"]
429  [PyString "grantableRolesAtHQ"]
430  [PyString "rolesAtBase"]
431  [PyString "grantableRolesAtBase"]
432  [PyString "rolesAtOther"]
433  [PyString "grantableRolesAtOther"]
434  [PyString "titleMask"]
435  [PyString "accountKey"]
436  [PyString "rowDate"]
437  [PyString "blockRoles"]
438  [PySubStruct]
439  [PySubStream 51 bytes]
440  [PyTuple 3 items]
441  [PyString "N=700149:17018"]
442  [PyDict 1 kvp]
443  [PyString "realRowCount"]
444  [PyInt 3]
445  [PyIntegerVar 129515350203058462]
446  [PyInt 3]
447  */
448 
449  PyDict *dict = new PyDict();
450  dict->SetItemString("realRowCount", new PyInt(rowCount)); // this is current member count
451  PyTuple* boundObject = new PyTuple(3);
452  boundObject->SetItem(0, new PyString(GetBindStr())); // node info here
453  boundObject->SetItem(1, dict);
454  boundObject->SetItem(2, new PyLong(GetFileTimeNow()));
455 
456  GetMembersSparseRowset ret;
457  ret.boundObject = boundObject;
458  ret.realRowCount = rowCount;
459  return ret.Encode();
460 }
461 
462 PyResult CorpRegistryBound::Handle_UpdateDivisionNames(PyCallArgs &call)
463 { // working
464  Call_UpdateDivisionNames args;
465  if (!args.Decode(&call.tuple)) {
466  codelog(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
467  return PyStatic.NewNone();
468  }
469 
470  Notify_IntRaw notif;
471  notif.key = m_corpID;
472  notif.data = new PyDict();
473 
474  if (!m_db.UpdateDivisionNames(notif.key, args, notif.data)) {
475  codelog(SERVICE__ERROR, "%s: Failed to update division names for corp %u", call.client->GetName(), notif.key);
476  PyDecRef( notif.data );
477  return PyStatic.NewNone();
478  }
479 
480  // Only send notification if it is needed...
481  if (notif.data->items.size()) {
483  MulticastTarget mct;
484  mct.corporations.insert(notif.key);
485  PyTuple * answer = notif.Encode();
486  sEntityList.Multicast("OnCorporationChanged", "corpid", &answer, mct);
487  call.client->SendNotification("OnCorporationChanged", "clientID", &answer);
488  }
489 
490  // returns nodeID and timestamp
491  PyTuple* tuple = new PyTuple(2);
492  tuple->SetItem(0, new PyString(GetBindStr())); // node info here
493  tuple->SetItem(1, new PyLong(GetFileTimeNow()));
494  return tuple;
495 }
496 
497 PyResult CorpRegistryBound::Handle_GetMembersPaged(PyCallArgs &call) {
498  //return self.GetCorpRegistry().GetMembersPaged(page)
499 
500  Call_SingleIntegerArg arg;
501  if (!arg.Decode(&call.tuple)) {
502  codelog(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
503  return nullptr;
504  }
505 
506  DBQueryResult res;
507  m_db.GetMembersPaged(m_corpID, arg.arg, res);
508  //uint32 rowCount = (uint32)res.GetRowCount();
509 
510  PyList* list = new PyList();
511  DBResultRow row;
512  while (res.GetRow(row)) {
513  //SELECT characterID, corporationID, title, rolesAtAll, grantableRoles, startDateTime, rolesAtHQ, grantableRolesAtHQ, \
514  rolesAtBase, grantableRolesAtBase, rolesAtOther, grantableRolesAtOther, titleMask, corpAccountKey, baseID, blockRoles, name
515  PyDict* dict = new PyDict();
516  dict->SetItemString( "characterID", new PyInt(row.GetInt(0)));
517  dict->SetItemString( "corporationID", new PyInt(row.GetInt(1)));
518  dict->SetItemString( "divisionID", new PyInt(0));
519  dict->SetItemString( "squadronID", new PyInt(0));
520  dict->SetItemString( "title", new PyInt(row.GetInt(2)));
521  dict->SetItemString( "roles", new PyLong(row.GetInt64(3)));
522  dict->SetItemString( "grantableRoles", new PyInt(row.GetInt(4)));
523  dict->SetItemString( "startDateTime", new PyLong(row.GetInt64(5)));
524  dict->SetItemString( "rolesAtHQ", new PyLong(row.GetInt64(6)));
525  dict->SetItemString( "grantableRolesAtHQ", new PyLong(row.GetInt64(7)));
526  dict->SetItemString( "rolesAtBase", new PyLong(row.GetInt64(8)));
527  dict->SetItemString( "grantableRolesAtBase", new PyLong(row.GetInt64(9)));
528  dict->SetItemString( "rolesAtOther", new PyLong(row.GetInt64(10)));
529  dict->SetItemString( "grantableRolesAtOther", new PyLong(row.GetInt64(11)));
530  dict->SetItemString( "titleMask", new PyLong(row.GetInt64(12))); // titleID
531  dict->SetItemString( "accountKey", new PyInt(row.GetInt(13)));
532  dict->SetItemString( "rowDate", new PyLong(GetFileTimeNow())); //may not be right
533  dict->SetItemString( "baseID", new PyInt(row.GetInt(14)));
534  dict->SetItemString( "blockRoles", new PyBool(row.GetInt(15)));
535  dict->SetItemString( "ownerName", new PyString(row.GetText(16)));
536  list->AddItem(new PyObject("util.KeyVal", dict));
537  }
538 
539  if (is_log_enabled(CORP__RSP_DUMP))
540  list->Dump(CORP__RSP_DUMP, "");
541 
542  return list;
543 }
544 
545 PyResult CorpRegistryBound::Handle_GetMembersByIds(PyCallArgs &call) {
546  //return self.GetCorpRegistry().GetMembersByIds(memberIDs)
547  _log(CORP__CALL, "CorpRegistryBound::Handle_GetMembersByIds()");
548  call.Dump(CORP__CALL_DUMP);
549 
550  Call_GetMembersByID args;
551  if (!args.Decode(&call.tuple)) {
552  codelog(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
553  return nullptr;
554  }
555 
556  PyList* list = new PyList();
557  for (PyList::const_iterator itr = args.memberIDs->begin(); itr != args.memberIDs->end(); ++itr)
558  list->AddItem(new PyObject("util.KeyVal", m_db.GetMember(PyRep::IntegerValueU32(*itr))));
559 
560  if (is_log_enabled(CORP__RSP_DUMP))
561  list->Dump(CORP__RSP_DUMP, "");
562 
563  return list;
564 }
565 
566 PyResult CorpRegistryBound::Handle_AddCorporation(PyCallArgs &call) {
567  Client* pClient(call.client);
568  Call_AddCorporation args;
569  if (!args.Decode(&call.tuple)) {
570  codelog(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
571  return nullptr;
572  }
573 
574  // verify they're not using bad words in their corp name
575  for (const auto cur : badWords)
576  if (EvE::icontains(args.corpName, cur))
577  throw CustomError ("Corp Name contains banned words");
578 
579  // this hits db directly, so test for possible sql injection code
580  for (const auto cur : badCharsSearch)
581  if (EvE::icontains(args.corpName, cur))
582  throw CustomError ("Corp Name contains invalid characters");
583 
584 
585  // this hits db directly, so test for possible sql injection code
586  for (const auto cur : badCharsSearch)
587  if (EvE::icontains(args.corpTicker, cur))
588  throw CustomError ("Corp Ticker contains invalid characters");
589 
590  // verify ticker is available
591  if (m_db.IsTickerTaken(args.corpTicker))
592  throw UserError ("CorpTickerNameInvalidTaken");
593 
594  double corp_cost = sConfig.rates.corpCost;
595  if (pClient->GetBalance(Account::CreditType::ISK) < corp_cost) {
596  _log(SERVICE__ERROR, "%s: Cannot afford corporation startup costs!", pClient->GetName());
597  // send error to client here?
598  return nullptr;
599  }
600 
601  //adding a corporation will affect eveStaticOwners, so we gotta invalidate the cache...
602  // call to db.AddCorporation() will update eveStaticOwners with new corp
603  PyString* cache_name = new PyString( "config.StaticOwners" );
604  m_manager->cache_service->InvalidateCache( cache_name );
605  PySafeDecRef( cache_name );
606 
607  // Register new corp
608  uint32 corpID(0);
609  if (!m_db.AddCorporation(args, pClient, corpID)) {
610  codelog(SERVICE__ERROR, "New corporation creation failed.");
611  return nullptr;
612  }
613 
614  // make sure AI is set correctly in db. sometimes it's not (cause i forget)
615  if (!IsPlayerCorp(corpID)) {
616  // not sure what to do here yet....delete everything, make sure db autoincrement is set right then reapply
617  _log(CORP__ERROR, "Auto Increment improperly set in DB.");
618  pClient->SendErrorMsg("Server Error when creating corp. CorpID invalid.");
619  return nullptr;
620  }
621 
622  // create default role title data
624 
625  //take the money, send wallet blink event record the transaction in their journal.
626  std::string reason = "DESC: Creating new corporation: ";
627  reason += args.corpName;
628  reason += " (";
629  reason += args.corpTicker;
630  reason += ")";
632  pClient->GetCharacterID(),
633  m_db.GetStationOwner(pClient->GetStationID()), // station owner files paperwork, this is fee for that
634  corp_cost,
635  reason.c_str(),
637  pClient->GetStationID(),
639 
640  // add corp event for creating new corp
641  m_db.AddItemEvent(corpID, pClient->GetCharacterID(), Corp::EventType::CreatedCorporation);
642 
643  // create corp channel
645 
646  CorpData data = CorpData();
647  data.name = args.corpName;
648  data.ticker = args.corpTicker;
649  data.taxRate = args.taxRate;
650  data.baseID = pClient->GetLocationID();
651  data.corpHQ = pClient->GetLocationID();
652  data.corporationID = corpID;
663  // update corp data and refresh session data.
664  pClient->GetChar()->JoinCorporation(data);
665 
666  // Here we send a notification about creating a new corporation...
667  OnCorporationChanged cc;
668  cc.corpID = corpID;
670  codelog(SERVICE__ERROR, "Failed to create OnCorpChanged notification stream.");
671  // This is a big problem, because this way we won't be able to see the difference...
672  pClient->SendErrorMsg("Unable to notify about corp creation.");
673  return nullptr;
674  }
675  PyTuple* a1 = cc.Encode();
676  // send single to client
677  pClient->SendNotification("OnCorporationChanged", "clientID", &a1);
678  // send multi to station guests
679  PyIncRef(a1);
680  sEntityList.Multicast("OnCorporationChanged", "stationid", &a1, NOTIF_DEST__LOCATION, pClient->GetLocationID());
681 
682  return m_db.GetCorporations(corpID);
683 }
684 
685 PyResult CorpRegistryBound::Handle_UpdateTitle(PyCallArgs &call) {
686  // self.GetCorpRegistry().UpdateTitle(titleID, titleName, roles, grantableRoles, rolesAtHQ, grantableRolesAtHQ, rolesAtBase, grantableRolesAtBase, rolesAtOther, grantableRolesAtOther)
687  _log(CORP__CALL, "CorpRegistryBound::Handle_UpdateTitle()");
688  //call.Dump(CORP__CALL_DUMP);
689 
690  Call_UpdateTitleData args;
691  if (!args.Decode(&call.tuple)) {
692  codelog(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
693  return nullptr;
694  }
695 
696  PyDict* updates = new PyDict();
697  if (m_db.UpdateTitle(m_corpID, args, updates)) {
699  OnTitleChanged change;
700  change.corpID = m_corpID;
701  change.titleID = args.titleID;
702  change.changes = updates;
703  PyTuple* notif = change.Encode();
704  MulticastTarget mct;
705  mct.corporations.insert(m_corpID);
706  sEntityList.Multicast("OnTitleChanged", "corpid", &notif, mct);
707  }
708 
709  //OnTitleChanged
710  return nullptr;
711 }
712 
713 PyResult CorpRegistryBound::Handle_UpdateTitles(PyCallArgs &call) {
714  // self.GetCorpRegistry().UpdateTitles(titles)
715  _log(CORP__CALL, "CorpRegistryBound::Handle_UpdateTitles()");
716  //call.Dump(CORP__CALL_DUMP);
717  if (!call.tuple->GetItem(0)->IsObject()) {
718  codelog(CORP__ERROR, "Tuple Item is wrong type: %s. Expected PyObject.", call.tuple->GetItem(0)->TypeString());
719  return nullptr;
720  }
721  Call_UpdateTitle arg;
722  if (!arg.Decode(&call.tuple)) {
723  codelog(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
724  return nullptr;
725  }
726 
727  if (!arg.object->arguments()->IsDict()) {
728  codelog(CORP__ERROR, "Object Argument is wrong type: %s. Expected PyDict.", arg.object->arguments()->TypeString());
729  return nullptr;
730  }
731 
732  PyDict* dict = arg.object->arguments()->AsDict();
733  //dict->Dump(CORP__TRACE, " ");
734  PyRep* rep = dict->GetItemString("lines");
735  if (!rep->IsList()) {
736  codelog(CORP__ERROR, "'lines' item is not PyList: %s", rep->TypeString());
737  return nullptr;
738  }
739 
740  Call_UpdateTitleData args;
741  PyList* list = rep->AsList();
742  for (PyList::const_iterator itr = list->begin(); itr != list->end(); ++itr) {
743  if (!(*itr)->IsList()) {
744  codelog(CORP__ERROR, "itr item is not PyList: %s", (*itr)->TypeString());
745  continue;
746  }
747  PyDict* updates = new PyDict();
748  PyList* list2 = (*itr)->AsList();
749  args.titleID = list2->GetItem(0)->AsInt()->value();
750  args.titleName = PyRep::StringContent(list2->GetItem(1));
751  args.roles = PyRep::IntegerValue(list2->GetItem(2));
752  args.grantableRoles = PyRep::IntegerValue(list2->GetItem(3));
753  args.rolesAtHQ = PyRep::IntegerValue(list2->GetItem(4));
754  args.grantableRolesAtHQ = PyRep::IntegerValue(list2->GetItem(5));
755  args.rolesAtBase = PyRep::IntegerValue(list2->GetItem(6));
756  args.grantableRolesAtBase = PyRep::IntegerValue(list2->GetItem(7));
757  args.rolesAtOther = PyRep::IntegerValue(list2->GetItem(8));
758  args.grantableRolesAtOther = PyRep::IntegerValue(list2->GetItem(9));
759  if (m_db.UpdateTitle(m_corpID, args, updates)) {
761  OnTitleChanged change;
762  change.corpID = m_corpID;
763  change.titleID = args.titleID;
764  change.changes = updates;
765  PyTuple* notif = change.Encode();
766  MulticastTarget mct;
767  mct.corporations.insert(m_corpID);
768  sEntityList.Multicast("OnTitleChanged", "corpid", &notif, mct);
769  }
770  }
771 
772  return nullptr;
773 }
774 
775 PyResult CorpRegistryBound::Handle_UpdateCorporation(PyCallArgs &call) {
776  _log(CORP__CALL, "CorpRegistryBound::Handle_UpdateCorporation() size=%u", call.tuple->size() );
777  call.Dump(CORP__CALL_DUMP);
778 
779  Call_UpdateCorporation args;
780  if (!args.Decode(&call.tuple)) {
781  codelog(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
782  return nullptr;
783  }
784 
785  Notify_IntRaw notif;
786  notif.key = m_corpID;
787  notif.data = new PyDict();
788 
789  if (!m_db.UpdateCorporation(notif.key, args, notif.data)) {
790  codelog(SERVICE__ERROR, "%s: Failed to update corporation data for corp %u", call.client->GetName(), notif.key);
791  PyDecRef( notif.data );
792  return PyStatic.NewNone();
793  }
794 
795  // Only send notification if it is needed...
796  if (notif.data->items.size()) {
798  MulticastTarget mct;
799  mct.corporations.insert(notif.key);
800  PyTuple * answer = notif.Encode();
801  sEntityList.Multicast("OnCorporationChanged", "corpid", &answer, mct);
802  call.client->SendNotification("OnCorporationChanged", "clientID", &answer);
803  }
804 
805  return PyStatic.NewNone();
806 }
807 
808 PyResult CorpRegistryBound::Handle_UpdateLogo(PyCallArgs &call)
809 {
810  Call_UpdateLogo args;
811  if (!args.Decode(&call.tuple)) {
812  codelog(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
813  return nullptr;
814  }
815 
816  Notify_IntRaw notif;
817  notif.key = m_corpID;
818 
819  // Check if we have enough money
820  double logo_change = 100;
821  if (AccountDB::GetCorpBalance(notif.key, Account::KeyType::Cash) < logo_change) {
822  _log( SERVICE__ERROR, "%s: Cannot afford corporation logo change costs", call.client->GetName());
823  call.client->SendErrorMsg("Your corporation doesn't have enough money (%u ISK) to change it's logo.", logo_change);
824  return nullptr;
825  }
826 
827  notif.data = new PyDict();
828  if (!m_db.UpdateLogo(notif.key, args, notif.data)) {
829  codelog( SERVICE__ERROR, "Corporation logo change failed..." );
830  PyDecRef( notif.data );
831  return nullptr;
832  }
833 
834  std::string reason = "Change Corporation Logo.";
835  // move cash and record the transaction.
837  call.client->GetCharacterID(),
839  logo_change,
840  reason,
842  Account::KeyType::Cash); // main wallet
843 
844  // Send notification to those in the station
846  MulticastTarget mct;
847  mct.locations.insert(call.client->GetLocationID());
848  PyTuple *answer = notif.Encode();
849  sEntityList.Multicast("OnCorporationChanged", "corpid", &answer, mct);
850 
851  return m_db.GetCorporation(notif.key);
852 }
853 
854 PyResult CorpRegistryBound::Handle_AddBulletin(PyCallArgs &call) {
855  // self.GetCorpRegistry().AddBulletin(title, body)
856  // self.GetCorpRegistry().AddBulletin(title, body, bulletinID=bulletinID, editDateTime=editDateTime) <-- this is to update bulletin
857  _log(CORP__CALL, "CorpRegistryBound::Handle_AddBulletin()");
858  call.Dump(CORP__CALL_DUMP);
859 
860  Call_AddBulletin args;
861  if (!args.Decode(&call.tuple)) {
862  codelog(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
863  return nullptr;
864  }
865 
866  bool edit = false;
867  int64 editDateTime = 0;
868  if (call.byname.find("editDateTime") != call.byname.end()) {
869  if (call.byname.find("editDateTime")->second->IsLong()) {
870  edit = true;
871  editDateTime = PyInt::IntegerValue(call.byname.find("editDateTime")->second);
872  } else {
873  _log(CORP__ERROR, "Handle_AddBulletin - editDateTime is of the wrong type: '%s'. Expected PyString or PyWString.", \
874  call.byname.find("editDateTime")->second->TypeString());
875  }
876  }
877 
878  int64 bulletinID = 0;
879  if (call.byname.find("bulletinID") != call.byname.end()) {
880  if (call.byname.find("bulletinID")->second->IsInt()) {
881  edit = true;
882  bulletinID = PyInt::IntegerValue(call.byname.find("bulletinID")->second);
883  } else {
884  _log(CORP__ERROR, "Handle_AddBulletin - bulletinID is of the wrong type: '%s'. Expected PyInt.", \
885  call.byname.find("bulletinID")->second->TypeString());
886  }
887  }
888 
889  if (edit) {
890  if (bulletinID >= 100000) {
891  AllianceDB::EditBulletin(bulletinID, call.client->GetCharacterID(), editDateTime, args.title, args.body);
892  } else {
893  m_db.EditBulletin(bulletinID, call.client->GetCharacterID(), editDateTime, args.title, args.body);
894  }
895 
896  } else {
897  m_db.AddBulletin(m_corpID, m_corpID, call.client->GetCharacterID(), args.title, args.body);
898  }
899 
900  return nullptr;
901 }
902 
903 PyResult CorpRegistryBound::Handle_DeleteBulletin(PyCallArgs &call) {
904  //self.GetCorpRegistry().DeleteBulletin(id)
905  _log(CORP__CALL, "CorpRegistryBound::Handle_DeleteBulletin() size=%u", call.tuple->size() );
906  call.Dump(CORP__CALL_DUMP);
907 
908  uint32 bulletinID = PyRep::IntegerValue(call.tuple->GetItem(0));
909  if (bulletinID >= 100000) {
910  AllianceDB::DeleteBulletin(bulletinID);
911  } else {
912  m_db.DeleteBulletin(bulletinID);
913  }
914  return nullptr;
915 }
916 
917 PyResult CorpRegistryBound::Handle_CreateRecruitmentAd(PyCallArgs &call) {
918  // return self.GetCorpRegistry().CreateRecruitmentAd(days, typeMask, allianceID, description, channelID, recruiters, title)
919  _log(CORP__CALL, "CorpRegistryBound::Handle_CreateRecruitmentAd()");
920  call.Dump(CORP__CALL_DUMP);
921  /*
922  * 00:41:50 [SvcCall] Service CorpRegistryBound::CreateRecruitmentAd()
923  * 00:41:50 W CorpRegistryBound::Handle_CreateRecruitmentAd(): size= 7
924  * 00:41:50 [CorpCallDump] Call Arguments:
925  * 00:41:50 [CorpCallDump] Tuple: 7 elements
926  * 00:41:50 [CorpCallDump] [ 0] Integer: 14
927  * 00:41:50 [CorpCallDump] [ 1] Integer: 34672663
928  * 00:41:50 [CorpCallDump] [ 2] None
929  * 00:41:50 [CorpCallDump] [ 3] WString: 'test'
930  * 00:41:50 [CorpCallDump] [ 4] Integer: 0
931  * 00:41:50 [CorpCallDump] [ 5] List: 1 elements
932  * 00:41:50 [CorpCallDump] [ 5] [ 0] Integer: 90000000
933  * 00:41:50 [CorpCallDump] [ 6] WString: 'test'
934  */
935 
936  Call_CreateRecruitmentAd args;
937  if (!args.Decode(&call.tuple)) {
938  codelog(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
939  return nullptr;
940  }
941 
942  uint32 amount = 1250000;
943  switch (args.days) {
944  case 7: amount = 2250000; break;
945  case 14: amount = 4000000; break;
946  case 28: amount = 7500000; break;
947  }
948 
949  AccountService::TranserFunds(m_corpID, call.client->GetCorpHQ(), amount, "Initial Advert Time for Corp Recruit Advert", Journal::EntryType::CorporationAdvertisementFee, call.client->GetCharacterID());
950 
951  int32 adID = m_db.CreateAdvert(call.client, m_corpID, args.typeMask, args.days, m_db.GetCorpMemberCount(m_corpID), args.description, args.channelID, args.title);
952 
953  std::vector<int32> recruiters;
954  recruiters.clear();
955  for (PyList::const_iterator itr = args.recruiters->begin(); itr != args.recruiters->end(); ++itr)
956  recruiters.push_back(PyRep::IntegerValue(*itr));
957  //recruiters.push_back((*itr)->AsInt()->value());
958 
959  // if no recruiters defined, default to creating character
960  if (recruiters.empty())
961  recruiters.push_back(call.client->GetCharacterID());
962 
963  m_db.AddRecruiters(adID, (int32)m_corpID, recruiters);
964 
965  return nullptr;
966 }
967 
968 PyResult CorpRegistryBound::Handle_UpdateRecruitmentAd(PyCallArgs &call) {
969  // return self.GetCorpRegistry().UpdateRecruitmentAd(adID, typeMask, description, channelID, recruiters, title, addedDays)
970  _log(CORP__CALL, "CorpRegistryBound::Handle_UpdateRecruitmentAd() size=%u", call.tuple->size() );
971  call.Dump(CORP__CALL_DUMP);
972 
973  /*
974  * 04:47:40 [CorpCall] CorpRegistryBound::Handle_UpdateRecruitmentAd() size=7
975  * 04:47:40 [CorpCallDump] Call Arguments:
976  * 04:47:40 [CorpCallDump] Tuple: 7 elements
977  * 04:47:40 [CorpCallDump] [ 0] Integer: 3
978  * 04:47:40 [CorpCallDump] [ 1] Integer: 34869363
979  * 04:47:40 [CorpCallDump] [ 2] WString: 'test advert msg'
980  * 04:47:40 [CorpCallDump] [ 3] Integer: 0
981  * 04:47:40 [CorpCallDump] [ 4] List: 3 elements
982  * 04:47:40 [CorpCallDump] [ 4] [ 0] Integer: 90000000
983  * 04:47:40 [CorpCallDump] [ 4] [ 1] Integer: 91000001
984  * 04:47:40 [CorpCallDump] [ 4] [ 2] Integer: 91000003
985  * 04:47:40 [CorpCallDump] [ 5] WString: 'mining corp'
986  * 04:47:40 [CorpCallDump] [ 6] Integer: 0
987  */
988 
989  Call_UpdateRecruitmentAd args;
990  if (!args.Decode(&call.tuple)) {
991  codelog(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
992  return nullptr;
993  }
994 
995  uint8 days = 1;
996  // check that corp can afford added time, if requested
997  if (args.addedDays) {
998  // 3d = .75misk, 7d = 1.75misk, 14d = 3.5misk
999  uint32 amount = 750000;
1000  switch (args.addedDays) {
1001  case 7: amount = 1750000; break;
1002  case 14: amount = 3500000; break;
1003  }
1004 
1005  AccountService::TranserFunds(m_corpID, call.client->GetCorpHQ(), amount, "Added Advert Time to Corp Recruit Advert", Journal::EntryType::CorporationAdvertisementFee);
1006 
1007  // do some funky shit to determine days left for advert then add additional time if requested
1008  int64 time = m_db.GetAdvertTime(args.adID, m_corpID);
1009  if (time > 0) {
1010  time -= GetFileTimeNow();
1011  days = time / EvE::Time::Day;
1012  days += args.addedDays;
1013  }
1014  }
1015 
1016  m_db.UpdateAdvert(args.adID, m_corpID, args.typeMask, days, m_db.GetCorpMemberCount(m_corpID), args.description, args.channelID, args.title);
1017 
1018  std::vector<int32> recruiters;
1019  recruiters.clear();
1020  for (PyList::const_iterator itr = args.recruiters->begin(); itr != args.recruiters->end(); ++itr)
1021  recruiters.push_back(PyRep::IntegerValue(*itr));
1022 
1023  // if no recruiters defined, default to creating character
1024  if (recruiters.empty())
1025  recruiters.push_back(call.client->GetCharacterID());
1026 
1027  m_db.AddRecruiters(args.adID, (int32)m_corpID, recruiters);
1028 
1029  return m_db.GetAdvert(args.adID);
1030 }
1031 
1032 PyResult CorpRegistryBound::Handle_MoveCompanyShares(PyCallArgs &call) {
1033  // return self.GetCorpRegistry().MoveCompanyShares(corporationID, toShareholderID, numberOfShares)
1034  _log(CORP__CALL, "CorpRegistryBound::Handle_MoveCompanyShares()");
1035  call.Dump(CORP__CALL_DUMP);
1036 
1037  Call_MoveShares args;
1038  if (!args.Decode(&call.tuple)) {
1039  codelog(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
1040  return nullptr;
1041  }
1042 
1043  if (IsCorp(args.toShareholderID)) {
1044  call.client->SendInfoModalMsg("You cannot give shares to a corporation.");
1045  return nullptr;
1046  }
1047 
1048  uint32 corpID = 0;
1049  Client* pClient = sEntityList.FindClientByCharID(args.toShareholderID);
1050  if (pClient == nullptr) {
1051  corpID = CharacterDB::GetCorpID(args.toShareholderID);
1052  } else {
1053  corpID = pClient->GetCorporationID();
1054  }
1055 
1057  m_db.MoveShares(m_corpID, corpID, args);
1058  return nullptr;
1059 }
1060 
1061 PyResult CorpRegistryBound::Handle_MovePrivateShares(PyCallArgs &call) {
1062  // return self.GetCorpRegistry().MovePrivateShares(corporationID, toShareholderID, numberOfShares)
1063  _log(CORP__CALL, "CorpRegistryBound::Handle_MovePrivateShares()");
1064  call.Dump(CORP__CALL_DUMP);
1065 
1066  Call_MoveShares args;
1067  if (!args.Decode(&call.tuple)) {
1068  codelog(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
1069  return nullptr;
1070  }
1071 
1072  uint32 corpID = 0;
1073  Client* pClient = sEntityList.FindClientByCharID(args.toShareholderID);
1074  if (pClient == nullptr) {
1075  corpID = CharacterDB::GetCorpID(args.toShareholderID);
1076  } else {
1077  corpID = pClient->GetCorporationID();
1078  }
1079 
1080  // gonna have to do this one different...
1081  // will need shares OF WHAT corpID also.
1083  return nullptr;
1084 }
1085 
1086 
1087 PyResult CorpRegistryBound::Handle_GetMemberIDsByQuery(PyCallArgs &call) {
1088  /*this is performed thru corp window using a multitude of options, to get specific members based on quite variable criteria
1089  * not as complicated as i had originally thought.
1090  */
1091 
1092  //return self.GetCorpRegistry().GetMemberIDsByQuery(query, includeImplied, searchTitles)
1093  call.Dump(CORP__CALL_DUMP);
1094  Call_GetMemberIDsByQuery_Main args;
1095  if (!args.Decode(&call.tuple)) {
1096  codelog(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
1097  return nullptr;
1098  }
1099 
1100  if (args.data->empty()) {
1101  call.client->SendErrorMsg("You must choose a role to search for.");
1102  return nullptr;
1103  }
1104 
1105  /*
1106  * query.append([property, operator, value])
1107  * query.append([joinOperator, property, operator, value])
1108  *
1109  * 04:28:06 [CorpCallDump] Call Arguments:
1110  * 04:28:06 [CorpCallDump] Tuple: 3 elements
1111  * 04:28:06 [CorpCallDump] [ 0] List: 3 elements
1112  * 04:28:06 [CorpCallDump] [ 0] [ 0] List: 3 elements
1113  * 04:28:06 [CorpCallDump] [ 0] [ 0] [ 0] String: 'roles'
1114  * 04:28:06 [CorpCallDump] [ 0] [ 0] [ 1] Integer: 7
1115  * 04:28:06 [CorpCallDump] [ 0] [ 0] [ 2] Integer: 134217728
1116  * 04:28:06 [CorpCallDump] [ 0] [ 1] List: 4 elements
1117  * 04:28:06 [CorpCallDump] [ 0] [ 1] [ 0] Integer: 2 <-- joinOp (AND/OR)
1118  * 04:28:06 [CorpCallDump] [ 0] [ 1] [ 1] String: 'roles' <-- queryType (Corp::QueryType {roles/charID/baseID/joinDate})
1119  * 04:28:06 [CorpCallDump] [ 0] [ 1] [ 2] Integer: 8 <-- searchOp (Corp::SearchOp)
1120  * 04:28:06 [CorpCallDump] [ 0] [ 1] [ 3] Integer: 4096 <-- value (depends on searchOp, int, int64)
1121  * 04:28:06 [CorpCallDump] [ 0] [ 2] List: 4 elements
1122  * 04:28:06 [CorpCallDump] [ 0] [ 2] [ 0] Integer: 2
1123  * 04:28:06 [CorpCallDump] [ 0] [ 2] [ 1] String: 'roles'
1124  * 04:28:06 [CorpCallDump] [ 0] [ 2] [ 2] Integer: 8
1125  * 04:28:06 [CorpCallDump] [ 0] [ 2] [ 3] Integer: 1024
1126  * 04:28:06 [CorpCallDump] [ 1] Integer: 1
1127  * 04:28:06 [CorpCallDump] [ 2] Integer: 1
1128  *
1129  */
1130  /*
1131  * int8 joinOp = Corp::JoinOp::None;
1132  * uint8 queryType = Corp::QueryType::Roles;
1133  * uint8 searchOp = Corp::SearchOp::EQUAL;
1134  * int64 value = 0;
1135  * std::string searchString = "";
1136  */
1137  // query holder
1138  std::ostringstream query;
1139  query << "SELECT characterID FROM chrCharacters WHERE corporationID = ";
1140  query << m_corpID << " AND ";
1141 
1142  bool set = false;
1143  // decode query format
1144  PyList* list(nullptr);
1145  for (PyList::const_iterator itr = args.data->begin(); itr != args.data->end(); ++itr) {
1146  list = (*itr)->AsList();
1147  if (list == nullptr)
1148  continue;
1149  if (list->size() == 3) {
1150  Call_GetMemberIDsByQuery_List3 args3;
1151  if (!args3.Decode(&list)) {
1152  codelog(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
1153  return nullptr;
1154  }
1155 
1156  if (args3.queryType.compare("roles") == 0) {
1157  query << "corpRole";
1158  } else {
1159  query << args3.queryType;
1160  }
1161 
1162  if (GetSearchValues(args3.searchOp, args3.valueRaw, query)) {
1163  set = true;
1164  } else {
1165  call.client->SendErrorMsg("Search data invalid. Ref: ServerError xxxxx");
1166  return nullptr;
1167  }
1168  } else if (list->size() == 4) {
1169  // db will not do bitwise for multiple operators.
1170  // will have to hit db for first call then query result with remaining conditionals to get result
1171  if (!set)
1172  return nullptr;
1173  Call_GetMemberIDsByQuery_List4 args4;
1174  if (!args4.Decode(&list)) {
1175  codelog(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
1176  return nullptr;
1177  }
1178 
1179  switch (args4.joinOp) {
1180  case Corp::JoinOp::AND: {
1181  query << " AND ";
1182  } break;
1183  case Corp::JoinOp::OR: {
1184  query << " OR ";
1185  } break;
1186  case Corp::JoinOp::None:
1187  default: {
1188  // error
1189  _log(CORP__ERROR, "CorpRegistryBound::Handle_GetMemberIDsByQuery() sent invalid JoinOp %i", args4.joinOp);
1190  return nullptr;
1191  } break;
1192  }
1193 
1194  if (args4.queryType.compare("roles") == 0) {
1195  query << "corpRole";
1196  } else {
1197  query << args4.queryType;
1198  }
1199 
1200  if (GetSearchValues(args4.searchOp, args4.valueRaw, query)) {
1201  set = true;
1202  } else {
1203  call.client->SendErrorMsg("Search data invalid. Ref: ServerError xxxxx");
1204  return nullptr;
1205  }
1206  } else {
1207  _log(CORP__ERROR, "CorpRegistryBound::Handle_GetMemberIDsByQuery() - Invalid data size: %u. Expected 3 or 4.", list->size());
1208  return nullptr;
1209  }
1210 
1211  }
1212 
1213  // get corp memberlist based on query
1214  std::vector<uint32> result;
1215  // make sure we have a valid query before sending to db method
1216  if (set)
1217  m_db.GetMembersForQuery(query, result);
1218 
1219  // create/clear list as needed
1220  if (list == nullptr) {
1221  list = new PyList();
1222  } else {
1223  list->clear();
1224  }
1225 
1226  // populate results
1227  for (auto cur : result)
1228  list->AddItem(new PyInt(cur));
1229 
1230  if (is_log_enabled(CORP__RSP_DUMP))
1231  list->Dump(CORP__RSP_DUMP, "");
1232 
1233  // return results
1234  return list;
1235 }
1236 
1237 //SELECT `characterID`\
1238 `corpRole`, `rolesAtAll`, `rolesAtHQ`, `rolesAtBase`, `rolesAtOther`, \
1239 `grantableRoles`, `grantableRolesAtHQ`, `grantableRolesAtBase`, `grantableRolesAtOther`,\
1240 `titleMask`, `blockRoles`, `baseID`, `startDateTime` FROM `chrCharacters` WHERE 1
1241 bool CorpRegistryBound::GetSearchValues(int8 op, PyRep* rep, std::ostringstream& query)
1242 {
1243  using namespace Corp;
1244  switch (op) {
1245  case SearchOp::EQUAL: {
1246  query << " = ";
1247  query << PyRep::IntegerValue(rep);
1248  } break;
1249  case SearchOp::GREATER: {
1250  query << " > ";
1251  query << PyRep::IntegerValue(rep);
1252  } break;
1254  query << " >= ";
1255  query << PyRep::IntegerValue(rep);
1256  } break;
1257  case SearchOp::LESS: {
1258  query << " < ";
1259  query << PyRep::IntegerValue(rep);
1260  } break;
1261  case SearchOp::LESS_OR_EQUAL: {
1262  query << " <= ";
1263  query << PyRep::IntegerValue(rep);
1264  } break;
1265  case SearchOp::NOT_EQUAL: {
1266  query << " != ";
1267  query << PyRep::IntegerValue(rep);
1268  } break;
1269  case SearchOp::HAS_BIT: {
1270  query << " &";
1271  query << PyRep::IntegerValue(rep);
1272  query << " = ";
1273  query << PyRep::IntegerValue(rep);
1274  } break;
1275  case SearchOp::NOT_HAS_BIT: {
1276  query << " ~";
1277  query << PyRep::IntegerValue(rep);
1278  query << " = ";
1279  query << PyRep::IntegerValue(rep);
1280  } break;
1282  case SearchOp::STR_LIKE: {
1283  query << "%";
1284  query << PyRep::StringContent(rep);
1285  query << "% ";
1286  } break;
1288  query << PyRep::StringContent(rep);
1289  query << "%";
1290  } break;
1291  case SearchOp::STR_ENDS_WITH: {
1292  query << "%";
1293  query << PyRep::StringContent(rep);
1294  } break;
1295  case SearchOp::STR_IS: {
1296  query << " = ";
1297  query << PyRep::StringContent(rep);
1298  } break;
1299  default: {
1300  _log(CORP__ERROR, "CorpRegistryBound::GetSearchValues() sent invalid searchOp %i", op);
1301  return false;
1302  };
1303  }
1304  return true;
1305 }
1306 
1307 // no longer used with new query decoding
1309 {
1310  if (queryType.compare("roles") == 0) {
1311  return Corp::QueryType::Roles;
1312  } else if (queryType.compare("rolesAtHQ") == 0) {
1313  return Corp::QueryType::Roles;
1314  } else if (queryType.compare("rolesAtBase") == 0) {
1315  return Corp::QueryType::Roles;
1316  } else if (queryType.compare("rolesAtOther") == 0) {
1317  return Corp::QueryType::Roles;
1318  } else if (queryType.compare("grantableRoles") == 0) {
1319  return Corp::QueryType::Roles;
1320  } else if (queryType.compare("grantableRolesAtHQ") == 0) {
1321  return Corp::QueryType::Roles;
1322  } else if (queryType.compare("grantableRolesAtBase") == 0) {
1323  return Corp::QueryType::Roles;
1324  } else if (queryType.compare("grantableRolesAtOther") == 0) {
1325  return Corp::QueryType::Roles;
1326  } else if (queryType.compare("baseID") == 0) {
1327  return Corp::QueryType::BaseID;
1328  } else if (queryType.compare("startDateTime") == 0) {
1330  } else if (queryType.compare("characterID") == 0) { //this is actually string. check searchOp for details
1331  return Corp::QueryType::CharID;
1332  } else if (queryType.compare("titleMask") == 0) {
1334  }
1335 
1336  _log(CORP__ERROR, "CorpRegistryBound::GetQueryType() - Invalid QueryType: %s", queryType.c_str());
1337  return 0;
1338 }
1339 
1340 
1345 PyResult CorpRegistryBound::Handle_PayoutDividend(PyCallArgs &call) {
1346  //self.GetCorpRegistry().PayoutDividend(payShareholders, payoutAmount)
1347  /*** shareholders
1348  * 04:42:43 W CorpRegistryBound::Handle_PayoutDividend(): size= 2
1349  * 04:42:43 [CorpCallDump] Call Arguments:
1350  * 04:42:43 [CorpCallDump] Tuple: 2 elements
1351  * 04:42:43 [CorpCallDump] [ 0] Integer field: 1 <-- int bool?
1352  * 04:42:43 [CorpCallDump] [ 1] Real field: 1.000000 <-- amount
1353  *** members
1354  * 04:42:50 W CorpRegistryBound::Handle_PayoutDividend(): size= 2
1355  * 04:42:50 [CorpCallDump] Call Arguments:
1356  * 04:42:50 [CorpCallDump] Tuple: 2 elements
1357  * 04:42:50 [CorpCallDump] [ 0] Integer field: 0
1358  * 04:42:50 [CorpCallDump] [ 1] Real field: 1.000000
1359  */
1360  _log(CORP__CALL, "CorpRegistryBound::Handle_PayoutDividend()");
1361  call.Dump(CORP__CALL_DUMP);
1362 
1363  Call_PayoutDividend args;
1364  if (!args.Decode(&call.tuple)) {
1365  codelog(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
1366  return nullptr;
1367  }
1368 
1371  // get list of ids to pay. this includes corp shareholders if paying to shares
1372  std::vector<uint32> toIDs;
1373  if (args.payShareholders) {
1374 
1375  } else {
1376 
1377  }
1378 
1379  // get total amount and divide by # of ids to pay
1380  float amount = args.payoutAmount / toIDs.size();
1381  if (amount < 0.01)
1382  return nullptr; //make error here?
1383 
1384  // pay each id and record xfer
1385  std::string reason = "Dividend Payment from ";
1386  reason += ""; //corp name here
1387  for (auto cur : toIDs)
1389 
1390  return nullptr;
1391 }
1392 
1393 PyResult CorpRegistryBound::Handle_UpdateMember(PyCallArgs &call) {
1394  //return self.GetCorpRegistry().UpdateMember(charIDToUpdate, title, divisionID, squadronID, roles, grantableRoles, rolesAtHQ, grantableRolesAtHQ, rolesAtBase, grantableRolesAtBase, rolesAtOther, grantableRolesAtOther, baseID, titleMask, blockRoles)
1396  /* called when clicking on "member details - roles tab - apply"
1397  * 21:14:49 [SvcCall] Service CorpRegistryBound::UpdateMember()
1398  * 21:14:49 [CorpCallDump] Call Arguments:
1399  * 21:14:49 [CorpCallDump] Tuple: 15 elements
1400  * 21:14:49 [CorpCallDump] [ 0] Integer: 91000034
1401  * 21:14:49 [CorpCallDump] [ 1] String: ''
1402  * 21:14:49 [CorpCallDump] [ 2] Integer: 0
1403  * 21:14:49 [CorpCallDump] [ 3] Integer: 0
1404  * 21:14:49 [CorpCallDump] [ 4] Long: 288230376151711744
1405  * 21:14:49 [CorpCallDump] [ 5] Integer: 0
1406  * 21:14:49 [CorpCallDump] [ 6] Integer: 0
1407  * 21:14:49 [CorpCallDump] [ 7] Integer: 0
1408  * 21:14:49 [CorpCallDump] [ 8] Integer: 0
1409  * 21:14:49 [CorpCallDump] [ 9] Integer: 0
1410  * 21:14:49 [CorpCallDump] [10] Integer: 0
1411  * 21:14:49 [CorpCallDump] [11] Integer: 0
1412  * 21:14:49 [CorpCallDump] [12] Integer: 60014137
1413  * 21:14:49 [CorpCallDump] [13] None
1414  * 21:14:49 [CorpCallDump] [14] None
1415  * 21:14:49 [CorpCallDump] Named Arguments:
1416  * 21:14:49 [CorpCallDump] machoVersion
1417  * 21:14:49 [CorpCallDump] Integer: 1
1418  * 21:14:49 [DecodeError] Decode Call_UpdateMember failed: grantableRoles is not a long Integer: Integer
1419  * 21:14:49 [SvcError] Handle_UpdateMember(/usr/local/src/eve/EVEmu/src/eve-server/corporation/CorpRegistryBound.cpp:1270): allan: Failed to decode arguments.
1420  */
1421  /* called when clicking on "member details - titles tab - apply"
1422  * 21:17:46 [SvcCall] Service CorpRegistryBound::UpdateMember()
1423  * 21:17:46 [CorpCallDump] Call Arguments:
1424  * 21:17:46 [CorpCallDump] Tuple: 15 elements
1425  * 21:17:46 [CorpCallDump] [ 0] Integer: 91000034
1426  * 21:17:46 [CorpCallDump] [ 1] WString: ''
1427  * 21:17:46 [CorpCallDump] [ 2] Integer: 0
1428  * 21:17:46 [CorpCallDump] [ 3] Integer: 0
1429  * 21:17:46 [CorpCallDump] [ 4] Integer: 0
1430  * 21:17:46 [CorpCallDump] [ 5] Integer: 0
1431  * 21:17:46 [CorpCallDump] [ 6] Integer: 0
1432  * 21:17:46 [CorpCallDump] [ 7] Integer: 0
1433  * 21:17:46 [CorpCallDump] [ 8] Integer: 0
1434  * 21:17:46 [CorpCallDump] [ 9] Integer: 0
1435  * 21:17:46 [CorpCallDump] [10] Integer: 0
1436  * 21:17:46 [CorpCallDump] [11] Integer: 0
1437  * 21:17:46 [CorpCallDump] [12] Integer: 60014137
1438  * 21:17:46 [CorpCallDump] [13] Integer: 1
1439  * 21:17:46 [CorpCallDump] [14] None
1440  * 21:17:46 [CorpCallDump] Named Arguments:
1441  * 21:17:46 [CorpCallDump] machoVersion
1442  * 21:17:46 [CorpCallDump] Integer: 1
1443  * 21:17:46 [DecodeWarning] Safe is enabled. title was decoded as PyWString
1444  * 21:17:46 [DecodeError] Decode Call_UpdateMember failed: roles is not a long Integer: Integer
1445  * 21:17:46 [SvcError] Handle_UpdateMember(/usr/local/src/eve/EVE/src/eve-server/corporation/CorpRegistryBound.cpp:1270): allan: Failed to decode arguments.
1446  */
1447  _log(CORP__CALL, "CorpRegistryBound::Handle_UpdateMember()");
1448  call.Dump(CORP__CALL_DUMP);
1449 
1450  Call_UpdateMember args;
1451  if (!args.Decode(&call.tuple)) {
1452  codelog(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
1453  return nullptr;
1454  }
1455  if (!IsCharacterID(args.charID))
1456  return nullptr;
1457 
1458  int64 oldRole(0);
1459  bool grantable(false); // boolean - do new roles have grantable privs? they may.
1460 
1461  Client* pClient = sEntityList.FindClientByCharID(args.charID);
1462  if (pClient == nullptr) {
1463  oldRole = CharacterDB::GetCorpRole(args.charID);
1464  CharacterDB::SetCorpRole(args.charID, args.roles);
1465  } else {
1466  oldRole = pClient->GetCorpRole();
1467  CorpData data = pClient->GetChar()->GetCorpData();
1468  data.rolesAtAll = args.roles;
1469  data.rolesAtBase = args.rolesAtBase;
1470  data.rolesAtHQ = args.rolesAtHQ;
1471  data.rolesAtOther = args.rolesAtOther;
1472  data.grantableRolesAtBase = args.grantableRolesAtBase;
1473  data.grantableRolesAtHQ = args.grantableRolesAtHQ;
1474  data.grantableRolesAtOther = args.grantableRolesAtOther;
1475  data.grantableRoles = args.grantableRoles;
1476  // update corp data and refresh session data.
1477  pClient->GetChar()->UpdateCorpData(data);
1478  }
1479 
1480  // check roleGroups data for bitmaks for grantable roles
1481  // use bitmaks to set 'grantable' bool
1482 
1483  m_db.AddRoleHistory(m_corpID, args.charID, call.client->GetCharacterID(), oldRole, args.roles, grantable);
1484  return nullptr;
1485 }
1486 
1487 PyResult CorpRegistryBound::Handle_InsertApplication(PyCallArgs &call)
1488 {
1489  Call_InsertApplication args;
1490  if (!args.Decode(&call.tuple)) {
1491  codelog(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
1492  return nullptr;
1493  }
1494 
1495  // should "corp jumpers" be time-limited? config option? parameters?
1496  // if so, put check here and return msg to player on hit
1497 
1498  // can we send app to non-player corp?
1499  if (!IsPlayerCorp(args.corpID))
1500  return nullptr;
1501  // check member limit
1502  if (m_db.GetCorpMemberCount(args.corpID) + 1 > m_db.GetCorpMemberLimit(args.corpID)) {
1503  call.client->SendNotifyMsg("%s cannot accept any new members at this time.", m_db.GetCorpName(args.corpID).c_str());
1504  return nullptr;
1505  }
1506 
1507  // check member race
1508  // ceo's ethnic relation skill allows +20%/lvl members of other races, based on member limit
1509  // not sure how im gonna do this yet....db column in corp table of off-race count maybe?
1510 
1511  uint32 charID = call.client->GetCharacterID();
1514  aInfo.valid = true;
1515  aInfo.charID = charID;
1516  aInfo.corpID = args.corpID;
1517  aInfo.appText = args.message;
1518  aInfo.role = Corp::Role::Member;
1519  aInfo.grantRole = Corp::Role::Member; // this is "None"
1521  aInfo.appTime = GetFileTimeNow();
1522  aInfo.deleted = false;
1523  aInfo.lastCID = 0;
1524 
1525  if (!m_db.InsertApplication(aInfo)) {
1526  codelog(SERVICE__ERROR, "%s: Failed to insert application request", call.client->GetName());
1527  return nullptr;
1528  }
1529 
1531 
1532  // this is sent for any change, including new
1534  oldInfo.valid = false;
1535  OnCorporationApplicationChanged OCAC;
1536  FillOCApplicationChange(OCAC, oldInfo, aInfo);
1537  // would this be for another corp??
1538  // could you bind/req this call from a diff corp?
1539  OCAC.corpID = args.corpID;
1540  OCAC.charID = charID;
1541  sEntityList.CorpNotify(args.corpID, Notify::Types::CorpAppNew, "OnCorporationApplicationChanged", "*corpid&corprole", OCAC.Encode());
1542  // this is also sent to applicant
1543  call.client->SendNotification("OnCorporationApplicationChanged", "*corpid&corprole", OCAC.Encode(), false);
1544 
1546 
1549  std::string subject = "New application from ";
1550  subject += call.client->GetName();
1551  std::vector<int32> recipients;
1552  recipients.push_back(m_db.GetCorporationCEO(args.corpID));
1553  m_manager->lsc_service->SendMail(charID, recipients, subject, args.message);
1554 
1555  // should this be sent from mail system? maybe not...cannot determine type from mail.
1556  // for now, this notification will need to be created/sent from same method sending mail.
1557  PyDict* dict = new PyDict();
1558  dict->SetItemString("applicationText", new PyString(args.message));
1559  dict->SetItemString("corpID", new PyInt(args.corpID));
1560  dict->SetItemString("charID", new PyInt(charID));
1561  OnNotify onn;
1562  onn.created = GetFileTimeNow();
1563  onn.data = dict;
1564  onn.notifyID = 0;
1565  onn.senderID = charID;
1566  onn.typeID = Notify::Types::CorpAppNew;
1567  sEntityList.CorpNotify(args.corpID, Notify::Types::CorpAppNew, "OnNotificationReceived", "clientID", onn.Encode());
1568 
1570  //returns none
1571  return nullptr;
1572 }
1573 
1574 PyResult CorpRegistryBound::Handle_UpdateApplicationOffer(PyCallArgs &call) {
1575  // return self.GetCorpRegistry().UpdateApplicationOffer(characterID, applicationText, status, applicationDateTime = None) NOTE: time not used.
1576  _log(CORP__CALL, "CorpRegistryBound::Handle_UpdateApplicationOffer() size=%u", call.tuple->size() );
1577  call.Dump(CORP__CALL_DUMP);
1578 
1579  Call_UpdateApplicationOffer args;
1580  if (!args.Decode(&call.tuple)) {
1581  codelog(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
1582  return nullptr;
1583  }
1584 
1585  // can we send app to non-player corp?
1586  if (!IsPlayerCorp(m_corpID))
1587  return nullptr;
1588 
1590  oldInfo.valid = true;
1591  oldInfo.appText = args.appText;
1592  oldInfo.charID = args.charID;
1593  oldInfo.corpID = m_corpID; // is this applicants current corpID or applied-to corpID??
1594  if (!m_db.GetCurrentApplicationInfo(oldInfo)) {
1595  codelog(SERVICE__ERROR, "%s: Failed to query application for char %u corp %u", call.client->GetName(), args.charID, m_corpID);
1596  return nullptr;
1597  }
1598 
1599  Corp::ApplicationInfo newInfo = oldInfo;
1600  newInfo.valid = true; // allow saving of this update. we'll null it later.
1601  // these are populated as we're still saving new status in db. subject to change as system progresses
1602  newInfo.status = args.newStatus;
1603  newInfo.lastCID = call.client->GetCharacterID();
1604  //newInfo.appTime = GetFileTimeNow(); // not used here.
1605  if (!m_db.UpdateApplication(newInfo)) {
1606  codelog(SERVICE__ERROR, "%s: Failed to update application for char %u corp %u", call.client->GetName(), args.charID, m_corpID);
1607  return nullptr;
1608  }
1609 
1610  // sets 'new' info to PyNone in OnCorporationApplicationChanged packet. this removes app from char/corp page
1611  //newInfo.valid = false;
1612 
1613  OnCorporationApplicationChanged ocac;
1614  ocac.charID = args.charID;
1615  ocac.corpID = m_corpID;
1616  FillOCApplicationChange(ocac, oldInfo, newInfo);
1617 
1618  if (args.newStatus == Corp::AppStatus::AcceptedByCorporation) {
1619  MemberAttributeUpdate change;
1620  if (!m_db.CreateMemberAttributeUpdate(oldInfo.corpID, args.charID, change)) {
1621  codelog(SERVICE__ERROR, "%s: Failed to update application for char %u corp %u", call.client->GetName(), args.charID, m_corpID);
1622  return nullptr;
1623  }
1624 
1625  sEntityList.CorpNotify(m_corpID, Notify::Types::CorpAppAccept, "OnCorporationApplicationChanged", "*corpid&corprole", ocac.Encode());
1626 
1627  // OnObjectPublicAttributesUpdated event <<<--- needs to be updated. do search in packet logs
1628  OnObjectPublicAttributesUpdated opau;
1629  opau.realRowCount = m_db.GetMemberCount(m_corpID); // for this call, this is corp membership
1630  opau.bindID = GetBindStr();
1631  opau.changePKIndexValue = args.charID; // logs show this as charID, but cant find anything about it in code as to why.
1632  opau.changes = change.Encode();
1633  sEntityList.CorpNotify(m_corpID, Notify::Types::CorpNews, "OnObjectPublicAttributesUpdated", "objectID", opau.Encode());
1634 
1635  // OnCorporationMemberChanged event
1636  OnCorpMemberChange ocmc;
1637  ocmc.charID = args.charID;
1638  ocmc.newCorpID = PyRep::IntegerValue(change.corporationIDNew);
1639  ocmc.oldCorpID = PyRep::IntegerValue(change.corporationIDOld);
1640  ocmc.newDate = (int64)GetFileTimeNow(); //PyRep::IntegerValue(OCAC.applicationDateTimeNew);
1641  ocmc.oldDate = oldInfo.appTime; // PyRep::IntegerValue(OCAC.applicationDateTimeOld);
1642 
1643  // both corporations' members will be notified about the change
1644  sEntityList.CorpNotify(m_corpID, Notify::Types::CorpNews, "OnCorporationMemberChanged", "corpid", ocmc.Encode());
1645  // old corp MAY be NPC corp...
1646  if (IsPlayerCorp(ocmc.oldCorpID))
1647  sEntityList.CorpNotify(ocmc.oldCorpID, Notify::Types::CorpNews, "OnCorporationMemberChanged", "corpid", ocmc.Encode());
1648 
1649  CorpData data = CorpData();
1650  sItemFactory.db()->GetCorpData(args.charID, data);
1661  data.corporationID = m_corpID;
1662  Client* recruit = sEntityList.FindClientByCharID(ocmc.charID); // this returns nullptr for offline chars
1663  if (recruit != nullptr) {
1664  recruit->GetChar()->JoinCorporation(data);
1665  } else {
1666  CharacterDB::AddEmployment(args.charID, m_corpID, ocmc.oldCorpID);
1667  }
1668 
1669  // add corp events for changing both corps
1670  m_db.AddItemEvent(m_corpID, args.charID, Corp::EventType::JoinedCorporation);
1671  if (IsPlayerCorp(ocmc.oldCorpID))
1672  m_db.AddItemEvent(ocmc.oldCorpID, args.charID, Corp::EventType::LeftCorporation);
1673  } else if (args.newStatus == Corp::AppStatus::RejectedByCorporation) {
1674  sEntityList.CorpNotify(m_corpID, Notify::Types::CorpAppReject, "OnCorporationApplicationChanged", "*corpid&corprole", ocac.Encode());
1675  } else if (args.newStatus == Corp::AppStatus::RenegotiatedByCorporation) {
1676  // i dont see this option in client code...may not be able to reneg app.
1677  _log(CORP__MESSAGE, "CorpRegistryBound::Handle_UpdateApplicationOffer() hit AppStatus::RenegotiatedByCorporation by %s ", call.client->GetName() );
1678  } else {
1679  codelog(SERVICE__ERROR, "%s: Sent unhandled status %u ", call.client->GetName(), args.newStatus);
1680  // error...what to do here?
1681  }
1682 
1683  // update applicant, if online
1684  Client* pClient = sEntityList.FindClientByCharID(args.charID);
1685  if (pClient != nullptr)
1686  pClient->SendNotification("OnCorporationApplicationChanged", "clientID", ocac.Encode(), false);
1687 
1688  return nullptr;
1689 }
1690 
1691 PyResult CorpRegistryBound::Handle_DeleteApplication(PyCallArgs & call)
1692 {
1693  // self.GetCorpRegistry().DeleteApplication(corporationID, characterID)
1694  _log(CORP__CALL, "CorpRegistryBound::Handle_DeleteApplication() size=%u", call.tuple->size() );
1695  call.Dump(CORP__CALL_DUMP);
1696 
1697  Call_TwoIntegerArgs args;
1698  if (!args.Decode(&call.tuple)) {
1699  codelog(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
1700  return PyStatic.NewFalse();
1701  }
1702 
1703  OnCorporationApplicationChanged ocac;
1704  ocac.corpID = args.arg1;
1705  ocac.charID = args.arg2;
1707  newInfo.valid = false;
1709  oldInfo.valid = true;
1710  oldInfo.corpID = args.arg1;
1711  oldInfo.charID = args.arg2;
1712  if (!m_db.GetCurrentApplicationInfo(oldInfo)) {
1713  codelog(SERVICE__ERROR, "%s: Failed to query application info for char %u corp %u", call.client->GetName(), ocac.charID, ocac.corpID);
1714  return PyStatic.NewFalse();
1715  }
1716 
1717  FillOCApplicationChange(ocac, oldInfo, newInfo);
1718  if (!m_db.DeleteApplication(oldInfo)) {
1719  codelog(SERVICE__ERROR, "%s: Failed to delete application info for char %u corp %u", call.client->GetName(), ocac.charID, ocac.corpID);
1720  return PyStatic.NewFalse();
1721  }
1722 
1723  sEntityList.CorpNotify(m_corpID, Notify::Types::CorpAppNew, "OnCorporationApplicationChanged", "*corpid&corprole", ocac.Encode());
1724 
1725  return PyStatic.NewTrue();
1726 }
1727 
1728 void CorpRegistryBound::FillOCApplicationChange(OnCorporationApplicationChanged& OCAC, const Corp::ApplicationInfo& Old, const Corp::ApplicationInfo& New)
1729 {
1730  // ? (PyRep*)new PyInt(x) : PyStatic.NewNone();
1731  if (Old.valid) {
1732  OCAC.applicationIDOld = new PyInt(Old.appID);
1733  //OCAC.applicationDateTimeOld = new PyLong(Old.appTime);
1734  OCAC.applicationTextOld = new PyString(Old.appText);
1735  OCAC.characterIDOld = new PyInt(Old.charID);
1736  OCAC.corporationIDOld = new PyInt(Old.corpID);
1737  //OCAC.deletedOld = new PyInt(Old.deleted);
1738  //OCAC.grantableRolesOld = new PyLong(Old.grantRole);
1739  if (Old.lastCID) {
1740  OCAC.lastCorpUpdaterIDOld = new PyInt(Old.lastCID);
1741  } else {
1742  OCAC.lastCorpUpdaterIDOld = PyStatic.NewNone();
1743  }
1744  //OCAC.rolesOld = new PyLong(Old.role);
1745  OCAC.statusOld = new PyInt(Old.status);
1746  } else {
1747  OCAC.applicationIDOld = PyStatic.NewNone();
1748  //OCAC.applicationDateTimeOld = PyStatic.NewNone();
1749  OCAC.applicationTextOld = PyStatic.NewNone();
1750  OCAC.characterIDOld = PyStatic.NewNone();
1751  OCAC.corporationIDOld = PyStatic.NewNone();
1752  //OCAC.deletedOld = PyStatic.NewNone();
1753  //OCAC.grantableRolesOld = PyStatic.NewNone();
1754  OCAC.lastCorpUpdaterIDOld = PyStatic.NewNone();
1755  //OCAC.rolesOld = PyStatic.NewNone();
1756  OCAC.statusOld = PyStatic.NewNone();
1757  }
1758 
1759  if (New.valid) {
1760  OCAC.applicationIDNew = new PyInt(New.appID);
1761  //OCAC.applicationDateTimeNew = new PyLong(New.appTime);
1762  OCAC.applicationTextNew = new PyString(New.appText);
1763  OCAC.characterIDNew = new PyInt(New.charID);
1764  OCAC.corporationIDNew = new PyInt(New.corpID);
1765  //OCAC.deletedNew = new PyInt(New.deleted);
1766  //OCAC.grantableRolesNew = new PyLong(New.grantRole);
1767  if (New.lastCID) {
1768  OCAC.lastCorpUpdaterIDNew = new PyInt(New.lastCID);
1769  } else {
1770  OCAC.lastCorpUpdaterIDNew = PyStatic.NewNone();
1771  }
1772  //OCAC.rolesNew = new PyLong(New.role);
1773  OCAC.statusNew = new PyInt(New.status);
1774  } else {
1775  OCAC.applicationIDNew = PyStatic.NewNone();
1776  //OCAC.applicationDateTimeNew = PyStatic.NewNone();
1777  OCAC.applicationTextNew = PyStatic.NewNone();
1778  OCAC.characterIDNew = PyStatic.NewNone();
1779  OCAC.corporationIDNew = PyStatic.NewNone();
1780  //OCAC.deletedNew = PyStatic.NewNone();
1781  //OCAC.grantableRolesNew = PyStatic.NewNone();
1782  OCAC.lastCorpUpdaterIDNew = PyStatic.NewNone();
1783  //OCAC.rolesNew = PyStatic.NewNone();
1784  OCAC.statusNew = PyStatic.NewNone();
1785  }
1786 }
1787 
1788 PyResult CorpRegistryBound::Handle_GetStations(PyCallArgs &call)
1789 { // not working
1790  // logs show this should be SparseRowset, but handled by bound corp registry object
1791  _log(CORP__CALL, "CorpRegistryBound::Handle_GetStations() size=%u", call.tuple->size() );
1792  call.Dump(CORP__CALL_DUMP);
1793 
1794  /*
1795  * [PyTuple 1 items]
1796  * [PySubStream 88 bytes]
1797  * [PyObjectData Name: util.SparseRowset]
1798  * [PyTuple 3 items]
1799  * [PyList 2 items]
1800  * [PyString "stationID"]
1801  * [PyString "typeID"]
1802  * [PySubStruct]
1803  * [PySubStream 51 bytes]
1804  * [PyTuple 3 items]
1805  * [PyString "N=698477:223512"]
1806  * [PyDict 1 kvp]
1807  * [PyString "realRowCount"]
1808  * [PyInt 0]
1809  * [PyIntegerVar 129492959106785392]
1810  * [PyInt 0]
1811  * [PyDict 1 kvp]
1812  * [PyString "OID+"]
1813  * [PyDict 1 kvp]
1814  * [PyString "N=698477:223512"]
1815  * [PyIntegerVar 129492959106785392]
1816  */
1817 
1842  PyObject* obj = m_db.GetStations(m_corpID);
1843 
1844  if (is_log_enabled(CORP__RSP_DUMP))
1845  obj->Dump(CORP__RSP_DUMP, "");
1846 
1847  return obj;
1848 }
1849 
1850 PyResult CorpRegistryBound::Handle_GetOffices(PyCallArgs &call) {
1851  _log(CORP__CALL, "CorpRegistryBound::Handle_GetOffices() size=%u", call.tuple->size() );
1852  call.Dump(CORP__CALL_DUMP);
1853 
1854  PyBoundObject* bObj = new SparseBound(m_manager, m_db, m_corpID);
1855  if (bObj == NULL) {
1856  _log(SERVICE__ERROR, "%s: Unable to create bound object for:", call.client->GetName()); //errors here
1857  return nullptr;
1858  }
1859 
1860  // this sends header info and # offices rented by corp
1861  // Data will be fetched from the subsequent call to SparseRowset (using self.sr.offices in client)
1862  CorpOfficeSparseRowset rsp;
1863  rsp.officeCount = StationDB::GetOfficeCount(m_corpID);
1864 
1865  PyDict* dict = new PyDict();
1866  dict->SetItemString("realRowCount", new PyInt(rsp.officeCount));
1867 
1868  PyDict* oid = new PyDict();
1869  rsp.boundObject = m_manager->BindObject(call.client, bObj, dict, oid);
1870 
1871  PyObject* obj = rsp.Encode();
1872  if (is_log_enabled(CORP__RSP_DUMP))
1873  obj->Dump(CORP__RSP_DUMP, "");
1874 
1875  return PyResult(obj, oid);
1876  /*
1877  [PyTuple 1 items]
1878  [PySubStream 114 bytes]
1879  [PyObjectData Name: util.SparseRowset]
1880  [PyTuple 3 items]
1881  [PyList 4 items]
1882  [PyString "stationID"]
1883  [PyString "typeID"]
1884  [PyString "officeID"]
1885  [PyString "officeFolderID"]
1886  [PySubStruct]
1887  [PySubStream 50 bytes]
1888  [PyTuple 3 items]
1889  [PyString "N=789442:2172"]
1890  [PyDict 1 kvp]
1891  [PyString "realRowCount"]
1892  [PyInt 8]
1893  [PyIntegerVar 129753802088805346]
1894  [PyInt 8]
1895  [PyDict 1 kvp]
1896  [PyString "OID+"]
1897  [PyDict 1 kvp]
1898  [PyString "N=789442:2172"]
1899  [PyIntegerVar 129753802088805346]
1900  */
1901  /* newish (dv packet)
1902  [PyTuple 1 items]
1903  [PySubStream 139 bytes]
1904  [PyObjectData Name: eve.common.script.sys.rowset.SparseRowset]
1905  [PyTuple 3 items]
1906  [PyList 5 items]
1907  [PyString "locationID"]
1908  [PyString "solarSystemID"]
1909  [PyString "typeID"]
1910  [PyString "officeID"]
1911  [PyString "officeFolderID"]
1912  [PySubStruct]
1913  [PySubStream 50 bytes]
1914  [PyTuple 3 items]
1915  [PyString "N=1222739:1759"]
1916  [PyDict 1 kvp]
1917  [PyString "realRowCount"]
1918  [PyInt 0]
1919  [PyIntegerVar 131101118262531055]
1920  [PyInt 0]
1921  [PyDict 1 kvp]
1922  [PyString "OID+"]
1923  [PyDict 1 kvp]
1924  [PyString "N=1222739:1759"]
1925  [PyIntegerVar 131101118262531055]
1926  */
1927 }
1928 
1929 PyResult CorpRegistryBound::Handle_InsertVoteCase(PyCallArgs &call) {
1930  // return self.GetCorpRegistry().InsertVoteCase(voteCaseText, description, corporationID, voteType, voteCaseOptions, startDateTime, endDateTime)
1931  // see notes in m_db.AddVoteCase() for more info on data
1932 
1933  _log(CORP__CALL, "CorpRegistryBound::Handle_InsertVoteCase()");
1934  call.Dump(CORP__CALL_DUMP);
1935 
1936  /*
1937  * 10:10:55 W CorpRegistryBound::Handle_InsertVoteCase(): size= 7
1938  * 10:10:55 [CorpCallDump] Call Arguments:
1939  * 10:10:55 [CorpCallDump] Tuple: 7 elements
1940  * 10:10:55 [CorpCallDump] [ 0] WString: 'test' << voteCaseText
1941  * 10:10:55 [CorpCallDump] [ 1] WString: 'test vote' << description
1942  * 10:10:55 [CorpCallDump] [ 2] Integer: 98000000 << corporationID
1943  * 10:10:55 [CorpCallDump] [ 3] Integer: 4 << voteType (Corp::VoteType::xx)
1944  * 10:10:55 [CorpCallDump] [ 4] Object:
1945  * 10:10:55 [CorpCallDump] [ 4] Type: String: 'util.Rowset'
1946  * 10:10:55 [CorpCallDump] [ 4] Args: Dictionary: 3 entries << voteCaseOptions
1947  * 10:10:55 [CorpCallDump] [ 4] Args: [ 0] Key: String: 'lines'
1948  * 10:10:55 [CorpCallDump] [ 4] Args: [ 0] Value: List: 2 elements
1949  * 10:10:55 [CorpCallDump] [ 4] Args: [ 0] Value: [ 0] List: 4 elements
1950  * 10:10:55 [CorpCallDump] [ 4] Args: [ 0] Value: [ 0] [ 0] WString: 'yay'
1951  * 10:10:55 [CorpCallDump] [ 4] Args: [ 0] Value: [ 0] [ 1] Integer: 0
1952  * 10:10:55 [CorpCallDump] [ 4] Args: [ 0] Value: [ 0] [ 2] None: 0
1953  * 10:10:55 [CorpCallDump] [ 4] Args: [ 0] Value: [ 0] [ 3] None: 0
1954  * 10:10:55 [CorpCallDump] [ 4] Args: [ 0] Value: [ 1] List: 4 elements
1955  * 10:10:55 [CorpCallDump] [ 4] Args: [ 0] Value: [ 1] [ 0] WString: 'nay'
1956  * 10:10:55 [CorpCallDump] [ 4] Args: [ 0] Value: [ 1] [ 1] Integer: 1
1957  * 10:10:55 [CorpCallDump] [ 4] Args: [ 0] Value: [ 1] [ 2] None: 0
1958  * 10:10:55 [CorpCallDump] [ 4] Args: [ 0] Value: [ 1] [ 3] None: 0
1959  * 10:10:55 [CorpCallDump] [ 4] Args: [ 1] Key: String: 'RowClass'
1960  * 10:10:55 [CorpCallDump] [ 4] Args: [ 1] Value: Token: 'util.Row'
1961  * 10:10:55 [CorpCallDump] [ 4] Args: [ 2] Key: String: 'header'
1962  * 10:10:55 [CorpCallDump] [ 4] Args: [ 2] Value: List: 4 elements
1963  * 10:10:55 [CorpCallDump] [ 4] Args: [ 2] Value: [ 0] String: 'choice'
1964  * 10:10:55 [CorpCallDump] [ 4] Args: [ 2] Value: [ 1] String: 'itemID'
1965  * 10:10:55 [CorpCallDump] [ 4] Args: [ 2] Value: [ 2] String: 'typeID'
1966  * 10:10:55 [CorpCallDump] [ 4] Args: [ 2] Value: [ 3] String: 'locationID'
1967  * 10:10:55 [CorpCallDump] [ 5] Long: 131575686552352973 << startDateTime
1968  * 10:10:55 [CorpCallDump] [ 6] Long: 131576550552352973 << endDateTime
1969  * 10:10:55 [CorpCallDump] Call Named Arguments:
1970  * 10:10:55 [CorpCallDump] Argument 'machoVersion':
1971  * 10:10:55 [CorpCallDump] Integer: 1
1972  */
1973 
1974  /*
1975  * 13:54:27 [CorpCall] CorpRegistryBound::Handle_InsertVoteCase()
1976  * 13:54:27 [DB Error] DoQuery_locked(/backups/local/src/eve/EVE/src/eve-core/database/dbcore.cpp:345):
1977  * DBCore Query - #1064 in
1978  * 'INSERT INTO crpVoteOptions (voteCaseID, optionID, optionText, parameter, parameter1, parameter2)
1979  * VALUES
1980  * (1,-104,'Lockdown the 125mm Gatling AutoCannon I Blueprint',140024216,819,60014140),
1981  * (1,0,'Don't lockdown the 125mm Gatling AutoCannon I Blueprint',0,0,0)':
1982  *
1983  * You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version
1984  * for the right syntax to use near 't lockdown the 125mm Gatling AutoCannon I Blueprint',0,0,0)' at line 1
1985  */
1986 
1987 
1988  if (!call.tuple->GetItem(4)->IsObject()) {
1989  codelog(CORP__ERROR, "Tuple Item is wrong type: %s. Expected PyObject.", call.tuple->GetItem(0)->TypeString());
1990  return nullptr;
1991  }
1992  Call_InsertVoteCase args;
1993  if (!args.Decode(&call.tuple)) {
1994  codelog(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
1995  return nullptr;
1996  }
1997 
1998  if (!args.voteCaseOptions->arguments()->IsDict()) {
1999  codelog(CORP__ERROR, "voteCaseOptions Argument is wrong type: %s. Expected PyDict.", args.voteCaseOptions->arguments()->TypeString());
2000  return nullptr;
2001  }
2002 
2003  m_db.AddVoteCase(m_corpID, call.client->GetCharacterID(), args);
2004 
2005  // OnCorporationVoteCaseChanged
2006 
2007  // send notification to online corp memebers
2008  //def OnNotificationReceived(self, notificationID, typeID, senderID, created, data = {}):
2009  /*
2010  * ==================== Sent from Server 161 bytes
2011  *
2012  * [PyObjectData Name: macho.Notification]
2013  * [PyTuple 6 items]
2014  * [PyInt 12]
2015  * [PyObjectData Name: macho.MachoAddress]
2016  * [PyTuple 4 items]
2017  * [PyInt 1]
2018  * [PyInt 698477]
2019  * [PyNone]
2020  * [PyNone]
2021  * [PyObjectData Name: macho.MachoAddress]
2022  * [PyTuple 4 items]
2023  * [PyInt 4]
2024  * [PyString "OnNotificationReceived"]
2025  * [PyList 0 items]
2026  * [PyString "clientID"]
2027  * [PyInt 5654387]
2028  * [PyTuple 1 items]
2029  * [PyTuple 2 items]
2030  * [PyInt 0]
2031  * [PySubStream 85 bytes]
2032  * [PyTuple 2 items]
2033  * [PyInt 0]
2034  * [PyTuple 2 items]
2035  * [PyInt 1]
2036  * [PyTuple 5 items]
2037  * [PyInt 342405655] << notifyID (sequential? random?)
2038  * [PyInt 25] << Notify::Types::CorpVote
2039  * [PyInt 1661059544] << senderID (CharID)
2040  * [PyIntegerVar 129492998400000000] << created timestamp
2041  * [PyDict 2 kvp] << data (varies for each notify type)
2042  * [PyString "body"]
2043  * [PyString "please vote for me"]
2044  * [PyString "subject"]
2045  * [PyString "proposed vote"]
2046  * [PyDict 1 kvp]
2047  * [PyString "sn"]
2048  * [PyIntegerVar 9]
2049  */
2050  return nullptr;
2051 }
2052 
2053 PyResult CorpRegistryBound::Handle_GetVoteCasesByCorporation(PyCallArgs &call)
2054 {
2055  // xxx = self.GetCorpRegistry().GetVoteCasesByCorporation(corpid)
2056  //return self.GetCorpRegistry().GetVoteCasesByCorporation(corpid, status, maxLen)
2057 
2058  /*** from closed
2059  * 04:24:15 W CorpRegistryBound::Handle_GetVoteCasesByCorporation(): size= 3
2060  * 04:24:15 [CorpCallDump] Call Arguments:
2061  * 04:24:15 [CorpCallDump] Tuple: 3 elements
2062  * 04:24:15 [CorpCallDump] [ 0] Integer field: 98000000
2063  * 04:24:15 [CorpCallDump] [ 1] Integer field: 1
2064  * 04:24:15 [CorpCallDump] [ 2] Integer field: 20
2065  *** from open
2066  * 04:24:20 W CorpRegistryBound::Handle_GetVoteCasesByCorporation(): size= 3
2067  * 04:24:20 [CorpCallDump] Call Arguments:
2068  * 04:24:20 [CorpCallDump] Tuple: 3 elements
2069  * 04:24:20 [CorpCallDump] [ 0] Integer field: 98000000
2070  * 04:24:20 [CorpCallDump] [ 1] Integer field: 2
2071  * 04:24:20 [CorpCallDump] [ 2] Integer field: 0
2072  *** from sanctionable actions
2073  * 12:48:19 [CorpCall] CorpRegistryBound::Handle_GetVoteCasesByCorporation()
2074  * 12:48:19 [CorpCallDump] Call Arguments:
2075  * 12:48:19 [CorpCallDump] Tuple: 1 elements
2076  * 12:48:19 [CorpCallDump] [ 0] Integer: 98000000
2077  *
2078  */
2079  /*
2080  [PyTuple 1 items]
2081  [PySubStream 193 bytes]
2082  [PyObjectData Name: util.IndexRowset]
2083  [PyDict 4 kvp]
2084  [PyString "items"]
2085  [PyDict 1 kvp]
2086  [PyInt 2167602]
2087  [PyList 8 items]
2088  [PyInt 2167602]
2089  [PyString "proposed vote"]
2090  [PyString "please vote for me"]
2091  [PyInt 98038978]
2092  [PyInt 1661059544]
2093  [PyInt 4]
2094  [PyIntegerVar 129492998400000000]
2095  [PyIntegerVar 129493862400000000]
2096  [PyString "RowClass"]
2097  [PyToken util.Row]
2098  [PyString "idName"]
2099  [PyString "voteCaseID"]
2100  [PyString "header"]
2101  [PyList 8 items]
2102  [PyString "voteCaseID"]
2103  [PyString "voteCaseText"]
2104  [PyString "description"]
2105  [PyString "corporationID"]
2106  [PyString "characterID"]
2107  [PyString "voteType"]
2108  [PyString "startDateTime"]
2109  [PyString "endDateTime"]
2110  */
2111  _log(CORP__CALL, "CorpRegistryBound::Handle_GetVoteCasesByCorporation()");
2112  call.Dump(CORP__CALL_DUMP);
2113 
2114  if (call.tuple->size() == 3) {
2115  Call_GetVoteCases args;
2116  if (!args.Decode(&call.tuple)) {
2117  codelog(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
2118  return nullptr;
2119  }
2120  return m_db.GetVoteItems(args.corpid, args.status, args.maxLen);
2121  } else if (call.tuple->size() == 1) {
2122  return m_db.GetVoteItems(m_corpID);
2123  } else {
2124  ; // error?
2125  }
2126 
2127  return nullptr;
2128 }
2129 
2130 PyResult CorpRegistryBound::Handle_GetVoteCaseOptions(PyCallArgs &call) {
2131  // options = self.GetCorpRegistry().GetVoteCaseOptions(corpID, voteCaseID)
2132  _log(CORP__CALL, "CorpRegistryBound::Handle_GetVoteCaseOptions()");
2133  call.Dump(CORP__CALL_DUMP);
2134 
2135  Call_TwoIntegerArgs args;
2136  if (!args.Decode(&call.tuple)) {
2137  codelog(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
2138  return nullptr;
2139  }
2140 
2141  PyRep* rsp = m_db.GetVoteOptions(args.arg2);
2142  if (is_log_enabled(CORP__RSP_DUMP))
2143  rsp->Dump(CORP__RSP_DUMP, "");
2144 
2145  return rsp;
2146 }
2147 
2148 PyResult CorpRegistryBound::Handle_GetVotes(PyCallArgs &call) {
2149  // charVotes = sm.GetService('corp').GetVotes(self.corpID, vote.voteCaseID)
2150  _log(CORP__CALL, "CorpRegistryBound::Handle_GetVotes() size=%u", call.tuple->size() );
2151  call.Dump(CORP__CALL_DUMP);
2152 
2153  Call_TwoIntegerArgs args;
2154  if (!args.Decode(&call.tuple)) {
2155  codelog(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
2156  return nullptr;
2157  }
2158  // this will need a bit more thought....
2159  /*
2160  charVotes = sm.GetService('corp').GetVotes(self.corpID, vote.voteCaseID)
2161  hasVoted = 0
2162  votedFor = -1
2163  if charVotes and charVotes.has_key(session.charid):
2164  hasVoted = 1
2165  votedFor = charVotes[session.charid].optionID
2166  */
2167 
2168  PyRep* rsp = m_db.GetVotes(args.arg2);
2169  if (is_log_enabled(CORP__RSP_DUMP))
2170  rsp->Dump(CORP__RSP_DUMP, "");
2171 
2172  return rsp;
2173 }
2174 
2175 /* GetVoteCaseOptions
2176  [PyTuple 1 items]
2177  [PySubStream 243 bytes]
2178  [PyObjectData Name: util.IndexRowset]
2179  [PyDict 4 kvp]
2180  [PyString "items"]
2181  [PyDict 3 kvp]
2182  [PyInt 0]
2183  [PyList 9 items]
2184  [PyInt 2167602]
2185  [PyInt 0]
2186  [PyString "vote choice 1"]
2187  [PyIntegerVar 0]
2188  [PyFloat 0]
2189  [PyInt 0]
2190  [PyInt 0]
2191  [PyNone]
2192  [PyNone]
2193  [PyInt 1]
2194  [PyList 9 items]
2195  [PyInt 2167602]
2196  [PyInt 1]
2197  [PyString "vote choice 2"]
2198  [PyIntegerVar 1]
2199  [PyFloat 0]
2200  [PyInt 0]
2201  [PyInt 0]
2202  [PyNone]
2203  [PyNone]
2204  [PyInt 2]
2205  [PyList 9 items]
2206  [PyInt 2167602]
2207  [PyInt 2]
2208  [PyString "vote choice 3"]
2209  [PyIntegerVar 2]
2210  [PyFloat 0]
2211  [PyInt 0]
2212  [PyInt 0]
2213  [PyNone]
2214  [PyNone]
2215  [PyString "RowClass"]
2216  [PyToken util.Row]
2217  [PyString "idName"]
2218  [PyString "optionID"]
2219  [PyString "header"]
2220  [PyList 9 items]
2221  [PyString "voteCaseID"]
2222  [PyString "optionID"]
2223  [PyString "optionText"]
2224  [PyString "parameter"]
2225  [PyString "votesFor"]
2226  [PyString "votesMade"]
2227  [PyString "votesProxied"]
2228  [PyString "parameter1"]
2229  [PyString "parameter2"]
2230 
2231  */
2232 
2233 
2234 PyResult CorpRegistryBound::Handle_GetSanctionedActionsByCorporation(PyCallArgs &call) {
2235  // rows = sm.GetService('corp').GetSanctionedActionsByCorporation(eve.session.corpid, state)
2236  /*
2237 05:09:00 [CorpCallDump] Call Arguments:
2238 05:09:00 [CorpCallDump] Tuple: 2 elements
2239 05:09:00 [CorpCallDump] [ 0] Integer: 98000000
2240 05:09:00 [CorpCallDump] [ 1] Integer: 1
2241 */
2242  _log(CORP__CALL, "CorpRegistryBound::Handle_GetSanctionedActionsByCorporation()");
2243  call.Dump(CORP__CALL_DUMP);
2244 
2245  Call_TwoIntegerArgs args;
2246  if (!args.Decode(&call.tuple)) {
2247  codelog(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
2248  return nullptr;
2249  }
2250  /* this still needs work...used to show voting items in corp that 'mean something'
2251  *
2252  * if row.voteType in [const.voteItemUnlock,
2253  * const.voteCEO,
2254  * const.voteWar,
2255  * const.voteShares,
2256  * const.voteKickMember,
2257  * const.voteItemLockdown] and row.parameter == 0:
2258  * continue
2259  * voteType = self.voteTypes[row.voteType]
2260  * title = voteCases[row.voteCaseID].voteCaseText
2261  * description = voteCases[row.voteCaseID].description
2262  * expires = util.FmtDate(row.expires)
2263  * actedUpon = [localization.GetByLabel('UI/Generic/No'), localization.GetByLabel('UI/Generic/Yes')][row.actedUpon]
2264  * inEffect = [localization.GetByLabel('UI/Generic/No'), localization.GetByLabel('UI/Generic/Yes')][row.inEffect]
2265  * rescended = localization.GetByLabel('UI/Generic/No')
2266  * if row.timeRescended:
2267  * rescended = localization.GetByLabel('UI/Corporations/CorpSanctionableActions/AnswerWithTimestamp', answer=rescended, timestamp=util.FmtDate(row.timeRescended))
2268  * if row.timeActedUpon:
2269  * actedUpon = localization.GetByLabel('UI/Corporations/CorpSanctionableActions/AnswerWithTimestamp', answer=actedUpon, timestamp=util.FmtDate(row.timeActedUpon))
2270  */
2271 
2272 
2273  return m_db.GetSanctionedItems(args.arg1, args.arg2);
2274 }
2275 
2276 PyResult CorpRegistryBound::Handle_CanVote(PyCallArgs &call) {
2277  // canVote = sm.GetService('corp').CanVote(self.corpID)
2278  _log(CORP__CALL, "CorpRegistryBound::Handle_CanVote() size=%u", call.tuple->size() );
2279  call.Dump(CORP__CALL_DUMP);
2280 
2281  return PyStatic.NewFalse();
2282 }
2283 
2284 
2285 PyResult CorpRegistryBound::Handle_InsertVote(PyCallArgs &call) {
2286  // return self.GetCorpRegistry().InsertVote(corporationID, voteCaseID, voteValue)
2287  _log(CORP__CALL, "CorpRegistryBound::Handle_InsertVote() size=%u", call.tuple->size() );
2288  call.Dump(CORP__CALL_DUMP);
2289 
2290  Call_InsertVote args;
2291  if (!args.Decode(&call.tuple)) {
2292  codelog(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
2293  return PyStatic.NewNone();
2294  }
2295 
2296  // can you change your vote? will we have to check for votes already cast and update them?
2297  m_db.CastVote(args.corpID, call.client->GetCharacterID(), args.voteCaseID, args.voteValue);
2298 
2299  // returns none
2300  return PyStatic.NewNone();
2301 }
2302 
2307 PyResult CorpRegistryBound::Handle_GetLockedItemLocations( PyCallArgs& call )
2308 { /*
2309  03:15:28 W CorpRegistryBound::Handle_GetLockedItemLocations(): size= 0
2310  03:15:28 [CorpCallDump] Call Arguments:
2311  03:15:28 [CorpCallDump] Tuple: Empty
2312  */
2313  // locationIDs = self.GetCorpRegistry().GetLockedItemLocations()
2314 
2315  // called from corp.assets.lockdown
2316  _log(CORP__CALL, "CorpRegistryBound::Handle_GetLockedItemLocations()");
2317  call.Dump(CORP__CALL_DUMP);
2318 
2319  //this returns an empty list for me on live.
2320  // ...because there are no locked items for your corp. :/
2321  return new PyList();
2322 }
2323 
2324 PyResult CorpRegistryBound::Handle_AddCorporateContact(PyCallArgs &call) {
2325  //self.GetCorpRegistry().AddCorporateContact(contactID, relationshipID)
2326  _log(CORP__CALL, "CorpRegistryBound::Handle_AddCorporateContact()");
2327  call.Dump(CORP__CALL_DUMP);
2328 
2329  Call_CorporateContactData args;
2330  if (!args.Decode(&call.tuple)) {
2331  codelog(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
2332  return nullptr;
2333  }
2334 
2335  m_db.AddContact(m_corpID, args);
2336 
2337  return nullptr;
2338 }
2339 
2340 PyResult CorpRegistryBound::Handle_EditCorporateContact(PyCallArgs &call) {
2341  //self.GetCorpRegistry().EditCorporateContact(contactID, relationshipID)
2342  _log(CORP__CALL, "CorpRegistryBound::Handle_EditCorporateContact()");
2343  call.Dump(CORP__CALL_DUMP);
2344 
2345  Call_CorporateContactData args;
2346  if (!args.Decode(&call.tuple)) {
2347  codelog(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
2348  return nullptr;
2349  }
2350 
2351  m_db.UpdateContact(args.relationshipID, args.contactID, m_corpID);
2352 
2353  return nullptr;
2354 }
2355 
2356 PyResult CorpRegistryBound::Handle_EditContactsRelationshipID(PyCallArgs &call) {
2357  //self.GetCorpRegistry().EditContactsRelationshipID(contactIDs, relationshipID)
2358  _log(CORP__CALL, "CorpRegistryBound::Handle_EditContactsRelationshipID()");
2359  call.Dump(CORP__CALL_DUMP);
2360 
2361  Call_EditCorporateContacts args;
2362  if (!args.Decode(&call.tuple)) {
2363  codelog(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
2364  return nullptr;
2365  }
2366 
2367  for (PyList::const_iterator itr = args.contactIDs->begin(); itr != args.contactIDs->end(); ++itr) {
2368  m_db.UpdateContact(args.relationshipID, PyRep::IntegerValueU32(*itr), m_corpID);
2369  }
2370 
2371  return nullptr;
2372 }
2373 
2374 PyResult CorpRegistryBound::Handle_RemoveCorporateContacts(PyCallArgs &call) {
2375  // self.GetCorpRegistry().RemoveCorporateContacts(contactIDs)
2376  _log(CORP__CALL, "CorpRegistryBound::Handle_RemoveCorporateContacts()");
2377  call.Dump(CORP__CALL_DUMP);
2378 
2379  Call_RemoveCorporateContacts args;
2380  if (!args.Decode(&call.tuple)) {
2381  codelog(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
2382  return nullptr;
2383  }
2384 
2385  for (PyList::const_iterator itr = args.contactIDs->begin(); itr != args.contactIDs->end(); ++itr) {
2386  m_db.RemoveContact(PyRep::IntegerValueU32(*itr), m_corpID);
2387  }
2388 
2389  return nullptr;
2390 }
2391 
2392 // this is a member role/title update by memberIDs called from corp->members->find in role->task mgmt
2393 PyResult CorpRegistryBound::Handle_ExecuteActions(PyCallArgs &call) {
2394  // verb, property, value = action
2395  // remoteActions.append(action)
2396  // return self.GetCorpRegistry().ExecuteActions(targetIDs, remoteActions)
2397  _log(CORP__CALL, "CorpRegistryBound::Handle_ExecuteActions() size=%u", call.tuple->size() );
2398  call.Dump(CORP__CALL_DUMP);
2399 
2400  Call_ExecuteActions args;
2401  if (!args.Decode(&call.tuple)) {
2402  codelog(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
2403  return nullptr;
2404  }
2405  args.Dump(CORP__TRACE);
2406 
2407  /*
2408  * args.memberIDs = list of charIDs to update
2409  * args.verb = one of add, remove, set, give
2410  * args.queryType = all role* types or title
2411  * args.value = roleMask or titleID
2412  */
2413 
2414  return nullptr;
2415 }
2416 
2417 PyResult CorpRegistryBound::Handle_CreateLabel(PyCallArgs &call) {
2418  // return self.GetCorpRegistry().CreateLabel(name, color)
2419  _log(CORP__CALL, "CorpRegistryBound::Handle_CreateLabel() size=%u", call.tuple->size() );
2420  call.Dump(CORP__CALL_DUMP);
2421 
2422  return nullptr;
2423 }
2424 
2425 PyResult CorpRegistryBound::Handle_DeleteLabel(PyCallArgs &call) {
2426  // self.GetCorpRegistry().DeleteLabel(labelID)
2427  _log(CORP__CALL, "CorpRegistryBound::Handle_DeleteLabel() size=%u", call.tuple->size() );
2428  call.Dump(CORP__CALL_DUMP);
2429 
2430  return nullptr;
2431 }
2432 
2433 PyResult CorpRegistryBound::Handle_EditLabel(PyCallArgs &call) {
2434  // self.GetCorpRegistry().EditLabel(labelID, name, color)
2435  _log(CORP__CALL, "CorpRegistryBound::Handle_EditLabel() size=%u", call.tuple->size() );
2436  call.Dump(CORP__CALL_DUMP);
2437 
2438  return nullptr;
2439 }
2440 
2441 PyResult CorpRegistryBound::Handle_AssignLabels(PyCallArgs &call) {
2442  // self.GetCorpRegistry().AssignLabels(contactIDs, labelMask)
2443  _log(CORP__CALL, "CorpRegistryBound::Handle_AssignLabels() size=%u", call.tuple->size() );
2444  call.Dump(CORP__CALL_DUMP);
2445 
2446  return nullptr;
2447 }
2448 
2449 PyResult CorpRegistryBound::Handle_RemoveLabels(PyCallArgs &call) {
2450  // self.GetCorpRegistry().RemoveLabels(contactIDs, labelMask)
2451  _log(CORP__CALL, "CorpRegistryBound::Handle_RemoveLabels() size=%u", call.tuple->size() );
2452  call.Dump(CORP__CALL_DUMP);
2453 
2454  return nullptr;
2455 }
2456 
2457 PyResult CorpRegistryBound::Handle_CreateAlliance(PyCallArgs &call) {
2458  //self.GetCorpRegistry().CreateAlliance(allianceName, shortName, description, url)
2459  _log(CORP__CALL, "CorpRegistryBound::Handle_CreateAlliance() size=%u", call.tuple->size() );
2460  call.Dump(CORP__CALL_DUMP);
2461 
2462  AllianceDB a_db;
2463  Client* pClient(call.client);
2464 
2465  Call_CreateAlliance args;
2466  if (!args.Decode(&call.tuple)) {
2467  codelog(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
2468  return nullptr;
2469  }
2470  args.Dump(CORP__TRACE);
2471 
2472  // verify they're not using bad words in their alliance name
2473  for (const auto cur : badWords)
2474  if (EvE::icontains(args.allianceName, cur))
2475  throw CustomError ("Alliance Name contains banned words");
2476 
2477  // this hits db directly, so test for possible sql injection code
2478  for (const auto cur : badCharsSearch)
2479  if (EvE::icontains(args.allianceName, cur))
2480  throw CustomError ("Alliance Name contains invalid characters");
2481 
2482  // this hits db directly, so test for possible sql injection code
2483  for (const auto cur : badCharsSearch)
2484  if (EvE::icontains(args.shortName, cur))
2485  throw CustomError ("Alliance short name contains invalid characters");
2486 
2487  // verify short name is available
2488  if (a_db.IsShortNameTaken(args.shortName))
2489  throw CustomError ("Alliance short name is taken.");
2490 
2491  double ally_cost = sConfig.rates.allyCost;
2492  if (pClient->GetBalance(Account::CreditType::ISK) < ally_cost) {
2493  _log(SERVICE__ERROR, "%s: Cannot afford alliance startup costs!", pClient->GetName());
2494 
2495  // send error to client here
2496  throw CustomError ("You must have %f ISK to create an alliance.", ally_cost);
2497  return nullptr;
2498  }
2499 
2500  //take the money, send wallet blink event record the transaction in their journal.
2501  std::string reason = "DESC: Creating new alliance: ";
2502  reason += args.allianceName;
2503  reason += " (";
2504  reason += args.shortName;
2505  reason += ")";
2507  pClient->GetCharacterID(),
2508  m_db.GetStationOwner(pClient->GetStationID()), // station owner files paperwork, this is fee for that
2509  ally_cost,
2510  reason.c_str(),
2512  pClient->GetStationID(),
2514 
2515  //creating an alliance will affect eveStaticOwners, so we gotta invalidate the cache...
2516  // call to db.AddCorporation() will update eveStaticOwners with new corp
2517  PyString* cache_name = new PyString( "config.StaticOwners" );
2518  m_manager->cache_service->InvalidateCache( cache_name );
2519  PySafeDecRef( cache_name );
2520 
2521  // Register new alliance (also gather current corpID and new allyID at same time)
2522  uint32 allyID(0);
2523  uint32 corpID(0);
2524  if (!a_db.CreateAlliance(args, pClient, allyID, corpID)) {
2525  codelog(SERVICE__ERROR, "New alliance creation failed.");
2526  return nullptr;
2527  }
2528 
2529  // create alliance channel
2531 
2532  // join corporation to alliance
2533  if (!a_db.UpdateCorpAlliance(allyID, corpID)) {
2534  codelog(SERVICE__ERROR, "Alliance join failed.");
2535  return nullptr;
2536  }
2537 
2538  // Add alliance membership record to corporation
2539  if (!a_db.AddEmployment(allyID, corpID)) {
2540  codelog(SERVICE__ERROR, "Add corp employment failed.");
2541  return nullptr;
2542  }
2543 
2544  // Update alliance ID on client session
2545  pClient->UpdateSessionInt("allianceid", allyID);
2546 
2547  //Return alliance we just created
2548  return a_db.GetAlliance(allyID);
2549 }
2550 
2551 PyResult CorpRegistryBound::Handle_ApplyToJoinAlliance(PyCallArgs &call) {
2552  _log(CORP__CALL, "CorpRegistryBound::Handle_ApplyToJoinAlliance()");
2553  call.Dump(CORP__CALL_DUMP);
2554 
2555  AllianceDB a_db;
2556 
2557  Call_ApplyToJoinAlliance args;
2558  if (!args.Decode(&call.tuple)) {
2559  codelog(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
2560  return nullptr;
2561  }
2562  args.Dump(CORP__TRACE);
2563 
2565  app.appText = args.applicationText;
2566  app.allyID = args.allianceID;
2567  app.corpID = m_corpID;
2569  app.valid = true;
2570 
2571  if (!a_db.InsertApplication(app)) {
2572  codelog(SERVICE__ERROR, "New alliance application failed.");
2573  return nullptr;
2574  }
2575 
2577  oldInfo.valid = false;
2578 
2579  OnAllianceApplicationChanged oaac;
2580  oaac.corpID = m_corpID;
2581  oaac.allianceID = app.allyID;
2582 
2583  AllianceBound::FillOAApplicationChange(oaac, oldInfo, app);
2584 
2585  //Send to everyone who needs to see it in the applying corp and in the alliance executor corp
2586  uint32 executorID = AllianceDB::GetExecutorID(app.allyID);
2587 
2588  std::vector<Client*> list;
2589  sEntityList.GetCorpClients(list, oaac.corpID);
2590  for (auto cur : list)
2591  {
2592  if (cur != nullptr)
2593  {
2594  cur->SendNotification("OnAllianceApplicationChanged", "clientID", oaac.Encode(), false);
2595  _log(ALLY__TRACE, "OnAllianceApplicationChanged sent to %s (%u)", cur->GetName(), cur->GetCharID());
2596  }
2597  }
2598 
2599  list.clear();
2600  sEntityList.GetCorpClients(list, executorID);
2601  for (auto cur : list)
2602  {
2603  if (cur != nullptr)
2604  {
2605  cur->SendNotification("OnAllianceApplicationChanged", "clientID", oaac.Encode(), false);
2606  _log(ALLY__TRACE, "OnAllianceApplicationChanged sent to %s (%u)", cur->GetName(), cur->GetCharID());
2607  }
2608  }
2609 
2612  std::string subject = "New application from ";
2613  subject += call.client->GetName();
2614  std::vector<int32> recipients;
2615  recipients.push_back(m_db.GetCorporationCEO(AllianceDB::GetExecutorID(app.allyID)));
2616  m_manager->lsc_service->SendMail(m_db.GetCorporationCEO(m_corpID), recipients, subject, args.applicationText);
2617 
2618  return nullptr;
2619 }
2620 
2621 PyResult CorpRegistryBound::Handle_GetAllianceApplications(PyCallArgs &call) {
2622  //application = sm.GetService('corp').GetAllianceApplications()[allianceID]
2623  _log(CORP__CALL, "CorpRegistryBound::Handle_GetAllianceApplications()");
2624  call.Dump(CORP__CALL_DUMP);
2625 
2626  AllianceDB a_db;
2627  return a_db.GetMyApplications(m_corpID);
2628 
2629  return nullptr;
2630 }
2631 
2632 PyResult CorpRegistryBound::Handle_DeleteAllianceApplication(PyCallArgs &call) {
2633  _log(CORP__CALL, "CorpRegistryBound::Handle_DeleteAllianceApplication()");
2634  call.Dump(CORP__CALL_DUMP);
2635 
2636  //This is not implemented by client, no context menu option
2637 
2638  AllianceDB a_db;
2639 
2640  Call_SingleIntegerArg args;
2641  if (!args.Decode(&call.tuple)) {
2642  codelog(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
2643  return nullptr;
2644  }
2645  args.Dump(CORP__TRACE);
2646 
2647  //Old application info
2649 
2650  if (!a_db.GetCurrentApplicationInfo(args.arg, call.client->GetCorporationID(), oldInfo))
2651  {
2652  _log(SERVICE__ERROR, "%s: Failed to query application for corp %u alliance %u", call.client->GetName(), call.client->GetCorporationID(), args.arg);
2653  return nullptr;
2654  }
2655 
2656  //New application info (set deleted flag to true here)
2657  Alliance::ApplicationInfo newInfo = oldInfo;
2658  newInfo.valid = true;
2659  newInfo.deleted = true;
2660 
2661  OnAllianceApplicationChanged oaac;
2662  oaac.allianceID = newInfo.allyID;
2663  oaac.corpID = newInfo.corpID;
2664  AllianceBound::FillOAApplicationChange(oaac, oldInfo, newInfo);
2665 
2666  if (!a_db.DeleteApplication(newInfo)) {
2667  codelog(SERVICE__ERROR, "Deletion failed.");
2668  return nullptr;
2669  }
2670 
2671  //Send to everyone who needs to see it in the applying corp and in the alliance executor corp
2672  uint32 executorID = AllianceDB::GetExecutorID(oaac.allianceID);
2673 
2674  std::vector<Client *> list;
2675  sEntityList.GetCorpClients(list, oaac.corpID);
2676  for (auto cur : list)
2677  {
2678  if (cur->GetChar().get() != nullptr)
2679  {
2680  cur->SendNotification("OnAllianceApplicationChanged", "clientID", oaac.Encode(), false);
2681  _log(ALLY__TRACE, "OnAllianceApplicationChanged sent to client %u", cur->GetClientID());
2682  }
2683  }
2684 
2685  list.clear();
2686  sEntityList.GetCorpClients(list, executorID);
2687  for (auto cur : list)
2688  {
2689  if (cur->GetChar().get() != nullptr)
2690  {
2691  cur->SendNotification("OnAllianceApplicationChanged", "clientID", oaac.Encode(), false);
2692  _log(ALLY__TRACE, "OnAllianceApplicationChanged sent to client %u", cur->GetClientID());
2693  }
2694  }
2695 
2696  return nullptr;
2697 }
2698 
2699 PyResult CorpRegistryBound::Handle_GetRentalDetailsPlayer(PyCallArgs &call) {
2700  //return self.GetCorpRegistry().GetRentalDetailsPlayer()
2701  _log(CORP__CALL, "CorpRegistryBound::Handle_GetRentalDetailsPlayer()");
2702  call.Dump(CORP__CALL_DUMP);
2703 
2704  return nullptr;
2705 }
2706 
2707 PyResult CorpRegistryBound::Handle_GetRentalDetailsCorp(PyCallArgs &call) {
2708  // return self.GetCorpRegistry().GetRentalDetailsCorp()
2709  _log(CORP__CALL, "CorpRegistryBound::Handle_GetRentalDetailsCorp()");
2710  call.Dump(CORP__CALL_DUMP);
2711 
2712  return nullptr;
2713 }
2714 
2715 PyResult CorpRegistryBound::Handle_UpdateCorporationAbilities(PyCallArgs &call) {
2716  _log(CORP__CALL, "CorpRegistryBound::Handle_UpdateCorporationAbilities()");
2717  call.Dump(CORP__CALL_DUMP);
2718 
2719  //this will need to update corp memberlimit, allowed races, and then update all members with new data
2720 
2721  return nullptr;
2722 }
2723 
2724 PyResult CorpRegistryBound::Handle_UpdateStationManagementSettings(PyCallArgs &call) {
2725  // self.corpStationMgr.UpdateStationManagementSettings(self.modifiedServiceAccessRulesByServiceID, self.modifiedServiceCostModifiers, self.modifiedRentableItems, self.station.stationName, self.station.description, self.station.dockingCostPerVolume, self.station.officeRentalCost, self.station.reprocessingStationsTake, self.station.reprocessingHangarFlag, self.station.exitTime, self.station.standingOwnerID)
2726 
2727  _log(CORP__CALL, "CorpRegistryBound::Handle_UpdateStationManagementSettings()");
2728  call.Dump(CORP__CALL_DUMP);
2729 
2730  // not real sure what this does yet....outpost shit maybe?
2731 
2732  return nullptr;
2733 }
2734 
2735 PyResult CorpRegistryBound::Handle_GetNumberOfPotentialCEOs(PyCallArgs &call) {
2736  // return self.GetCorpRegistry().GetNumberOfPotentialCEOs()
2737  _log(CORP__CALL, "CorpRegistryBound::Handle_GetNumberOfPotentialCEOs()");
2738  call.Dump(CORP__CALL_DUMP);
2739 
2740 
2741  return nullptr;
2742 }
2743 
2744 PyResult CorpRegistryBound::Handle_CanLeaveCurrentCorporation(PyCallArgs &call) {
2745  // canLeave, error, errorDetails = corpSvc.CanLeaveCurrentCorporation()
2746  // error: CrpCantQuitNotInStasis and canLeave=false for member that has roles
2747 
2748  PyTuple* tuple = new PyTuple(3);
2749  tuple->SetItem(0, PyStatic.NewTrue()); //canLeave - set this to timer or w/e to deter corp jumpers
2750  tuple->SetItem(1, PyStatic.NewNone());
2751  tuple->SetItem(2, PyStatic.NewNone());
2752 
2753  return tuple;
2754 }
2755 
2756 
2757 
Base Python wire object.
Definition: PyRep.h:66
#define sConfig
A macro for easier access to the singleton.
void SetAccountKey(int32 accountKey)
Definition: Character.cpp:435
uint32 GetStationOwner(uint32 stationID)
Dispatcher *const m_dispatch
unsigned __int8 uint8
Definition: eve-compat.h:46
void UpdateSessionInt(const char *sessionType, int value)
Definition: Client.cpp:1965
bool DeleteApplication(const Alliance::ApplicationInfo &aInfo)
Definition: AllianceDB.cpp:209
PyRep * GetCorporations(uint32 corpID)
void AddContact(uint32 ownerID, Call_CorporateContactData corpData)
void SendNotification(const PyAddress &dest, EVENotificationStream &noti, bool seq=true)
Definition: Client.cpp:2245
bool UpdateLogo(uint32 corpID, const Call_UpdateLogo &upd, PyDict *notif)
static std::string StringContent(PyRep *pRep)
Definition: PyRep.cpp:103
uint32 GetLocationID() const
Definition: Client.h:151
bool UpdateCorporation(uint32 corpID, const Call_UpdateCorporation &upd, PyDict *notif)
std::set< uint32 > corporations
Definition: EntityList.h:60
PyRep * GetMemberTrackingInfo(uint32 corpID)
const char * GetText(uint32 index) const
Definition: dbcore.h:104
void SendErrorMsg(const char *fmt,...)
Definition: Client.cpp:2719
#define _log(type, fmt,...)
Definition: logsys.h:124
int64 grantableRolesAtHQ
void AddRecruiters(uint16 adID, int32 corpID, std::vector< int32 > &charVec)
PyRep * GetItem(size_t index) const
Returns Python object.
Definition: PyRep.h:602
Python string.
Definition: PyRep.h:430
uint16 GetMemberCount(uint32 corpID)
PyRep * GetCorpRoleGroups()
int32 value() const
Definition: PyRep.h:247
PyRep * GetItemString(const char *key) const
Obtains database entry based on given key string.
Definition: PyRep.cpp:702
uint32 corpHQ
int32 GetInt(uint32 index) const
Definition: dbcore.cpp:635
PyRep * GetShares(uint32 corpID)
int64 GetCorpRole() const
Definition: Client.h:129
Python's dictionary.
Definition: PyRep.h:719
static int32 GetOfficeCount(uint32 corpID)
Definition: StationDB.cpp:38
int32 GetCorpHQ() const
Definition: Client.h:124
std::map< std::string, PyRep * > byname
Definition: PyCallable.h:51
size_t size() const
Definition: PyRep.h:591
static void EditBulletin(uint32 bulletinID, uint32 eCharID, int64 eDataTime, std::string &title, std::string &body)
Definition: AllianceDB.cpp:25
void DeleteAdvert(uint16 adID)
int64 rolesAtHQ
void RemoveContact(uint32 contactID, uint32 ownerID)
PyRep * GetLabels(uint32 corpID)
bool CreateMemberAttributeUpdate(uint32 newCorpID, uint32 charID, MemberAttributeUpdate &attrib)
int64 rolesAtBase
PyRep * GetMyShares(uint32 ownerID)
bool CreateCorporationCreatePacket(OnCorporationChanged &cc, uint32 oldCorpID, uint32 newCorpID)
PyRep * GetRecruiters(int32 corpID, uint16 adID)
void SendMail(uint32 sender, uint32 recipient, const std::string &subject, const std::string &content)
Definition: LSCService.h:64
std::string appText
Definition: CorpData.h:68
void SendInfoModalMsg(const char *fmt,...)
Definition: Client.cpp:2756
int32 GetCharacterID() const
Definition: Client.h:113
bool DeleteApplication(const Corp::ApplicationInfo &aInfo)
const_iterator begin() const
Definition: PyRep.h:660
PyRep * GetCorpRoles()
int32 GetCorporationID() const
Definition: Client.h:123
#define sEntityList
Definition: EntityList.h:208
storage_type::const_iterator const_iterator
Definition: PyRep.h:644
bool AddEmployment(uint32 allyID, uint32 corpID)
Definition: AllianceDB.cpp:299
static uint32 IntegerValueU32(PyRep *pRep)
Definition: PyRep.cpp:134
PyRep * GetKillsAndLosses(uint32 corpID, uint32 number, uint32 offset)
bool IsObject() const
Definition: PyRep.h:115
void AddBulletin(uint32 corpID, uint32 ownerID, uint32 cCharID, std::string &title, std::string &body)
void SendNotifyMsg(const char *fmt,...)
Definition: Client.cpp:2776
void UpdateContact(int32 relationshipID, uint32 contactID, uint32 ownerID)
static uint32 GetCorporationCEO(uint32 corpID)
CharacterRef GetChar() const
Definition: Client.h:164
Python tuple.
Definition: PyRep.h:567
Advanced version of UserError that allows to send a full custom message.
Definition: PyExceptions.h:453
void Dump(FILE *into, const char *pfx) const
Dumps object to file.
Definition: PyRep.cpp:84
int64 rolesAtOther
void CreateTitleData(uint32 corpID)
bool GetSearchValues(int8 op, PyRep *rep, std::ostringstream &query)
signed __int8 int8
Definition: eve-compat.h:45
bool IsList() const
Definition: PyRep.h:109
PyObject * GetCorporation(uint32 corpID)
void AddItem(PyRep *i)
Definition: PyRep.h:701
signed __int32 int32
Definition: eve-compat.h:49
PyRep * GetSharesForCorp(uint32 corpID)
void _SetCallDispatcher(CallDispatcher *d)
Definition: PyCallable.h:87
PyRep * GetItem(size_t index) const
Returns Python object.
Definition: PyRep.h:674
* args
static uint32 GetExecutorID(uint32 allyID)
Definition: AllianceDB.cpp:334
bool GetRow(DBResultRow &into)
Definition: dbcore.cpp:552
Python boolean.
Definition: PyRep.h:323
bool UpdateTitle(uint32 corpID, Call_UpdateTitleData &args, PyDict *updates)
void EditBulletin(uint32 bulletinID, uint32 eCharID, int64 eDataTime, std::string &title, std::string &body)
float taxRate
PyRep * GetApplications(uint32 corpID)
#define is_log_enabled(type)
Definition: logsys.h:78
uint16 GetCorpMemberCount(uint32 corpID)
PyRep * GetBulletins(uint32 corpID)
static PyRep * GetInfoWindowDataForChar(uint32 charID)
void CreateSystemChannel(int32 channelID)
Definition: LSCService.cpp:951
static const std::array< std::string, 28 > badWords
Definition: EVE_Consts.h:55
bool UpdateCorpAlliance(uint32 allyID, uint32 corpID)
Definition: AllianceDB.cpp:355
bool InsertApplication(Alliance::ApplicationInfo &aInfo)
Definition: AllianceDB.cpp:162
Python object.
Definition: PyRep.h:826
Definition: EVE_Corp.h:15
#define codelog(type, fmt,...)
Definition: logsys.h:128
void SetItem(size_t index, PyRep *object)
Stores Python object.
Definition: PyRep.h:610
PyRep * GetAdvert(uint16 adID)
PyRep * GetVotes(uint32 voteCaseID)
bool AddCorporation(Call_AddCorporation &corpInfo, Client *pClient, uint32 &corpID)
PyRep * GetContacts(uint32 corpID)
PyList * AsList()
Definition: PyRep.h:140
std::string GetBindStr() const
static void TranserFunds(uint32 fromID, uint32 toID, double amount, std::string reason="", uint8 entryTypeID=Journal::EntryType::Undefined, uint32 referenceID=0, uint16 fromKey=Account::KeyType::Cash, uint16 toKey=Account::KeyType::Cash, Client *pClient=nullptr)
int64 rolesAtAll
Python integer.
Definition: PyRep.h:231
PyDict * AsDict()
Definition: PyRep.h:142
void CastVote(uint32 corpID, uint32 charID, uint32 voteCaseID, uint8 optionID)
PyRep * GetAlliance(uint32 allyID)
Definition: AllianceDB.cpp:58
PyRep * GetVoteOptions(uint32 voteCaseID)
CorporationDB & m_db
#define PyStatic
Definition: PyRep.h:1209
static void DeleteBulletin(uint32 bulletinID)
Definition: AllianceDB.cpp:34
const char * GetName() const
Definition: Client.h:94
static uint32 GetCorpID(uint32 charID)
#define IsPlayerCorp(itemID)
Definition: EVE_Defines.h:241
void DeleteTitle(uint32 corpID, uint16 titleID)
PyRep * PyHasShares(uint32 charID, uint32 corpID)
int64 corpRole
#define PyDecRef(op)
Definition: PyRep.h:57
Client *const client
Definition: PyCallable.h:49
#define IsCharacterID(itemID)
Definition: EVE_Defines.h:206
PyRep * GetTitles(uint32 corpID)
Python object "ccp_exceptions.UserError".
Definition: PyExceptions.h:121
#define PyCallable_REG_CALL(c, m)
Definition: PyServiceCD.h:78
Definition: Client.h:66
LSCService * lsc_service
Definition: PyServiceMgr.h:77
void clear()
Definition: PyRep.cpp:627
void GetMembersForQuery(std::ostringstream &query, std::vector< uint32 > &result)
unsigned __int32 uint32
Definition: eve-compat.h:50
#define PyIncRef(op)
Definition: PyRep.h:56
uint32 baseID
bool GetCurrentApplicationInfo(Corp::ApplicationInfo &aInfo)
void InvalidateCache(const PyRep *objectID)
void AddRoleHistory(uint32 corpID, uint32 charID, uint32 issuerID, int64 oldRoles, int64 newRoles, bool grantable)
#define IsCorp(itemID)
Definition: EVE_Defines.h:234
uint16 GetCorpMemberLimit(uint32 corpID)
float GetBalance(uint8 type=Account::CreditType::ISK)
Definition: Client.h:176
PyRep * GetMyApplications(uint32 allyID)
Definition: AllianceDB.cpp:86
PyObject * GetStations(uint32 corpID)
static int64 GetCorpRole(uint32 charID)
uint32 corporationID
void GetMembersPaged(uint32 corpID, uint8 page, DBQueryResult &res)
PyRep * GetMemberTrackingInfoSimple(uint32 corpID)
double GetFileTimeNow()
Definition: utils_time.cpp:84
PyRep * GetMyApplications(uint32 charID)
PyServiceMgr *const m_manager
Definition: PyBoundObject.h:53
PySubStruct * BindObject(Client *pClient, PyBoundObject *pObj, PyDict *dict=nullptr, PyDict *oid=nullptr)
signed __int64 int64
Definition: eve-compat.h:51
static const std::array< std::string, 16 > badCharsSearch
Definition: EVE_Consts.h:108
const_iterator end() const
Definition: PyRep.h:661
int16 corpAccountKey
PyObject * GetEveOwners(uint32 corpID)
bool UpdateApplication(const Corp::ApplicationInfo &aInfo)
void UpdateCorpData(CorpData &data)
Definition: Character.cpp:451
ObjCacheService * cache_service
Definition: PyServiceMgr.h:78
void JoinCorporation(const CorpData &data)
Definition: Character.cpp:426
void MoveShares(uint32 ownerID, uint32 corpID, Call_MoveShares &args)
void Dump(LogType type) const
Definition: PyCallable.cpp:81
bool IsTickerTaken(std::string ticker)
static void FillOAApplicationChange(OnAllianceApplicationChanged &OAAC, const Alliance::ApplicationInfo &Old, const Alliance::ApplicationInfo &New)
static void AddEmployment(uint32 charID, uint32 corpID, uint32 oldCorpID=0)
void AddItemEvent(uint32 corpID, uint32 charID, uint16 eTypeID)
void UpdateAdvert(uint16 adID, uint32 corpID, int64 typeMask, int8 days, uint16 members, std::string description, uint32 channelID, std::string title)
void DeleteBulletin(uint32 bulletinID)
size_t size() const
Definition: PyRep.h:663
#define PySafeDecRef(op)
Definition: PyRep.h:61
#define sItemFactory
Definition: ItemFactory.h:165
int32 GetStationID() const
Definition: Client.h:114
PyRep * GetAdRegistryData(int64 typeMask=0, bool inAlliance=false, int16 minMembers=0, uint16 maxMembers=12602)
static int64 IntegerValue(PyRep *pRep)
Definition: PyRep.cpp:118
PyRep * GetMember(uint32 charID)
static void FillOCApplicationChange(OnCorporationApplicationChanged &OCAC, const Corp::ApplicationInfo &Old, const Corp::ApplicationInfo &New)
bool UpdateDivisionNames(uint32 corpID, const Call_UpdateDivisionNames &divs, PyDict *notif)
CorpData GetCorpData()
Definition: Character.h:298
int64 grantableRoles
int64 GetAdvertTime(uint16 adID, uint32 corpID)
PyInt * AsInt()
Definition: PyRep.h:122
static double GetCorpBalance(uint32 corpID, uint16 accountKey)
Definition: AccountDB.cpp:69
int64 grantableRolesAtBase
int64 GetInt64(uint32 index) const
Definition: dbcore.cpp:670
Dispatcher *const m_dispatch
std::set< uint32 > locations
Definition: EntityList.h:59
int64 grantableRolesAtOther
static void SetCorpRole(uint32 charID, int64 role)
unsigned __int16 uint16
Definition: eve-compat.h:48
std::string ticker
void AddVoteCase(uint32 corpID, uint32 charID, Call_InsertVoteCase &args)
PyRep * GetSanctionedItems(uint32 corpID, uint8 status=0)
bool IsShortNameTaken(std::string shortName)
Definition: AllianceDB.cpp:405
CorporationDB uint32 corpID
const char * TypeString() const
Definition: PyRep.cpp:76
std::string name
bool InsertApplication(Corp::ApplicationInfo &aInfo)
Python list.
Definition: PyRep.h:639
static std::string GetCorpName(uint32 corpID)
void SetItemString(const char *key, PyRep *value)
SetItemString adds or sets a database entry.
Definition: PyRep.h:812
bool CreateAlliance(Call_CreateAlliance &allyInfo, Client *pClient, uint32 &allyID, uint32 &corpID)
Definition: AllianceDB.cpp:430
const char * GetName() const
Definition: PyBoundObject.h:44
bool icontains(std::string data, std::string toSearch, size_t pos=0)
Definition: misc.cpp:194
Python long integer.
Definition: PyRep.h:261
uint8 GetQueryType(std::string queryType)
uint32 CreateAdvert(Client *pClient, uint32 corpID, int64 typeMask, int8 days, uint16 members, std::string description, uint32 channelID, std::string title)
PyTuple * tuple
Definition: PyCallable.h:50
PyRep * GetVoteItems(uint32 corpID, uint8 status=0, uint8 maxLen=20)
bool GetCurrentApplicationInfo(uint32 allyID, uint32 corpID, Alliance::ApplicationInfo &aInfo)
Definition: AllianceDB.cpp:128