| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702 | 
							- #include <boost/bind.hpp>
 
- #include <iostream>
 
- #include <boost/format.hpp>
 
- // #include <boost/log/core.hpp>
 
- // #include <boost/log/trivial.hpp>
 
- #include <regex>
 
- #include "config.h"
 
- #include "logging.h"
 
- #include "session.h"
 
- #include <string>
 
- // #include <boost/log/attributes/named_scope.hpp>
 
- bool replace(std::string &str, const std::string &from, const std::string &to) {
 
-   size_t start_pos = str.find(from);
 
-   if (start_pos == std::string::npos)
 
-     return false;
 
-   do {
 
-     str.replace(start_pos, from.length(), to);
 
-   } while ((start_pos = str.find(from)) != std::string::npos);
 
-   return true;
 
- }
 
- bool replace(std::string &str, const char *from, const char *to) {
 
-   size_t start_pos = str.find(from);
 
-   if (start_pos == std::string::npos)
 
-     return false;
 
-   do {
 
-     str.replace(start_pos, strlen(from), to);
 
-   } while ((start_pos = str.find(from)) != std::string::npos);
 
-   return true;
 
- }
 
- void ansi_clean(std::string &str) {
 
-   static std::regex ansi_cleaner("\x1b\[[0-9;]*[A-Zmh]",
 
-                                  std::regex_constants::ECMAScript);
 
-   str = std::regex_replace(str, ansi_cleaner, "");
 
- }
 
- void high_ascii(std::string &str) {
 
-   static std::regex high_cleaner("[\x80-\xff]+",
 
-                                  std::regex_constants::ECMAScript);
 
-   str = std::regex_replace(str, high_cleaner, "#");
 
- }
 
- std::smatch ansi_newline(const std::string &str) {
 
-   static std::regex ansi_nl("\x1b\[[0-9;]*[JK]",
 
-                             std::regex_constants::ECMAScript);
 
-   std::smatch m;
 
-   std::regex_search(str, m, ansi_nl);
 
-   return m;
 
- }
 
- std::string clean_string(const std::string &source) {
 
-   // BOOST_LOG_NAMED_SCOPE("clean_string");
 
-   std::string clean = source;
 
-   replace(clean, "\n", "\\n");
 
-   replace(clean, "\r", "\\r");
 
-   replace(clean, "\b", "\\b");
 
-   // ANSI too
 
-   ansi_clean(clean);
 
-   // BUGZ_LOG(error) << "cleaned: " << clean;
 
-   high_ascii(clean);
 
-   replace(clean, "\x1b", "^");
 
-   return clean;
 
- }
 
- Session::Session(boost::asio::ip::tcp::socket socket,
 
-                  boost::asio::io_service &io_service, std::string hostname,
 
-                  std::string port)
 
-     : main(this), socket_(std::move(socket)), io_service_{io_service},
 
-       resolver_{io_service}, server_{io_service}, prompt_timer_{io_service},
 
-       keep_alive_{io_service}, host{hostname}, port{port} {
 
-   // server_sent = 0;
 
-   time_ms = stoi(from_config("prompt_timeout", "50"));
 
-   keepalive_secs = stoi(from_config("keepalive", "45"));
 
-   // director.push(new CoreDispatch((*this)));
 
- }
 
- void Session::start(void) {
 
-   // BOOST_LOG_NAMED_SCOPE();
 
-   // If I want the file and line number information, here's how to do it:
 
-   // BUGZ_LOG(info) << boost::format("(%1%:%2%) ") % __FILE__ % __LINE__
 
-   BUGZ_LOG(info) << "Session::start()";
 
-   auto self(shared_from_this());
 
-   // read_buffer.reserve(1024);
 
-   // do_write("Welcome!\n");
 
-   client_read();
 
- }
 
- Session::~Session() { BUGZ_LOG(info) << "~Session"; }
 
- /**
 
-  * Returns the current server prompt.
 
-  *
 
-  * NOTE:  This is the raw string from the server, so it can contain
 
-  * color codes.  Make sure you clean it before trying to test it for
 
-  * any text.
 
-  *
 
-  * @return const std::string&
 
-  */
 
