| 
					
				 | 
			
			
				@@ -47,6 +47,14 @@ void high_ascii(std::string &str) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   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; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -93,6 +101,15 @@ void Session::start(void) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 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::parse_auth(void) { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -152,6 +169,28 @@ void Session::dispatch_line(std::string line) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   std::string temp = clean_string(line); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // NOTE:  We get "TradeWars Game Server\n"  (Missing \r) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // We add the \r with our injection line. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (temp.find("TradeWars Game Server") != std::string::npos) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    to_client("\rTradeWars Proxy v2++ READY (~ to activate)\n\r"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // additional analysis needed here 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // state :  where are we, what is this line? 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // collect all data we can from the server.  (P1) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (temp.find("Selection (? for menu): ") != std::string::npos) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    char ch = temp[temp.length() - 1]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (ch >= 'A' && ch < 'Q') { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      BUGZ_LOG(warning) << "GAME " << ch << " activated!"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // "Selection (? for menu): ?" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // This gives us the current game that we're in. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // (excluding ?, #, ! and Q) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   BUGZ_LOG(info) << "SL: " << temp; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -171,10 +210,41 @@ void Session::process_lines(std::string &received) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   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(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        dispatch_line(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); 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -209,15 +279,6 @@ void Session::process_lines(std::string &received) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     // display on? 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     // to_client(line); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    // NOTE:  We get "TradeWars Game Server\n"  (Missing \r) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    // We add the \r with our injection line. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    // TODO(stevet): MOVE TO DEFAULT dispatcher 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    // our first injection 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    if (line.find("TradeWars Game Server") != std::string::npos) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      to_client("\rTradeWars Proxy v2++ READY (~ to activate)\n\r"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     // How should I handle \r in lines?  For now, remove it 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     // but LOG that we did. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -268,6 +329,7 @@ void Session::set_timer(void) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 void Session::reset_timer(void) { timer_.cancel(); } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 void Session::on_timer(const boost::system::error_code error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   if (error != boost::asio::error::operation_aborted) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     // Ok, VALID timeout 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -347,6 +409,21 @@ void Session::on_resolve( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+void Session::client_input(const std::string &input) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (active) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // do something amazing with the user's input. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (input == "\x1b" || input == "~") { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      std::string prompt = clean_string(get_prompt()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      BUGZ_LOG(debug) << "CI: ACTIVATE prompt shows: [" << prompt << "]"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (talk_direct) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    to_server(input); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  BUGZ_LOG(info) << "CI: " << input; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 void Session::client_read(void) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   auto self(shared_from_this()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -386,9 +463,8 @@ void Session::client_read(void) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             // Proxy Active? 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             // BOOST_LOG_NAMED_SCOPE("Session"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if (talk_direct) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-              to_server(read_buffer); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            BUGZ_LOG(info) << "CI: " << read_buffer; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            std::string line(read_buffer, length); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            client_input(line); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             // do_write(output); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           } 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -403,7 +479,7 @@ void Session::client_read(void) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-void Session::to_client(std::string message) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+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) 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -426,7 +502,7 @@ void Session::to_client(std::string message) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-void Session::to_server(std::string message) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+void Session::to_server(const std::string &message) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   auto self(shared_from_this()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   boost::asio::async_write( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       server_, boost::asio::buffer(message), 
			 |