The Battle for Wesnoth  1.17.10+dev
ban.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2008 - 2022
3  by Pauli Nieminen <paniemin@cc.hut.fi>
4  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 #include "config.hpp"
17 #include "filesystem.hpp"
18 #include "lexical_cast.hpp"
19 #include "log.hpp"
21 #include "serialization/parser.hpp"
24 #include "utils/general.hpp"
25 
26 #include "server/wesnothd/ban.hpp"
27 
28 #include <functional>
29 
30 namespace wesnothd
31 {
32 static lg::log_domain log_server("server");
33 #define ERR_SERVER LOG_STREAM(err, log_server)
34 #define LOG_SERVER LOG_STREAM(info, log_server)
35 #define DBG_SERVER LOG_STREAM(debug, log_server)
36 
37 std::ostream& operator<<(std::ostream& o, const banned& n)
38 {
39  return o << "IP: " << n.get_ip() <<
40  (n.get_nick().empty() ? "" : " nick: " + n.get_nick()) <<
41  " reason: '" << n.get_reason() << "'"
42  " start_time: " << n.get_human_start_time() <<
43  " end_time: " << n.get_human_end_time() <<
44  " issuer: " << n.get_who_banned();
45 }
46 
48 {
49  return (*a) > (*b);
50 }
51 
53 
55 {
56  return (this->*(active_))(a,b);
57 }
58 
60 {
61  return a->get_int_ip() < b->get_int_ip();
62 }
63 
64 const std::string banned::who_banned_default_ = "system";
65 
66 banned::banned(const std::string& ip)
67  : ip_(0)
68  , mask_(0)
69  , ip_text_()
70  , end_time_(0)
71  , start_time_(0)
72  , reason_()
73  , who_banned_(who_banned_default_)
74  , group_()
75  , nick_()
76 {
77  ip_mask pair = parse_ip(ip);
78  ip_ = pair.first;
79  mask_ = 0xFFFFFFFF;
80 }
81 
82 banned::banned(const std::string& ip,
83  const std::time_t end_time,
84  const std::string& reason,
85  const std::string& who_banned,
86  const std::string& group,
87  const std::string& nick)
88  : ip_(0)
89  , mask_(0)
90  , ip_text_(ip)
91  , end_time_(end_time)
92  , start_time_(std::time(0))
93  , reason_(reason)
94  , who_banned_(who_banned)
95  , group_(group)
96  , nick_(nick)
97 {
98  ip_mask pair = parse_ip(ip_text_);
99  ip_ = pair.first;
100  mask_ = pair.second;
101 }
102 
104  : ip_(0)
105  , mask_(0)
106  , ip_text_()
107  , end_time_(0)
108  , start_time_(0)
109  , reason_()
111  , group_()
112  , nick_()
113 {
114  read(cfg);
115 }
116 
117 ip_mask parse_ip(const std::string& ip)
118 {
119  // We use bit operations to construct the integer
120  // ip_mask is a pair: first is ip and second is mask
121  ip_mask ret;
122  ret.first = 0;
123  ret.second = 0;
124  std::vector<std::string> split_ip = utils::split(ip, '.');
125  if (split_ip.size() > 4) throw banned::error("Malformed ip address: " + ip);
126 
127  unsigned int shift = 4*8; // start shifting from the highest byte
128  //unsigned int mask = 0xFF000000;
129  const unsigned int complete_part_mask = 0xFF;
130  auto part = split_ip.begin();
131  bool wildcard = false;
132  do {
133  shift -= 8;
134  //mask >>= 8;
135  if(part == split_ip.end()) {
136  if(!wildcard)
137  throw banned::error("Malformed ip address: '" + ip + "'");
138  // Adding 0 to ip and mask is nop
139  // we can then break out of loop
140  break;
141  } else {
142  if(*part == "*") {
143  wildcard = true;
144  // Adding 0 to ip and mask is nop
145  } else {
146  // wildcard = false;
147  unsigned int part_ip = lexical_cast_default<unsigned int>(*part, complete_part_mask + 1);
148  if(part_ip > complete_part_mask) {
149  throw banned::error("Malformed ip address: '" + ip + "'");
150  }
151 
152  ret.first |= (part_ip << shift);
153  ret.second |= (complete_part_mask << shift);
154  }
155  }
156  ++part;
157  } while(shift);
158 
159  return ret;
160 }
161 
162 void banned::read(const config& cfg)
163 {
164  {
165  // parse ip and mask
166  ip_text_ = cfg["ip"].str();
167  ip_mask pair = parse_ip(ip_text_);
168  ip_ = pair.first;
169  mask_ = pair.second;
170  }
171 
172  nick_ = cfg["nick"].str();
173 
174  if(cfg.has_attribute("end_time")) {
175  end_time_ = cfg["end_time"].to_time_t(0);
176  }
177 
178  if(cfg.has_attribute("start_time")) {
179  start_time_ = cfg["start_time"].to_time_t(0);
180  }
181 
182  reason_ = cfg["reason"].str();
183 
184  // only overwrite defaults if exists
185  if(cfg.has_attribute("who_banned")) {
186  who_banned_ = cfg["who_banned"].str();
187  }
188 
189  if(cfg.has_attribute("group")) {
190  group_ = cfg["group"].str();
191  }
192 }
193 
194 void banned::write(config& cfg) const
195 {
196  cfg["ip"] = get_ip();
197  cfg["nick"] = get_nick();
198 
199  if(end_time_ > 0) {
200  std::stringstream ss;
201  ss << end_time_;
202  cfg["end_time"] = ss.str();
203  }
204 
205  if(start_time_ > 0) {
206  std::stringstream ss;
207  ss << start_time_;
208  cfg["start_time"] = ss.str();
209  }
210 
211  cfg["reason"] = reason_;
212 
214  cfg["who_banned"] = who_banned_;
215  }
216 
217  if(!group_.empty()) {
218  cfg["group"] = group_;
219  }
220 }
221 
222 std::string banned::get_human_start_time() const
223 {
224  if(start_time_ == 0) {
225  return "unknown";
226  }
227 
229 }
230 
231 std::string banned::get_human_end_time() const
232 {
233  if(end_time_ == 0) {
234  return "permanent";
235  }
236 
238 }
239 
240 std::string banned::get_human_time_span() const
241 {
242  if(end_time_ == 0) {
243  return "permanent";
244  }
245 
246  return lg::get_timespan(end_time_ - std::time(nullptr));
247 }
248 
249 bool banned::operator>(const banned& b) const
250 {
251  return end_time_ > b.get_end_time();
252 }
253 
254 unsigned int banned::get_mask_ip(unsigned int mask) const
255 {
256  return ip_ & mask & mask_;
257 }
258 
259 bool banned::match_ip(const ip_mask& pair) const
260 {
261  return (ip_ & mask_) == (pair.first & mask_);
262 }
263 
264 // Unlike match_ip this function takes both masks into account.
265 bool banned::match_ipmask(const ip_mask& pair) const
266 {
267  return (ip_ & mask_ & pair.second) == (pair.first & pair.second & mask_);
268 }
269 
271 {
272  if(filename_.empty() || !filesystem::file_exists(filename_)) {
273  return;
274  }
275 
276  LOG_SERVER << "Reading bans from " << filename_;
277  config cfg;
278  dirty_ = false;
280  read_gz(cfg, *ban_file);
281 
282  for(const config& b : cfg.child_range("ban")) {
283  try {
284  auto new_ban = std::make_shared<banned>(b);
285  assert(bans_.insert(new_ban).second);
286 
287  if (new_ban->get_end_time() != 0)
288  time_queue_.push(new_ban);
289  } catch(const banned::error& e) {
290  ERR_SERVER << e.message << " while reading bans";
291  }
292  }
293 
294  // load deleted too
295  if(const config& cfg_del = cfg.child("deleted")) {
296  for(const config& b : cfg_del.child_range("ban")) {
297  try {
298  auto new_ban = std::make_shared<banned>(b);
299  deleted_bans_.push_back(new_ban);
300  } catch(const banned::error& e) {
301  ERR_SERVER << e.message << " while reading deleted bans";
302  }
303  }
304  }
305 }
306 
308 {
309  if(filename_.empty() || !dirty_) {
310  return;
311  }
312 
313  LOG_SERVER << "Writing bans to " << filename_;
314  dirty_ = false;
315 
316  config cfg;
317  for(const auto& b : bans_) {
318  config& child = cfg.add_child("ban");
319  b->write(child);
320  }
321 
322  config& deleted = cfg.add_child("deleted");
323  for(const auto& db : deleted_bans_) {
324  config& child = deleted.add_child("ban");
325  db->write(child);
326  }
327 
329  config_writer writer(*ban_file, true);
330  writer.write(cfg);
331 }
332 
333 bool ban_manager::parse_time(const std::string& duration, std::time_t* time) const
334 {
335  if (!time) return false;
336 
337  if(duration.substr(0, 4) == "TIME") {
338  std::tm* loc;
339  loc = std::localtime(time);
340 
341  std::size_t number = 0;
342  for(auto i = duration.begin() + 4; i != duration.end(); ++i) {
343  if(is_digit(*i)) {
344  number = number * 10 + to_digit(*i);
345  } else {
346  switch(*i) {
347  case 'Y':
348  loc->tm_year = number;
349  break;
350  case 'M':
351  loc->tm_mon = number;
352  break;
353  case 'D':
354  loc->tm_mday = number;
355  break;
356  case 'h':
357  loc->tm_hour = number;
358  break;
359  case 'm':
360  loc->tm_min = number;
361  break;
362  case 's':
363  loc->tm_sec = number;
364  break;
365  default:
366  LOG_SERVER << "Invalid time modifier given: '" << *i << "'.";
367  break;
368  }
369  number = 0;
370  }
371  }
372  *time = mktime(loc);
373  return true;
374  }
375 
376  const auto time_itor = ban_times_.find(duration);
377 
378  std::string dur_lower;
379  try {
380  dur_lower = utf8::lowercase(duration);
381  } catch(const utf8::invalid_utf8_exception& e) {
382  ERR_SERVER << "While parsing ban command duration string, caught an invalid utf8 exception: " << e.what();
383  return false;
384  }
385 
386  if(dur_lower == "permanent" || duration == "0") {
387  *time = 0;
388  } else if(ban_times_.find(duration) != ban_times_.end()) {
389  *time += time_itor->second;
390  } else {
391  std::string::const_iterator i = duration.begin();
392  int number = -1;
393  for (std::string::const_iterator d_end = duration.end(); i != d_end; ++i) {
394  if (is_digit(*i))
395  {
396  if (number == -1) number = 0;
397  number = number * 10 + to_digit(*i);
398  } else {
399  if (number == -1) number = 1;
400  switch(*i)
401  {
402  case 'Y':
403  case 'y':
404  if (++i != d_end && tolower(*i) == 'e'
405  && ++i != d_end && tolower(*i) == 'a'
406  && ++i != d_end && tolower(*i) == 'r'
407  && ++i != d_end && tolower(*i) == 's') {
408  } else --i;
409  *time += number * 365*24*60*60; // a year;
410  break;
411  case 'M':
412  if (++i != d_end && tolower(*i) == 'i') {
413  if (++i != d_end && tolower(*i) == 'n'
414  && ++i != d_end && tolower(*i) == 'u'
415  && ++i != d_end && tolower(*i) == 't'
416  && ++i != d_end && tolower(*i) == 'e'
417  && ++i != d_end && tolower(*i) == 's') {
418  } else --i;
419  *time += number * 60;
420  break;
421  }
422  --i;
423  if (++i != d_end && tolower(*i) == 'o'
424  && ++i != d_end && tolower(*i) == 'n'
425  && ++i != d_end && tolower(*i) == 't'
426  && ++i != d_end && tolower(*i) == 'h'
427  && ++i != d_end && tolower(*i) == 's') {
428  } else --i;
429  *time += number * 30*24*60*60; // 30 days
430  break;
431  case 'D':
432  case 'd':
433  if (++i != d_end && tolower(*i) == 'a'
434  && ++i != d_end && tolower(*i) == 'y'
435  && ++i != d_end && tolower(*i) == 's') {
436  } else --i;
437  *time += number * 24*60*60;
438  break;
439  case 'H':
440  case 'h':
441  if (++i != d_end && tolower(*i) == 'o'
442  && ++i != d_end && tolower(*i) == 'u'
443  && ++i != d_end && tolower(*i) == 'r'
444  && ++i != d_end && tolower(*i) == 's') {
445  } else --i;
446  *time += number * 60*60;
447  break;
448  case 'm':
449  if (++i != d_end && tolower(*i) == 'o') {
450  if (++i != d_end && tolower(*i) == 'n'
451  && ++i != d_end && tolower(*i) == 't'
452  && ++i != d_end && tolower(*i) == 'h'
453  && ++i != d_end && tolower(*i) == 's') {
454  } else --i;
455  *time += number * 30*24*60*60; // 30 days
456  break;
457  }
458  --i;
459  if (++i != d_end && tolower(*i) == 'i'
460  && ++i != d_end && tolower(*i) == 'n'
461  && ++i != d_end && tolower(*i) == 'u'
462  && ++i != d_end && tolower(*i) == 't'
463  && ++i != d_end && tolower(*i) == 'e'
464  && ++i != d_end && tolower(*i) == 's') {
465  } else --i;
466  *time += number * 60;
467  break;
468  case 'S':
469  case 's':
470  if (++i != d_end && tolower(*i) == 'e'
471  && ++i != d_end && tolower(*i) == 'c'
472  && ++i != d_end && tolower(*i) == 'o'
473  && ++i != d_end && tolower(*i) == 'n'
474  && ++i != d_end && tolower(*i) == 'd'
475  && ++i != d_end && tolower(*i) == 's') {
476  } else --i;
477  *time += number;
478  break;
479  default:
480  return false;
481  break;
482  }
483  number = -1;
484  }
485  }
486 
487  if(is_digit(*--i)) {
488  *time += number * 60; // default to minutes
489  }
490  }
491 
492  return true;
493 }
494 
495 std::string ban_manager::ban(const std::string& ip,
496  const std::time_t& end_time,
497  const std::string& reason,
498  const std::string& who_banned,
499  const std::string& group,
500  const std::string& nick)
501 {
502  std::ostringstream ret;
503  try {
504  ban_set::iterator ban;
505  if((ban = bans_.find(std::make_shared<banned>(ip))) != bans_.end()) {
506  // Already exsiting ban for ip. We have to first remove it
507  ret << "Overwriting ban: " << (**ban) << "\n";
508  bans_.erase(ban);
509  }
510  } catch(const banned::error& e) {
511  ERR_SERVER << e.message << " while creating dummy ban for finding existing ban";
512  return e.message;
513  }
514 
515  try {
516  auto new_ban = std::make_shared<banned>(ip, end_time, reason, who_banned, group, nick);
517  bans_.insert(new_ban);
518  if(end_time != 0) {
519  time_queue_.push(new_ban);
520  }
521  ret << *new_ban;
522  } catch(const banned::error& e) {
523  ERR_SERVER << e.message << " while banning";
524  return e.message;
525  }
526 
527  dirty_ = true;
528  write();
529  return ret.str();
530 }
531 
532 void ban_manager::unban(std::ostringstream& os, const std::string& ip, bool immediate_write)
533 {
534  ban_set::iterator ban;
535  try {
536  ban = bans_.find(std::make_shared<banned>(ip));
537  } catch (const banned::error& e) {
538  ERR_SERVER << e.message;
539  os << e.message;
540  return;
541  }
542 
543  if(ban == bans_.end()) {
544  os << "There is no ban on '" << ip << "'.";
545  return;
546  }
547 
548  // keep ban entry still in memory
549  os << "Ban on '" << **ban << "' removed.";
550  // group bans don't get saved
551  if ((*ban)->get_group().empty()) deleted_bans_.push_back(*ban);
552  bans_.erase(ban);
553  dirty_ = true;
554  if(immediate_write) {
555  write();
556  }
557 }
558 
559 void ban_manager::unban_group(std::ostringstream& os, const std::string& group)
560 {
561  ban_set temp;
562  std::insert_iterator<ban_set> temp_inserter(temp, temp.begin());
563  std::remove_copy_if(bans_.begin(), bans_.end(), temp_inserter, [&group](const banned_ptr& p) { return p->match_group(group); });
564 
565  os << "Removed " << (bans_.size() - temp.size()) << " bans";
566  bans_.swap(temp);
567  dirty_ = true;
568  write();
569 }
570 
571 void ban_manager::check_ban_times(std::time_t time_now)
572 {
573  while(!time_queue_.empty()) {
574  banned_ptr ban = time_queue_.top();
575 
576  if(ban->get_end_time() > time_now) {
577  // No bans going to expire
578  DBG_SERVER << "ban " << ban->get_ip() << " not removed. time: " << time_now << " end_time "
579  << ban->get_end_time();
580  break;
581  }
582 
583  // This ban is going to expire so delete it.
584  LOG_SERVER << "Remove a ban " << ban->get_ip() << ". time: " << time_now << " end_time " << ban->get_end_time();
585  std::ostringstream os;
586  unban(os, ban->get_ip(), false);
587  time_queue_.pop();
588  }
589 
590  // Save bans if there is any new ones
591  write();
592 }
593 
594 void ban_manager::list_deleted_bans(std::ostringstream& out, const std::string& mask) const
595 {
596  if(deleted_bans_.empty()) {
597  out << "No removed bans found.";
598  return;
599  }
600 
601  ip_mask pair;
602  try {
603  pair = parse_ip(mask);
604  } catch(const banned::error& e) {
605  out << "parse error: " << e.message;
606  return;
607  }
608 
609  out << "DELETED BANS LIST";
610  for(deleted_ban_list::const_iterator i = deleted_bans_.begin(); i != deleted_bans_.end(); ++i) {
611  if((*i)->match_ipmask(pair)) {
612  out << "\n" << (**i);
613  }
614  }
615 }
616 
617 void ban_manager::list_bans(std::ostringstream& out, const std::string& mask)
618 {
619  expire_bans();
620  if(bans_.empty()) {
621  out << "No bans set.";
622  return;
623  }
624 
625  ip_mask pair;
626  try {
627  pair = parse_ip(mask);
628  } catch(const banned::error& e) {
629  out << "parse error: " << e.message;
630  return;
631  }
632 
633  out << "BAN LIST";
634  std::set<std::string> groups;
635 
636  for(const auto& b : bans_) {
637  if(b->get_group().empty()) {
638  if(b->match_ipmask(pair)) {
639  out << "\n" << *b;
640  }
641  } else {
642  groups.insert(b->get_group());
643  }
644  }
645 
646  // Don't list ban groups when looking for specific bans.
647  if(!groups.empty() && mask == "*") {
648  out << "\nban groups: ";
649 
650  out << *groups.begin();
651  std::ostream& (*fn)(std::ostream&, const std::string&) = &std::operator<<;
652  std::for_each(++groups.begin(), groups.end(),
653  std::bind(fn, std::bind(fn, std::ref(out), std::string(", ")), std::placeholders::_1));
654  }
655 }
656 
657 std::string ban_manager::is_ip_banned(const std::string& ip)
658 {
659  expire_bans();
660  ip_mask pair;
661  try {
662  pair = parse_ip(ip);
663  } catch (const banned::error&) {
664  return "";
665  }
666 
667  auto ban = std::find_if(bans_.begin(), bans_.end(), [pair](const banned_ptr& p) { return p->match_ip(pair); });
668  if (ban == bans_.end()) return "";
669  const std::string& nick = (*ban)->get_nick();
670  return (*ban)->get_reason() + (nick.empty() ? "" : " (" + nick + ")") + " (Remaining ban duration: " + (*ban)->get_human_time_span() + ")";
671 }
672 
674 {
675  ban_help_ = "ban <mask> <time> <reason>\n"
676  "The time format is: %d[%s[%d[%s[...]]]] where %s is a time"
677  " modifier: s or S (seconds), m (minutes), h or H (hours), d"
678  " or D (days), M (months) or y or Y (years) and %d is a number.\n"
679  "Permanent bans can be set with 'permanent' or '0' as the time"
680  " argument.\n";
681  auto itor = ban_times_.begin();
682  if(itor != ban_times_.end()) {
683  ban_help_ += "You can also use " + itor->first;
684  ++itor;
685  }
686  for(; itor != ban_times_.end(); ++itor) {
687  ban_help_ += std::string(", ") + itor->first;
688  }
689  if(!ban_times_.empty()) {
690  ban_help_ += " for standard ban times. (not combinable)\n";
691  }
692  ban_help_ += "ban 127.0.0.1 2h20m flooded lobby\n"
693  "kban suokko 5D flooded again\n"
694  "kban suokko Y One year ban for constant flooding";
695 }
696 
698 {
699  ban_times_.clear();
700  for(const config& bt : cfg.child_range("ban_time")) {
701  std::time_t duration = 0;
702  if(parse_time(bt["time"], &duration)) {
703  ban_times_.emplace(bt["name"], duration);
704  }
705  }
706 
707  init_ban_help();
708  if(filename_ != cfg["ban_save_file"]) {
709  dirty_ = true;
710  filename_ = cfg["ban_save_file"].str();
711  }
712 }
713 
715 {
716  try {
717  write();
718  } catch(...) {
719  DBG_SERVER << "Caught exception in ban_manager destructor: " << utils::get_unknown_exception_type();
720  }
721 }
722 
724  : bans_()
725  , deleted_bans_()
726  , time_queue_()
727  , ban_times_()
728  , ban_help_()
729  , filename_()
730  , dirty_(false)
731 {
732  init_ban_help();
733 }
734 
735 } // namespace wesnothd
bool(banned_compare_subnet::* compare_fn)(const banned_ptr &a, const banned_ptr &b) const
Definition: ban.hpp:48
#define LOG_SERVER
Definition: ban.cpp:34
bool match_ipmask(const ip_mask &ip) const
Definition: ban.cpp:265
#define DBG_SERVER
Definition: ban.cpp:35
std::string reason_
Definition: ban.hpp:66
std::string get_reason() const
Definition: ban.hpp:89
std::string get_timestamp(const std::time_t &t, const std::string &format)
Definition: log.cpp:267
config & child(config_key_type key, int n=0)
Returns the nth child with the given key, or a reference to an invalid config if there is none...
Definition: config.cpp:402
void write(const config &cfg)
std::string get_timespan(const std::time_t &t)
Definition: log.cpp:274
void load_config(const config &)
Definition: ban.cpp:697
banned(const std::string &ip, const std::time_t end_time, const std::string &reason, const std::string &who_banned=who_banned_default_, const std::string &group="", const std::string &nick="")
Definition: ban.cpp:82
bool less(const banned_ptr &a, const banned_ptr &b) const
Definition: ban.cpp:59
std::time_t start_time_
Definition: ban.hpp:65
New lexcical_cast header.
bool has_attribute(config_key_type key) const
Definition: config.cpp:211
#define a
void check_ban_times(std::time_t time_now)
Definition: ban.cpp:571
std::string is_ip_banned(const std::string &ip)
Definition: ban.cpp:657
static bool file_exists(const bfs::path &fpath)
Definition: filesystem.cpp:264
std::time_t get_end_time() const
Definition: ban.hpp:81
child_itors child_range(config_key_type key)
Definition: config.cpp:344
std::string get_human_end_time() const
Definition: ban.cpp:231
filesystem::scoped_istream istream_file(const std::string &fname, bool treat_failure_as_error)
STL namespace.
std::string get_unknown_exception_type()
Utility function for finding the type of thing caught with catch(...).
Definition: general.cpp:23
void read_gz(config &cfg, std::istream &file, abstract_validator *validator)
Might throw a std::ios_base::failure especially a gzip_error.
Definition: parser.cpp:683
Definitions for the interface to Wesnoth Markup Language (WML).
std::string group_
Definition: ban.hpp:68
filesystem::scoped_ostream ostream_file(const std::string &fname, std::ios_base::openmode mode, bool create_directory)
static compare_fn active_
Definition: ban.hpp:49
std::string filename_
Definition: action_wml.cpp:564
#define b
std::pair< unsigned int, unsigned int > ip_mask
Definition: ban.hpp:56
std::shared_ptr< banned > banned_ptr
Definition: ban.hpp:34
std::string get_who_banned() const
Definition: ban.hpp:97
void read(const config &)
Definition: ban.cpp:162
std::string nick_
Definition: ban.hpp:69
static lg::log_domain log_server("server")
void unban_group(std::ostringstream &os, const std::string &group)
Definition: ban.cpp:559
Class for writing a config out to a file in pieces.
void list_deleted_bans(std::ostringstream &out, const std::string &mask="*") const
Definition: ban.cpp:594
std::string ban(const std::string &, const std::time_t &, const std::string &, const std::string &, const std::string &, const std::string &="")
Definition: ban.cpp:495
bool operator()(const banned_ptr &a, const banned_ptr &b) const
Definition: ban.cpp:47
std::time_t end_time_
Definition: ban.hpp:64
std::string get_human_start_time() const
Definition: ban.cpp:222
std::unique_ptr< std::istream > scoped_istream
Definition: filesystem.hpp:39
ip_mask parse_ip(const std::string &ip)
Definition: ban.cpp:117
unsigned int mask() const
Definition: ban.hpp:113
std::unique_ptr< std::ostream > scoped_ostream
Definition: filesystem.hpp:40
std::size_t i
Definition: function.cpp:967
Thrown by operations encountering invalid UTF-8 data.
std::string who_banned_
Definition: ban.hpp:67
mock_party p
std::ostream & operator<<(std::ostream &o, const banned &n)
Definition: ban.cpp:37
void write(config &) const
Definition: ban.cpp:194
std::string get_nick() const
Definition: ban.hpp:100
std::set< banned_ptr, banned_compare_subnet > ban_set
Definition: ban.hpp:52
static const std::string who_banned_default_
Definition: ban.hpp:70
Declarations for File-IO.
std::string lowercase(const std::string &s)
Returns a lowercased version of the string.
Definition: unicode.cpp:52
unsigned int ip_
Definition: ban.hpp:61
config & add_child(config_key_type key)
Definition: config.cpp:514
#define ERR_SERVER
Definition: ban.cpp:33
void list_bans(std::ostringstream &out, const std::string &mask="*")
Definition: ban.cpp:617
void init_ban_help()
Definition: ban.cpp:673
bool match_ip(const ip_mask &ip) const
Definition: ban.cpp:259
std::vector< std::string > split(const config_attribute_value &val)
std::string get_ip() const
Definition: ban.hpp:92
void unban(std::ostringstream &os, const std::string &ip, bool immediate_write=true)
Definition: ban.cpp:532
bool parse_time(const std::string &duration, std::time_t *time) const
Parses the given duration and adds it to *time except if the duration is &#39;0&#39; or &#39;permanent&#39; in which ...
Definition: ban.cpp:333
Standard logging facilities (interface).
std::string message
Definition: exceptions.hpp:30
unsigned int get_mask_ip(unsigned int) const
Definition: ban.cpp:254
#define e
bool operator>(const banned &b) const
Definition: ban.cpp:249
std::string get_human_time_span() const
Definition: ban.cpp:240
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:60
static map_location::DIRECTION n
std::string::const_iterator iterator
Definition: tokenizer.hpp:25
bool operator()(const banned_ptr &a, const banned_ptr &b) const
Definition: ban.cpp:54
std::string ip_text_
Definition: ban.hpp:63
unsigned int mask_
Definition: ban.hpp:62