- const std::string &Session::get_prompt(void) { return server_prompt; }
 
- void Session::set_prompt(const std::string &prompt) { server_prompt = prompt; }
 
- void Session::post(notifyFunc nf) {
 
-   if (nf) {
 
-     BUGZ_LOG(info) << "Session::post()";
 
-     io_service_.post(nf);
 
-   } else {
 
-     BUGZ_LOG(error) << "Session::post( nullptr )";
 
-   }
 
- }
 
- void Session::parse_auth(void) {
 
-   // how many nulls should I be seeing?
 
-   // \0user\0pass\0terminal/SPEED\0
 
-   // If I don't have a proper rlogin value here, it isn't going
 
-   // to work when I try to connect to the rlogin server.
 
-   if (rlogin_auth.size() > 10)
 
-     rlogin_name = rlogin_auth.c_str() + 1;
 
-   else
 
-     rlogin_name = "?";
 
- }
 
- void Session::on_connect(const boost::system::error_code error) {
 
-   // We've connected to the server!  WOOT WOOT!
 
-   // BOOST_LOG_NAMED_SCOPE("Session");
 
-   if (!error) {
 
-     BUGZ_LOG(info) << "Connected to " << host;
 
-     to_client("Connected...\n\r");
 
-     connected = true;
 
-     if (rlogin_auth[0] != 0) {
 
-       // Ok, the rlogin information was junk --
 
-       to_client("Let me make up some fake rlogin data for you...\n\r");
 
-       char temp[] = "\0test\0test\0terminal/9600\0";
 
-       std::string tmp(temp, sizeof(temp));
 
-       to_server(tmp);
 
-     } else {
 
-       to_server(rlogin_auth);
 
-     }
 
-     server_read();
 
-   } else {
 
-     // TODO:
 
-     std::string output =
 
-         str(boost::format("Failed to connect: %1%:%2%\n\r") % host % port);
 
-     to_client(output);
 
-     BUGZ_LOG(error) << "Failed to connect to " << host << ":" << port;
 
-     BUGZ_LOG(warning) << "socket.shutdown()";
 
-     socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both);
 
-   }
 
- }
 
- /**
 
-  * Called with the current line received from the server.
 
-  *
 
-  * This will do server parsing.  Sector/Ports/Connecting Sectors.
 
-  * Port status/inventory/%.
 
-  *
 
-  * See \ref split_lines()
 
-  * @param line
 
-  */
 
- void Session::on_server_line(const std::string &line) {
 
-   BUGZ_LOG(info) << "SL: [" << line << "]";
 
-   if (line.find("TradeWars Game Server   ") != std::string::npos) {
 
-     to_client("\rTradeWars Proxy v2++ READY (~ or ESC to activate)\n\r");
 
-     game = 0;
 
-     // reset "active game" -- we're back at the menu
 
-   }
 
-   // additional analysis needed here
 
-   // state :  where are we, what is this line?
 
-   // collect all data we can from the server.  (P1)
 
-   // "Selection (? for menu): ?"
 
-   // This gives us the current game that we're in.
 
-   // (excluding ?, #, ! and Q)
 
-   if (line.find("Selection (? for menu): ") != std::string::npos) {
 
-     char ch = line[line.length() - 1];
 
-     if (ch >= 'A' && ch < 'Q') {
 
-       game = ch;
 
-       BUGZ_LOG(warning) << "GAME " << game << " activated!";
 
-     }
 
-     // not needed (handled by above Game Server check).
 
-     if (ch == 'Q')
 
-       game = 0;
 
-   }
 
-   // should I have an internal emit_server_line for parsing sections?
 
-   // rather then having a weird state machine to track where we are?
 
-   if (emit_server_line)
 
-     emit_server_line(line);
 
- }
 
- /**
 
-  * Split server input into lines.
 
-  *
 
-  * @param line
 
-  */
 
- void Session::split_lines(std::string line) {
 
-   // Does this have \n\r still on it?  I don't want them.
 
-   // cleanup backspaces
 
-   size_t pos;
 
-   while ((pos = line.find('\b')) != std::string::npos) {
 
-     // backspace?  OK!  (unless)
 
-     if (pos == 0) {
 
-       // first character, so there's nothing "extra" to erase.
 
-       line = line.erase(pos, 1);
 
-     } else
 
-       line = line.erase(pos - 1, 2);
 
-   }
 
-   std::string temp = clean_string(line);
 
-   on_server_line(temp);
 
- }
 
