using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using Tor.Helpers;
using System.ComponentModel;
namespace Tor.Controller
{
///
/// A class containing the command to retrieve router status information.
///
internal sealed class GetRouterStatusCommand : Command
{
private string identity;
///
/// Initializes a new instance of the class.
///
public GetRouterStatusCommand() : this(null)
{
}
///
/// Initializes a new instance of the class.
///
/// The router identity to retrieve status information for.
public GetRouterStatusCommand(string identity)
{
this.identity = identity;
}
#region Properties
///
/// Gets or sets the identity of the router.
///
public string Identity
{
get { return identity; }
}
#endregion
#region Tor.Controller.Command<>
///
/// Dispatches the command to the client control port and produces a response result.
///
///
///
/// A object instance containing the response data.
///
protected override GetRouterStatusResponse Dispatch(Connection connection)
{
if (identity == null)
return new GetRouterStatusResponse(false, null);
string request = string.Format("ns/id/{0}", identity);
if (connection.Write("getinfo {0}", request))
{
ConnectionResponse response = connection.Read();
if (!response.Success || !response.Responses[0].StartsWith(request, StringComparison.CurrentCultureIgnoreCase))
return new GetRouterStatusResponse(false, null);
Router router = null;
foreach (string line in response.Responses)
{
string stripped = line.Trim();
if (string.IsNullOrWhiteSpace(stripped))
continue;
if (stripped.StartsWith("r"))
{
string[] values = stripped.Split(' ');
if (values.Length < 9)
continue;
DateTime publication = DateTime.MinValue;
if (!DateTime.TryParse(string.Format("{0} {1}", values[4], values[5]), out publication))
publication = DateTime.MinValue;
int orPort = 0;
if (!int.TryParse(values[7], out orPort))
orPort = 0;
int dirPort = 0;
if (!int.TryParse(values[8], out dirPort))
dirPort = 0;
IPAddress ipAddress = null;
if (!IPAddress.TryParse(values[6], out ipAddress))
ipAddress = null;
router = new Router();
router.Digest = values[3];
router.DIRPort = dirPort;
router.Identity = values[2];
router.IPAddress = ipAddress;
router.Nickname = values[1];
router.ORPort = orPort;
router.Publication = publication;
continue;
}
if (stripped.StartsWith("s") && router != null)
{
string[] values = stripped.Split(' ');
for (int i = 1, length = values.Length; i < length; i++)
{
RouterFlags flag = ReflectionHelper.GetEnumerator(attr => values[i].Equals(attr.Description, StringComparison.CurrentCultureIgnoreCase));
if (flag != RouterFlags.None)
router.Flags |= flag;
}
continue;
}
if (stripped.StartsWith("w") && router != null)
{
string[] values = stripped.Split(' ');
if (values.Length < 2 || !values[1].StartsWith("bandwidth=", StringComparison.CurrentCultureIgnoreCase))
continue;
string[] value = values[1].Split(new[] { '=' }, 2);
if (value.Length < 2)
continue;
int bandwidth;
if (int.TryParse(value[1].Trim(), out bandwidth))
router.Bandwidth = new Bytes((double)bandwidth, Bits.KB).Normalize();
}
}
return new GetRouterStatusResponse(true, router);
}
return new GetRouterStatusResponse(false, null);
}
#endregion
}
///
/// A class containing the response information from a getinfo ns/id/? command.
///
internal sealed class GetRouterStatusResponse : Response
{
private readonly Router router;
///
/// Initializes a new instance of the class.
///
/// A value indicating whether the command was received and processed successfully.
/// The router information retrieved from the command.
public GetRouterStatusResponse(bool success, Router router) : base(success)
{
this.router = router;
}
#region Properties
///
/// Gets the router information retrieved from the control connection.
///
public Router Router
{
get { return router; }
}
#endregion
}
}