TheRaven/Connection.csharp

179 lines
7.7 KiB
Plaintext
Raw Permalink Normal View History

Converting to Git. Bazaar log was: ------------------------------------------------------------ revno: 6 committer: dev <dev@aninix.net> branch nick: TheRaven timestamp: Thu 2016-06-02 23:21:56 -0500 message: Updating to include dedicated raven user. Adding RavenExecute.Command() static function to handle OS integration. Updating RavenCommand to use Djinni package for mailing. ------------------------------------------------------------ revno: 5 committer: dev <dev@aninix.net> branch nick: TheRaven timestamp: Wed 2016-04-20 16:59:51 -0500 message: Updated Makefile to include OS dependencies Updated ircservermessage to fix dropped sections of searches from things like "r.image :blar:" Added new tinyURL feature -- WARNING: this requires that the OS has a script api-keys in the path that will return an API key for the TinyURL service ------------------------------------------------------------ revno: 4 committer: dev <dev@aninix.net> branch nick: TheRaven timestamp: Mon 2016-03-28 14:40:00 -0500 message: MailerCount is now added to limit the number of pages sent to admins. ------------------------------------------------------------ revno: 3 committer: ircd <ircd@aninix.net> branch nick: TheRaven timestamp: Fri 2016-01-15 14:36:54 -0600 message: Removing an unneeded file -- requests are tracked in keep.google.com now Makefile had a run rule added to run the bot in the foreground with the verbose flag. This prevents the user from accidentally compiling and installing TheRaven with higher verbosity and filling system logs. Ravencommand was modified to check for user modes r (registerd on UnrealIRCd) or G (registered on InspIRCd) before running whitelist commands. connection.csharp had functions added to check for users being authenticated (IRC response code 330 in a WHOIS request) and do get modes ------------------------------------------------------------ revno: 2 committer: root <root@aninix.net> branch nick: TheRaven timestamp: Mon 2015-12-14 14:58:02 -0600 message: Updated commenting Removed requests file in favor of keep.google.com Updated ircservermessage.csharp et. al. for better verbosity options Edited connection.csharp to not need a Raven instance and instead take host and port Updated private globals to standard Moved Verbosity enum to not be inside ReportMessage class ------------------------------------------------------------ revno: 1 committer: ircd <ircd@aninix.net> branch nick: TheRaven timestamp: Thu 2015-12-10 21:58:41 -0600 message: Adding all my files.
2016-08-04 11:08:14 -05:00
using System;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Text;
using System.Threading;
using AniNIX.Shared;
Converting to Git. Bazaar log was: ------------------------------------------------------------ revno: 6 committer: dev <dev@aninix.net> branch nick: TheRaven timestamp: Thu 2016-06-02 23:21:56 -0500 message: Updating to include dedicated raven user. Adding RavenExecute.Command() static function to handle OS integration. Updating RavenCommand to use Djinni package for mailing. ------------------------------------------------------------ revno: 5 committer: dev <dev@aninix.net> branch nick: TheRaven timestamp: Wed 2016-04-20 16:59:51 -0500 message: Updated Makefile to include OS dependencies Updated ircservermessage to fix dropped sections of searches from things like "r.image :blar:" Added new tinyURL feature -- WARNING: this requires that the OS has a script api-keys in the path that will return an API key for the TinyURL service ------------------------------------------------------------ revno: 4 committer: dev <dev@aninix.net> branch nick: TheRaven timestamp: Mon 2016-03-28 14:40:00 -0500 message: MailerCount is now added to limit the number of pages sent to admins. ------------------------------------------------------------ revno: 3 committer: ircd <ircd@aninix.net> branch nick: TheRaven timestamp: Fri 2016-01-15 14:36:54 -0600 message: Removing an unneeded file -- requests are tracked in keep.google.com now Makefile had a run rule added to run the bot in the foreground with the verbose flag. This prevents the user from accidentally compiling and installing TheRaven with higher verbosity and filling system logs. Ravencommand was modified to check for user modes r (registerd on UnrealIRCd) or G (registered on InspIRCd) before running whitelist commands. connection.csharp had functions added to check for users being authenticated (IRC response code 330 in a WHOIS request) and do get modes ------------------------------------------------------------ revno: 2 committer: root <root@aninix.net> branch nick: TheRaven timestamp: Mon 2015-12-14 14:58:02 -0600 message: Updated commenting Removed requests file in favor of keep.google.com Updated ircservermessage.csharp et. al. for better verbosity options Edited connection.csharp to not need a Raven instance and instead take host and port Updated private globals to standard Moved Verbosity enum to not be inside ReportMessage class ------------------------------------------------------------ revno: 1 committer: ircd <ircd@aninix.net> branch nick: TheRaven timestamp: Thu 2015-12-10 21:58:41 -0600 message: Adding all my files.
2016-08-04 11:08:14 -05:00
namespace AniNIX.TheRaven {
public class Connection : IDisposable {
private const int _ircReadTimeout = 200000; // We set this to the IRC mimimum of two minutes in microseconds
//These privates will be the socket we use.
private NetworkStream _networkStream = null; // This is the stream to use.
private TcpClient _tcpClient = null; // This is the TCP socket for the stream.
private StreamWriter _streamWriter = null; // This is the stream to write to
private StreamReader _streamReader = null; // This is the stream to read from
private String _host = null; // This is DNS name or IP of the host to talk to
private int _port = 0; // this is the port number to connect to
/// <summary>
/// Connect to the host, populating the socket from the configuration options
/// </summary>
public Connection(String host, int port) {
ReportMessage.Log(Verbosity.Verbose,String.Format("Connecting to host {0}...",host));
this._host = host;
this._port = port;
this._tcpClient = new TcpClient(this._host,this._port);
this._tcpClient.ReceiveTimeout = Connection._ircReadTimeout;
this._networkStream = this._tcpClient.GetStream();
this._streamWriter = new StreamWriter(this._networkStream);
this._streamReader = new StreamReader(this._networkStream);
ReportMessage.Log(Verbosity.VeryVerbose,"... Connected.");
}
/// <summary>
/// Reads a line from the socket
/// </summary>
/// <returns> A string read from the socket </returns>
public IRCServerMessage Read() {
String response = null;
while (response == null) {
try {
response = this._streamReader.ReadLine();
} catch (IOException e) { // If the socket times out, make sure the host is still alive.
try {
IRCPongMessage pingHost = new IRCPongMessage(String.Format("PING :{0}",this._host));
Write(pingHost);
response = this._streamReader.ReadLine();
} catch (IOException f) { // If we get this, then the socket is dead and we need to signal
throw new RavenTimedOutException(String.Format("{0}\n{1}\n",e.Message,f.Message));
}
}
if (response != null && response.Length > 3 && response.Substring(0,4).Equals("PING")) { // if the response is a PING message, PONG and read again.
IRCPongMessage pong = new IRCPongMessage(response);
Write(pong);
response = null;
}
}
IRCServerMessage readMessage = new IRCServerMessage(response);
ReportMessage.Log(Verbosity.VeryVerbose,readMessage.ToString());
return readMessage;
}
/// <summary>
/// Writes a line to the socket
/// </summary>
/// <param name="toWrite">
/// The string to write
/// </param>
public void Write(IRCMessage toWrite) {
ReportMessage.Log(Verbosity.VeryVerbose,toWrite.ToString());
this._streamWriter.WriteLine(String.Format("{0}\r\n",toWrite.GetOutgoingIRCString()));
this._streamWriter.Flush();
}
/// <summary>
/// Is the user logged in?
/// </summary>
/// <param name="userName">
/// The username to check
/// </param>
/// <returns>
/// A boolean value representing whether the user is logged in or not
/// </returns>
public bool IsLoggedIn(String userName) {
ReportMessage.Log(Verbosity.VeryVerbose,String.Format("Asking for user {0} login status.",userName));
String outgoing = String.Format("WHOIS {0}\r\n",userName);
ReportMessage.Log(Verbosity.VeryVerbose,String.Format("<<< {0}",outgoing.Trim()));
this._streamWriter.WriteLine(outgoing);
this._streamWriter.Flush();
String[] bySpace;
do {
String response = this._streamReader.ReadLine();
ReportMessage.Log(Verbosity.VeryVerbose,String.Format(">>> {0}",response));
bySpace = response.Split(' ');
if (bySpace.Length > 1 && bySpace[1].Equals("330")) {
ReportMessage.Log(Verbosity.VeryVerbose,String.Format("User {0} is authenticated.",userName));
return true;
}
} while (bySpace.Length < 2 || !bySpace[1].Equals("318"));
ReportMessage.Log(Verbosity.VeryVerbose,String.Format("User {0} is not authenticated.",userName));
return false;
}
/// <summary>
/// Get the modes for a user
/// </summary>
/// <param name="userName">
/// the username to check
/// </param>
/// <returns>
/// A string with the modes.
/// </returns>
public String GetModes(String userName) {
ReportMessage.Log(Verbosity.VeryVerbose,String.Format("Asking for user {0} mode.",userName));
String outgoing = String.Format("MODE {0}\r\n",userName);
ReportMessage.Log(Verbosity.VeryVerbose,String.Format("<<< {0}",outgoing.Trim()));
this._streamWriter.WriteLine(outgoing);
this._streamWriter.Flush();
String[] bySpace;
do {
String response = this._streamReader.ReadLine();
ReportMessage.Log(Verbosity.VeryVerbose,String.Format(">>> {0}",response));
bySpace = response.Split(' ');
if (bySpace.Length > 9 && bySpace[1].Equals("330")) {
ReportMessage.Log(Verbosity.VeryVerbose,String.Format("User {0} has modes {1}.",userName,bySpace[4]));
return bySpace[4];
}
} while (bySpace.Length < 2 || !bySpace[1].Equals("502"));
ReportMessage.Log(Verbosity.VeryVerbose,String.Format("Cannot get user modes -- not a netadmin.",userName));
return "";
}
/* CONNECTION NEEDS TO BE DISPOSABLE BECAUSE IT HOLDS A SOCKET */
/// <summary>
/// Clean up this Connection, implementing IDisposable
/// </summary>
public void Dispose() {
Dispose(true); // Dispose of this instance
GC.SuppressFinalize(this); //The Garbage Collector doesn't need to finalize it.
}
/// <summary>
/// Force the GarbageCollector to Dispose if programmer does not
/// </summary>
~Connection() {
Dispose(false);
ReportMessage.Log(Verbosity.Error,"Programmer forgot to dispose of Connection. Marking for Garbage Collector");
}
// This bool indicates whether we are disposed of yet or not
bool _isDisposed = false;
/// <summary>
/// Dispose of this Connection's resources responsibly.
/// </summary>
protected virtual void Dispose(bool disposing) {
if (!this._isDisposed) { //if we haven't already disposed of this, we should.
if (disposing) {
//No managed resources for this class.
}
// Cleaning unmanaged resources
this._streamReader.Dispose();
this._streamWriter.Dispose();
this._tcpClient.Close();
this._networkStream.Dispose();
}
this._isDisposed = true;
}
}
}