- /*
 
- Call this with whatever we just received.
 
- That will allow me to send "just whatever I got"
 
- this time around, rather then trying to figure out
 
- what was just added to server_prompt.
 
- What about \r, \b ?  Should that "reset" the server_prompt?
 
- \r should not, because it is followed by \n (eventually)
 
- and that completes my line.
 
-  */
 
- void Session::process_lines(std::string &received) {
 
-   // break server_prompt into lines and send/process one by one.
 
-   size_t pos, rpos;
 
-   server_prompt.append(received);
 
-   // I also need to break on r"\x1b[\[0-9;]*JK", treat these like \n
 
-   while ((pos = server_prompt.find('\n', 0)) != std::string::npos) {
 
-     std::string line;
 
-     std::smatch m = ansi_newline(server_prompt);
 
-     if (!m.empty()) {
 
-       // We found one.
 
-       size_t mpos = m.prefix().length();
 
-       // int mlen = m[0].length();
 
-       if (mpos < pos) {
 
-         // Ok, the ANSI newline is before the \n
 
-         // perform this process with the received line
 
-         std::smatch rm = ansi_newline(received);
 
-         if (!rm.empty()) {
 
-           size_t rpos = rm.prefix().length();
 
-           int rlen = rm[0].length();
 
-           if (show_client) {
 
-             line = received.substr(0, rpos + rlen);
 
-             to_client(line);
 
-           }
 
-           received = rm.suffix();
 
-         }
 
-         // perform this on the server_prompt line
 
-         line = m.prefix();
 
-         split_lines(line);
 
-         server_prompt = m.suffix();
 
-         // redo this loop -- there's still a \n in there
 
-         continue;
 
-       }
 
-     }
 
-     // process "line" in received
 
-     rpos = received.find('\n', 0);
 
-     // get line to send to the client
 
-     if (show_client) {
 
-       // that is, if we're sending to the client!
 
-       line = received.substr(0, rpos + 1);
 
-       /*
 
-       std::string clean = clean_string(line);
 
-       BUGZ_LOG(error) << "rpos/show_client:" << clean;
 
-       */
 
-       to_client(line);
 
-     }
 
-     received = received.substr(rpos + 1);
 
-     // process "line" in server_prompt
 
-     line = server_prompt.substr(0, pos + 1);
 
-     server_prompt = server_prompt.substr(pos + 1);
 
-     // Remove \n for dispatching
 
-     std::string part = line.substr(0, pos);
 
-     /*
 
-     if (server_sent != 0) {
 
-       line = line.substr(server_sent);
 
-       server_sent = 0;
 
-     };
 
-     */
 
-     // display on?
 
-     // to_client(line);
 
-     // How should I handle \r in lines?  For now, remove it
 
-     // but LOG that we did.
 
-     replace(part, "\r", "");
 
-     /*
 
-     if (replace(part, "\r", "")) {
 
-       BUGZ_LOG(warning) << "\\r removed from line";
 
-     }
 
-     */
 
-     split_lines(part);
 
-   }
 
-   // Ok, we have sent all of the \n lines.
 
-   if (!received.empty())
 
-     if (show_client) {
 
-       to_client(received);
 
-       // std::string clean = clean_string(received);
 
-       // BUGZ_LOG(error) << "show_client/leftovers:" << clean;
 
-     }
 
-   // This is eating the entire string.  String is partial line
 
-   // portcim line, ending with '\r', this eats the line.
 
-   /*
 
-   // check the server prompt here:
 
-   if ((pos = server_prompt.rfind('\r')) != std::string::npos) {
 
-     // server_prompt contains \r, remove it.
 
-     server_prompt = server_prompt.substr(pos + 1);
 
-   }
 
-   */
 
-   while ((pos = server_prompt.find('\b')) != std::string::npos) {
 
-     // backspace?  OK!  (unless)
 
-     if (pos == 0) {
 
-       // first character, so there's nothing "extra" to erase.
 
-       server_prompt = server_prompt.erase(pos, 1);
 
-     } else
 
-       server_prompt = server_prompt.erase(pos - 1, 2);
 
-   }
 
-   if (!server_prompt.empty()) {
 
-     // We have something remaining -- start the timer!
 
-     set_prompt_timer();
 
-   }
 
- }
 
- void Session::set_prompt_timer(void) {
 
-   prompt_timer_.expires_after(std::chrono::milliseconds(time_ms));
 
-   prompt_timer_.async_wait(boost::bind(&Session::on_prompt_timeout, this,
 
-                                        boost::asio::placeholders::error));
 
- }
 
- void Session::reset_prompt_timer(void) { prompt_timer_.cancel(); }
 
- void Session::on_server_prompt(const std::string &prompt) {
 
-   BUGZ_LOG(warning) << "SP: [" << prompt << "]";
 
-   if (emit_server_prompt) {
 
-     emit_server_prompt(prompt);
 
-   }
 
- }
 
- void Session::on_prompt_timeout(const boost::system::error_code error) {
 
-   if (error != boost::asio::error::operation_aborted) {
 
-     // Ok, VALID timeout
 
-     if (!server_prompt.empty()) {
 
-       // Here's what is happening:
 
-       // SP: [ESC[2JESC[H]
 
-       // which after clean_string is empty.
 
-       std::string clean = clean_string(server_prompt);
 
-       if (!clean.empty()) {
 
-         on_server_prompt(clean);
 
-       }
 
-       // BUGZ_LOG(trace) << "SP: [" << server_prompt << "]";
 
-     }
 
-   }
 
- }
 
- void Session::server_read(void) {
 
-   auto self(shared_from_this());
 
-   boost::asio::async_read(
 
-       server_, boost::asio::buffer(server_buffer, sizeof(server_buffer) - 1),
 
-       boost::asio::transfer_at_least(1),
 
-       [this, self](boost::system::error_code ec, std::size_t length) {
 
-         if (!ec) {
 
-           server_buffer[length] = 0;
 
-           // server_prompt.append(server_buffer, length);
 
-           std::string received(server_buffer, length);
 
-           process_lines(received);
 
-           /*
 
-           I don't believe I need to consume this,
 
-           I'm not async_reading from a stream.
 
-           */
 
-           /*
 
-             if (length) {
 
-               // std::cout << length << std::endl;
 
-               std::cout << "S: " << server_buffer << std::endl;
 
-               do_write(server_buffer);
 
-             }
 
-             */
 
-           server_read();
 
-         } else {
 
-           BUGZ_LOG(warning) << "S: read_failed: socket.shutdown()";
 
-           socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both);
 
-         }
 
-       });
 
- }
 
- void Session::on_resolve(
 
-     const boost::system::error_code error,
 
-     const boost::asio::ip::tcp::resolver::results_type results) {
 
-   //
 
-   auto self(shared_from_this());
 
-   if (!error) {
 
-     // Take the first endpoint.
 
-     boost::asio::ip::tcp::endpoint const &endpoint = *results;
 
-     server_.async_connect(endpoint,
 
-                           boost::bind(&Session::on_connect, this,
 
-                                       boost::asio::placeholders::error));
 
-   } else {
 
-     // TO DO:
 
-     // BOOST_LOG_NAMED_SCOPE("Session");
 
-     BUGZ_LOG(error) << "Unable to resolve: " << host;
 
-     std::string output =
 
-         str(boost::format("Unable to resolve: %1%\n\r") % host);
 
-     to_client(output);
 
-     BUGZ_LOG(warning) << "socket.shutdown()";
 
-     socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both);
 
-   }
 
- }
 
- void Session::client_input(const std::string &input) {
 
-   BUGZ_LOG(info) << "CI: " << input;
 
-   // Is "proxy" active
 
-   if (active) {
 
-     // do something amazing with the user's input.
 
-   } else {
 
-     if (input == "\x1b" || input == "~") {
 
-       std::string prompt = clean_string(get_prompt());
 
-       BUGZ_LOG(trace) << "CI: ACTIVATE prompt shows: [" << prompt << "]";
 
-       if (prompt == "Selection (? for menu): ") {
 
-         to_client("\n\rThere's not much we can do here.  Activate in-game at a "
 
-                   "Command prompt.\n\r");
 
-         to_client(get_prompt());
 
-         return;
 
-       }
 
-       // easter-eggs:
 
-       if (prompt == "Enter your choice: ") {
 
-         to_client("\n\r\x1b[1;36mI'd choose \x1b[1;37m`T`\x1b[1;36m, but "
 
-                   "that's how I was coded.\n\r");
 
-         to_client(get_prompt());
 
-         return;
 
-       }
 
-       // easter-egg
 
-       if (prompt == "[Pause]") {
 
-         to_client(" \x1b[1;36mMeow\x1b[0m\n\r");
 
-         to_client(get_prompt());
 
-         return;
 
-       }
 
-       //
 
-       // The command prompt that we're looking for:
 
-       //
 
-       // "Command [TL=00:00:00]:[242] (?=Help)? : "
 
-       // the time, and the sector number vary...
 
-       if (prompt.substr(0, 9) == "Command [") {
 
-         int len = prompt.length();
 
-         if (prompt.substr(len - 14) == "] (?=Help)? : ") {
 
-           proxy_activate();
 
-           /*
 
-           to_client("\n\r\x1b[1;34mWELCOME!  This is where the proxy would "
 
-                     "activate.\n\r");
 
-           // active = true;
 
-           // show_client = true;  // because if something comes (unexpected)
 
-           // from the server? talk_direct = false;
 
-           // but we aren't activating (NNY)
 
-           to_client(get_prompt());
 
-           */
 
-           return;
 
-         }
 
-       }
 
-       // eat this input.
 
-       BUGZ_LOG(warning) << "CI: unable to activate, prompt was: [" << prompt
 
-                         << "]";
 
-       return;
 
-     }
 
-   }
 
-   // as the above code matures, talk_direct might get changed.
 
-   // keep this part here (and not above).
 
-   if (talk_direct) {
 
-     to_server(input);
 
-   }
 
-   if (emit_client_input) {
 
-     emit_client_input(input);
 
-   }
 
- }
 
- void Session::proxy_activate(void) {
 
-   active = true;
 
-   main.setNotify([this](void) { this->proxy_deactivate(); });
 
-   main.activate();
 
- }
 
- void Session::proxy_deactivate(void) {
 
-   // Ok, how do we return?
 
-   active = false;
 
-   to_client(get_prompt());
 
-   // to_client(" \b");
 
- }
 
- void Session::client_read(void) {
 
-   auto self(shared_from_this());
 
-   boost::asio::async_read( // why can't I async_read_some here?
 
-       socket_, boost::asio::buffer(read_buffer, sizeof(read_buffer) - 1),
 
-       boost::asio::transfer_at_least(1),
 
-       [this, self](boost::system::error_code ec, std::size_t length) {
 
-         if (!ec) {
 
-           read_buffer[length] = 0;
 
-           if (rlogin_auth.empty()) {
 
-             // first read should be rlogin information
 
-             rlogin_auth.assign(read_buffer, length);
 
-             // parse authentication information
 
-             parse_auth();
 
-             to_client(std::string(1, 0));
 
-             to_client("Welcome, ");
 
-             to_client(rlogin_name);
 
-             to_client("\n\r");
 
-             // Activate the connection to the server
 
-             /* // this fails, and I'm not sure why.  I've used code like this
 
-                before. resolver_.async_resolve( host, port, std::bind(
 
-                &Session::on_resolve, this, _1, _2)); */
 
-             // This example shows using boost::bind, which WORKS.
 
-             // https://stackoverflow.com/questions/6025471/bind-resolve-handler-to-resolver-async-resolve-using-boostasio
 
-             resolver_.async_resolve(
 
-                 host, port,
 
-                 boost::bind(&Session::on_resolve, this,
 
-                             boost::asio::placeholders::error,
 
-                             boost::asio::placeholders::iterator));
 
-           } else if (length) {
 
-             // Proxy Active?
 
-             // BOOST_LOG_NAMED_SCOPE("Session");
 
-             std::string line(read_buffer, length);
 
-             client_input(line);
 
-             // do_write(output);
 
-           }
 
-           client_read();
 
-         } else {
 
-           BUGZ_LOG(warning) << "CI: read_failed";
 
-           if (connected) {
 
-             BUGZ_LOG(warning) << "Server.shutdown()";
 
-             server_.shutdown(boost::asio::ip::tcp::socket::shutdown_both);
 
-           }
 
-         }
 
-       });
 
- }
 
- void Session::to_client(const std::string &message) {
 
-   auto self(shared_from_this());
 
-   // output the cleaned string (so I can see what we're sending in the
 
-   // logs)
 
-   std::string clean = clean_string(message);
 
-   BUGZ_LOG(trace) << "2C: " << clean;
 
-   boost::asio::async_write(
 
-       socket_, boost::asio::buffer(message),
 
-       [this, self](boost::system::error_code ec, std::size_t /*length*/) {
 
-         if (!ec) {
 
-         } else {
 
-           BUGZ_LOG(warning) << "2C: write failed? closed? Server.shutdown()";
 
-           if (connected) {
 
-             BUGZ_LOG(warning) << "Server.shutdown()";
 
-             server_.shutdown(boost::asio::ip::tcp::socket::shutdown_both);
 
-           }
 
-         }
 
-       });
 
- }
 
- void Session::to_server(const std::string &message) {
 
-   auto self(shared_from_this());
 
-   boost::asio::async_write(
 
-       server_, boost::asio::buffer(message),
 
-       [this, self](boost::system::error_code ec, std::size_t /*length*/) {
 
-         if (!ec) {
 
-         } else {
 
-           BUGZ_LOG(warning) << "S: write failed? closed? socket.shutdown()";
 
-           socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both);
 
-         }
 
-       });
 
-   // keep alive timer
 
-   keep_alive_.expires_after(std::chrono::seconds(keepalive_secs));
 
-   keep_alive_.async_wait(boost::bind(&Session::stayin_alive, this,
 
-                                      boost::asio::placeholders::error));
 
- }
 
- void Session::stayin_alive(const boost::system::error_code error) {
 
-   if (error != boost::asio::error::operation_aborted) {
 
-     // stayin' alive, stayin' alive...
 
-     to_server(" ");
 
-     BUGZ_LOG(warning) << "Session::stayin_alive()";
 
-   }
 
- }
 
- Server::Server(boost::asio::io_service &io_service,
 
-                const boost::asio::ip::tcp::endpoint &endpoint, std::string host,
 
-                std::string port)
 
-     : io_service_{io_service}, acceptor_{io_service_, endpoint}, host_{host},
 
-       port_{port} {
 
-   only_one = from_config("one_connection", "0") == "1";
 
-   BUGZ_LOG(info) << "Server::Server()";
 
-   do_accept();
 
- }
 
- Server::~Server() { BUGZ_LOG(info) << "Server::~Server()"; }
 
- /**
 
-  * setup async connect accept
 
-  *
 
-  * This creates a session for each connection.  Using make_shared allows the
 
-  * session to automatically clean up when it is no longer active/has anything
 
-  * running in the reactor.
 
-  */
 
- void Server::do_accept(void) {
 
-   acceptor_.async_accept([this](boost::system::error_code ec,
 
-                                 boost::asio::ip::tcp::socket socket) {
 
-     if (!ec) {
 
-       BUGZ_LOG(info) << "Server::do_accept()";
 
-       std::make_shared<Session>(std::move(socket), io_service_, host_, port_)
 
-           ->start();
 
-     }
 
-     if (!only_one) {
 
-       do_accept();
 
-     }
 
-   });
 
- }
 
- /**
 
-  * Clean up the trailing ../ in __FILE__
 
-  *
 
-  * This is used by the logging macro.
 
-  *
 
-  * @param filepath
 
-  * @return const char*
 
-  */
 
- const char *trim_path(const char *filepath) {
 
-   if (strncmp(filepath, "../", 3) == 0) {
 
-     filepath += 3;
 
-   }
 
-   return filepath;
 
- }
 
 
  |