diff --git a/DBEditor/CommandList.cs b/DBEditor/CommandList.cs index 93ed1064..1318fa5c 100644 --- a/DBEditor/CommandList.cs +++ b/DBEditor/CommandList.cs @@ -36,6 +36,7 @@ namespace TShockDBEditor CommandList.Add("kill"); CommandList.Add("butcher"); CommandList.Add("item"); + CommandList.Add("clearitems"); CommandList.Add("heal"); CommandList.Add("whisper"); CommandList.Add("annoy"); diff --git a/HttpBins/HttpServer.dll b/HttpBins/HttpServer.dll new file mode 100644 index 00000000..bf543068 Binary files /dev/null and b/HttpBins/HttpServer.dll differ diff --git a/HttpBins/HttpServer.pdb b/HttpBins/HttpServer.pdb new file mode 100644 index 00000000..f1cfd83f Binary files /dev/null and b/HttpBins/HttpServer.pdb differ diff --git a/HttpBins/HttpServer.xml b/HttpBins/HttpServer.xml new file mode 100644 index 00000000..fff737b5 --- /dev/null +++ b/HttpBins/HttpServer.xml @@ -0,0 +1,6183 @@ + + + + HttpServer + + + + + Used to read from a string object. + + + + + Base interface to read string tokens from different sources. + + + + + Assign a new buffer + + Buffer to process. + Where to start process buffer + Buffer length + + + + Assign a new buffer + + Buffer to process + + + + Consume current character. + + + + + Consume specified characters + + One or more characters. + + + + Consumes horizontal white spaces (space and tab). + + + + + Consume horizontal white spaces and the specified character. + + Extra character to consume + + + + Checks if one of the remaining bytes are a specified character. + + Character to find. + true if found; otherwise false. + + + + Read a character. + + Character if not EOF; otherwise null. + + + + Get a text line. + + + Will merge multiline headers. + + + + Read quoted string + + string if current character (in buffer) is a quote; otherwise null. + + + + Read until end of string, or to one of the delimiters are found. + + characters to stop at + A string (can be ). + + Will not consume the delimiter. + + + + + Read until end of string, or to one of the delimiters are found. + + A string (can be ). + + Will not consume the delimiter. + + + + + Read to end of buffer, or until specified delimiter is found. + + Delimiter to find. + A string (can be ). + + Will not consume the delimiter. + + + + + Will read until specified delimiter is found. + + Character to stop at. + A string if the delimiter was found; otherwise null. + + Will trim away spaces and tabs from the end. + Will not consume the delimiter. + + + + + Read until one of the delimiters are found. + + characters to stop at + A string if one of the delimiters was found; otherwise null. + + Will trim away spaces and tabs from the end. + Will not consume the delimiter. + + + + + Read until a horizontal white space occurs. + + A string if a white space was found; otherwise null. + + + + Gets current character + + if end of buffer. + + + + Gets if end of buffer have been reached + + + + + Gets if more bytes can be processed. + + + + + Gets or sets current position in buffer. + + + THINK before you manually change the position since it can blow up + the whole parsing in your face. + + + + + Gets total length of buffer. + + + + + Gets or sets line number. + + + + + Gets next character + + if end of buffer. + + + + Gets number of bytes left. + + + + + Initializes a new instance of the class. + + Buffer to process. + + + + Initializes a new instance of the class. + + + + + Assign a new buffer + + Buffer to process. + Where to start process buffer + Buffer length + MUST be of type . + buffer needs to be of type string + + + + Assign a new buffer + + Buffer to process + MUST be of type . + buffer needs to be of type string + + + + Consume current character. + + + + + Get a text line. + + + Will merge multiline headers. + + + + Read quoted string + + string if current character (in buffer) is a quote; otherwise null. + + + + Read until end of string, or to one of the delimiters are found. + + characters to stop at + A string (can be ). + InvalidOperationException. + + + + Read until end of string, or to one of the delimiters are found. + + A string (can be ). + + Will not consume the delimiter. + + + + + Read to end of buffer, or until specified delimiter is found. + + Delimiter to find. + A string (can be ). + InvalidOperationException. + + + + Consume specified characters + + One or more characters. + + + + Consumes horizontal white spaces (space and tab). + + + + + Read a character. + + + Character if not EOF; otherwise null. + + + + + Will read until specified delimiter is found. + + Character to stop at. + + A string if the delimiter was found; otherwise null. + + + Will trim away spaces and tabs from the end. + Will not consume the delimiter. + + InvalidOperationException. + + + + Read until one of the delimiters are found. + + characters to stop at + + A string if one of the delimiters was found; otherwise null. + + + Will not consume the delimiter. + + InvalidOperationException. + + + + Read until a horizontal white space occurs (or end, or end of line). + + + A string if a white space was found; otherwise null. + + + + + Consume horizontal white spaces and the specified character. + + Extra character to consume + + + + Checks if one of the remaining bytes are a specified character. + + Character to find. + + true if found; otherwise false. + + + + + Gets or sets line number. + + + + + Gets if end of buffer have been reached + + + + + + Gets if more bytes can be processed. + + + + + + Gets next character + + if end of buffer. + + + + Gets current character + + if end of buffer. + + + + Gets or sets current position in buffer. + + + THINK before you manually change the position since it can blow up + the whole parsing in your face. + + + + + Gets total length of buffer. + + + + + + Gets number of bytes left. + + + + + Reads strings from a byte array. + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class. + + Encoding to use when converting byte array to strings. + + + + Initializes a new instance of the class. + + Buffer to read from. + Encoding to use when converting byte array to strings. + + + + Assign a new buffer + + Buffer to process. + Where to start process buffer + Buffer length + Buffer needs to be a byte array + + + + Assign a new buffer + + Buffer to process + Buffer needs to be a byte array + + + + Consume current character. + + + + + Get a text line. + + + Will merge multi line headers. + + + + Read quoted string + + string if current character (in buffer) is a quote; otherwise null. + + + + Read until end of string, or to one of the delimiters are found. + + characters to stop at + + A string (can be ). + + + Will not consume the delimiter. + + InvalidOperationException. + + + + Read until end of string, or to one of the delimiters are found. + + A string (can be ). + + Will not consume the delimiter. + + + + + Read to end of buffer, or until specified delimiter is found. + + Delimiter to find. + + A string (can be ). + + + Will not consume the delimiter. + + InvalidOperationException. + + + + Consume specified characters + + One or more characters. + + + + Consumes horizontal white spaces (space and tab). + + + + + Consume horizontal white spaces and the specified character. + + Extra character to consume + + + + Read a character. + + + Character if not EOF; otherwise null. + + + + + Will read until specified delimiter is found. + + Character to stop at. + + A string if the delimiter was found; otherwise null. + + + Will trim away spaces and tabs from the end. + InvalidOperationException. + + + + Read until one of the delimiters are found. + + characters to stop at + + A string if one of the delimiters was found; otherwise null. + + + Will not consume the delimiter. + + InvalidOperationException. + + + + Read until a horizontal white space occurs. + + A string if a white space was found; otherwise null. + + + + Checks if one of the remaining bytes are a specified character. + + Character to find. + + true if found; otherwise false. + + + + + Gets or sets line number. + + + + + Gets if end of buffer have been reached + + + + + + Gets if more bytes can be processed. + + + + + + Gets next character + + if end of buffer. + + + + Gets current character + + if end of buffer. + + + + Gets or sets current position in buffer. + + + THINK before you manually change the position since it can blow up + the whole parsing in your face. + + + + + Gets total length of buffer. + + + + + + Gets number of bytes left. + + + + + Event arguments used when a new header have been parsed. + + + + + Initializes a new instance of the class. + + Name of header. + Header value. + Name cannot be empty + value is null. + + + + Initializes a new instance of the class. + + + + + Gets or sets header name. + + + + + Gets or sets header value. + + + + + Resource information. + + + Used by content providers to be able to get information + on resources (views, files etc). + + + + + Gets or sets date when resource was modified. + + + if not used. + + + Should always be universal time. + + + + + Gets or sets resource stream. + + + + + Loads resources from a specific location (such as assembly, hard drive etc). + + + + + Checks if a resource exists in the specified directory + + Uri path to resource + true if resource was found; otherwise false. + + + if (resources.Exists("/files/user/user.png")) + Debug.WriteLine("Resource exists."); + + + + + + Find all views in a folder/path. + + Absolute Uri path to files that should be found, can end with wild card. + Collection to add all view names to. + + + + Gets a resource. + + Uri path to resource. + Resource + Uri contains forbidden characters. + + + Resource resource = resources.Get("/files/user/user.png"); + + + + + + Parses Cookie header. + + + + + Used to parse header values + + + + + Parse a header + + Name of header. + Reader containing value. + HTTP Header + Header value is not of the expected format. + + + + Parse a header + + Name of header. + Reader containing value. + HTTP Header + Header value is not of the expected format. + + + + Used by to filter out unwanted connections. + + + + + Initializes a new instance of the class. + + The socket. + + + + Gets or sets if socket can be accepted. + + + + + Gets socket. + + + + + Http listener + + + + + Start listener. + + Number of pending accepts. + + Make sure that you are subscribing on first. + + Listener have already been started. + Failed to start socket. + Invalid port number. + + + + Stop listener. + + + + + Gets listener address. + + + + + Gets if listener is secure. + + + + + Gets if listener have been started. + + + + + Gets or sets logger. + + + + + Gets listening port. + + + + + Gets the maximum content size. + + The content length limit. + + Used when responding to 100-continue. + + + + + A new request have been received. + + + + + Can be used to reject certain clients. + + + + + A HTTP exception have been thrown. + + + Fill the body with a user friendly error page, or redirect to somewhere else. + + + + + Collection of files. + + + + + Checks if a file exists. + + Name of the file (form item name) + + + + + Add a new file. + + File to add. + + + + Remove all files from disk. + + + + + Get a file + + Name in form + File if found; otherwise null. + + + + Gets number of files + + + + + Custom network stream to mark sockets as reusable when disposing the stream. + + + + + Creates a new instance of the class for the specified . + + + The that the will use to send and receive data. + + + The parameter is null. + + + The parameter is not connected. + -or- + The property of the parameter is not . + -or- + The parameter is in a nonblocking state. + + + + + Initializes a new instance of the class for the specified with the specified ownership. + + + The that the will use to send and receive data. + + + Set to true to indicate that the will take ownership of the ; otherwise, false. + + + The parameter is null. + + + The parameter is not connected. + -or- + the value of the property of the parameter is not . + -or- + the parameter is in a nonblocking state. + + + + + Creates a new instance of the class for the specified with the specified access rights. + + + The that the will use to send and receive data. + + + A bitwise combination of the values that specify the type of access given to the over the provided . + + + The parameter is null. + + + The parameter is not connected. + -or- + the property of the parameter is not . + -or- + the parameter is in a nonblocking state. + + + + + Creates a new instance of the class for the specified with the specified access rights and the specified ownership. + + + The that the will use to send and receive data. + + + A bitwise combination of the values that specifies the type of access given to the over the provided . + + + Set to true to indicate that the will take ownership of the ; otherwise, false. + + + The parameter is null. + + + The parameter is not connected. + -or- + The property of the parameter is not . + -or- + The parameter is in a nonblocking state. + + + + + Closes the current stream and releases any resources (such as sockets and file handles) associated with the current stream. + + + + + Releases the unmanaged resources used by the and optionally releases the managed resources. + + true to release both managed and unmanaged resources; false to release only unmanaged resources. + + + + Request sent to a HTTP server. + + + + + + Base interface for request and response. + + + + + Add a new header. + + + + + + + Add a new header. + + Header to add. + + + + Gets body stream. + + + + + Size of the body. MUST be specified before sending the header, + unless property Chunked is set to true. + + + + + Kind of content in the body + + Default is text/html + + + + Gets or sets encoding + + + + + Gets headers. + + + + + Get a header + + Type that it should be cast to + Name of header + Header if found and casted properly; otherwise null. + + + + Gets or sets connection header. + + + + + Gets cookies. + + + + + Gets all uploaded files. + + + + + Gets form parameters. + + + + + Gets or sets HTTP version. + + + + + Gets if request is an Ajax request. + + + + + Gets or sets HTTP method. + + + + + Gets query string and form parameters + + + + + Gets query string. + + + + + Gets requested URI. + + + + + Serves files in the web server. + + + + FileModule fileModule = new FileModule(); + fileModule.Resources.Add(new FileResources("/", "C:\\inetpub\\myweb")); + + + + + + HTTP Module + + + + + Process a request. + + Request information + What to do next. + + + + Initializes a new instance of the class. + + baseUri or basePath is null. + + + + Mime types that this class can handle per default + + + Contains the following mime types: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Will send a file to client. + + HTTP context containing outbound stream. + Response containing headers. + File stream + + + + Process a request. + + Request information + What to do next. + Failed to find file extension + Forbidden file type. + + + + Gets a list with all allowed content types. + + All other mime types will result in . + + + + Gets provider used to add files to the file manager, + + + + + An exception that can't be handled by the library have been thrown. + + + + + Initializes a new instance of the class. + + The exception. + + + + Gets caught exception. + + + + + Helper for content types. + + + + + Decodes forms that have multiple sections. + + + http://www.faqs.org/rfcs/rfc1867.html + + + + + Decodes body stream. + + + + + Decode body stream + + Stream containing the content + Content type header + Stream encoding + Decoded data. + Body format is invalid for the specified content type. + Something unexpected failed. + + + + All content types that the decoder can parse. + + A collection of all content types that the decoder can handle. + + + + form-data + + + + + multipart/form-data + + + + + Decode body stream + + Stream containing the content + Content type header + Stream encoding + Decoded data. + Body format is invalid for the specified content type. + Something unexpected failed. + stream is null. + + + + All content types that the decoder can parse. + + A collection of all content types that the decoder can handle. + + + + A HTTP parser using delegates to which parsing methods. + + + + + Initializes a new instance of the class. + + + + + Parser method to copy all body bytes. + + + Needed since a TCP packet can contain multiple messages + after each other, or partial messages. + + + + Try to find a header name. + + + + + + Get header values. + + + Will also look for multi header values and automatically merge them to one line. + Content length is not a number. + + + + Toggle body bytes event. + + + + + + + + Raise the event, since we have successfully parsed a message and it's body. + + + + + First message line. + + Will always contain three elements. + Used to raise the or event + depending on the words in the array. + BadRequestException. + + + + Continue parsing a message + + Byte buffer containing bytes + Where to start the parsing + Number of bytes to parse + index where the parsing stopped. + Parsing failed. + + + + Parses the first line in a request/response. + + true if first line is well formatted; otherwise false. + Invalid request/response line. + + + + Reset parser to initial state. + + + + + Gets or sets current line number. + + + + + The request line has been parsed. + + + + + Response line has been parsed. + + + + + Parsed a header. + + + + + Received body bytes. + + + + + A message have been successfully parsed. + + + + + Used to be able to quickly swap parser method. + + + + + + Default log filter implementation. + + + + + Determines which classes can log + + + + + Checks if the specified type can send + log entries at the specified level. + + Log level + Type that want to write a log entry. + true if logging is allowed; otherwise false. + + + + Add a name space filter. + + Name space to add filter for. + Minimum log level required. + + + // Parsing can only add error and fatal messages + AddNamespace("SipSharp.Messages.Headers.Parsers", LogLevel.Error); + AddType(typeof(SipParser), LogLevel.Error); + + // Transport layer can only log warnings, errors and fatal messages + AddNamespace("SipSharp.Transports.*", LogLevel.Warning); + + + + + + Used to specify standard filter rules + + + Parser can only display errors. Transports only warnings. + + + + + Add filter for a type + + Type to add filter for. + Minimum log level required. + + + // Parsing can only add error and fatal messages + AddNamespace("SipSharp.Messages.Headers.Parsers", LogLevel.Error); + AddType(typeof(SipParser), LogLevel.Error); + + // Transport layer can only log warnings, errors and fatal messages + AddNamespace("SipSharp.Transports.*", LogLevel.Warning); + + + + + + Add filter for a type + + Type to add filter for. + Minimum log level required. + + + // Parsing can only add error and fatal messages + AddNamespace("SipSharp.Messages.Headers.Parsers", LogLevel.Error); + AddType("SipSharp.Messages.MessageFactory", LogLevel.Error); + + // Transport layer can only log warnings, errors and fatal messages + AddNamespace("SipSharp.Transports.*", LogLevel.Warning); + + + Type could not be identified. + + + + Checks if the specified type can send + log entries at the specified level. + + Log level + Type that want to write a log entry. + true if logging is allowed; otherwise false. + + + No filters = everything logged. = no logs. Don't use a rule with '*' or '.*' + + + + User have specified a wild card filter. + + + Wild card filters are used to log a name space and + all it's children name spaces. + + + + + Factory implementation used to create logs. + + + + + Create a new logger. + + Type that requested a logger. + Logger for the specified type; + + MUST ALWAYS return a logger. Return if no logging + should be used. + + + + + Response to a request. + + + + + Redirect user. + + Where to redirect to. + + Any modifications after a redirect will be ignored. + + + + + Gets connection type. + + + + + Gets cookies. + + + + + Gets HTTP version. + + + Default is HTTP/1.1 + + + + + Information about why a specific status code was used. + + + + + Status code that is sent to the client. + + Default is + + + + Gets or sets content type + + + + + Rules are used to perform operations before a request is being handled. + Rules can be used to create routing etc. + + + + + Process the incoming request. + + Request context information. + Processing result. + If any parameter is null. + + + + Used to access resources. + + + + + Add a new resource loader. + + Provider to add. + Manager have been started. + + + + Check if a resource exists. + + Uri to check + true if found; otherwise false. + + + if (manager.Exists("/views/user/view.haml")) + return true + + + + + + Get a resource. + + Uri path to resource. + Resource if found; otherwise null. + + + Resource resource = manager.Get("/views/user/view.haml"); + + + + + + Start manager. + + + + + Gets number of resource providers + + + + + Parses "Date" header. + + + + + Parse a header + + Name of header. + Reader containing value. + HTTP Header + Header value is not of the expected format. + + + + Content-type + + + + + Header in a message + + + Important! Each header should override ToString() + and return it's data correctly formatted as a HTTP header value. + + + + + Gets header name + + + + + Gets value as it would be sent back to client. + + + + + Header name. + + + + + Initializes a new instance of the class. + + Type of the content. + Value parameters. + + + + Initializes a new instance of the class. + + Type of the content. + + + + Returns data formatted as a HTTP header value. + + + A that represents the current . + + + + + Gets all parameters. + + + + + Gets content type. + + + + + Gets header name + + + + + Used to get or set properties on objects. + + + This class should be a bit faster than the standard reflection. + + + + + Get cached type. + + Type to get/set properties in + Type to use + + + + Flyweight design pattern implementation. + + Type of object. + + + + Initializes a new instance of the class. + + How large buffers to allocate. + + + + Get an object. + + Created object. + Will create one if queue is empty. + + + + Enqueues the specified buffer. + + Object to enqueue. + Buffer is is less than the minimum requirement. + + + + Used to create new objects. + + Type of objects to create. + Newly created object. + . + + + + Used to load/store sessions in the server. + + + + + Initializes a new instance of the class. + + Web server that the provider is for.. + Store to use. + + + + Initializes a new instance of the class. + + The server. + + Uses a file store. + + + + + Loads a session for all requests that got the session cookie. + + The sender. + The instance containing the event data. + + + + Gets current session + + Session if set, otherwise null. + + + + Gets or sets the session life time in minutes. + + The session life time. + + + + A session have been loaded. Use to access it. + + + + + Used to build headers. + + + + + Add a parser + + Header that the parser is for. + Parser implementation + + Will replace any existing parser for the specified header. + + + + + Add all default (built-in) parsers. + + + Will not replace previously added parsers. + + + + + Create a header parser + + implementation. + + + Uses attribute to find which headers + the parser is for. + + Will not replace previously added parsers. + + + + + Parse a header. + + Name of header + Header value + Header. + Value is not a well formatted header value. + + + + Arguments used when more body bytes have come. + + + + + Initializes a new instance of the class. + + buffer that contains the received bytes. + offset in buffer where to start processing. + number of bytes from that should be parsed. + buffer is null. + + + + Initializes a new instance of the class. + + + + + Gets or sets buffer that contains the received bytes. + + + + + Gets or sets number of bytes from that should be parsed. + + + + + Gets or sets offset in buffer where to start processing. + + + + + redirects from one URL to another. + + + + + Initializes a new instance of the class. + + Absolute path (no server name) + Absolute path (no server name) + + server.Add(new RedirectRule("/", "/user/index")); + + + + + Initializes a new instance of the class. + + Absolute path (no server name) + Absolute path (no server name) + true if request should be redirected, false if the request URI should be replaced. + + server.Add(new RedirectRule("/", "/user/index")); + + + + + Process the incoming request. + + Request context. + Processing result. + If any parameter is null. + + + + Gets string to match request URI with. + + Is compared to request.Uri.AbsolutePath + + + + Gets whether the server should redirect the client instead of simply modifying the URI. + + + false means that the rule will replace + the current request URI with the new one from this class. + true means that a redirect response is sent to the client. + + + + + Gets where to redirect. + + + + + cookie sent by the client/browser + + + + + + Constructor. + + cookie identifier + cookie content + id or content is null + id is empty + + + + Gets the cookie HTML representation. + + cookie string + + + + Gets the cookie identifier. + + + + + Gets value. + + + Set to null to remove cookie. + + + + + A request have been parsed successfully by the server. + + + + + Initializes a new instance of the class. + + Received request. + + + + Gets received request. + + + + + Context that received a HTTP request. + + + + + Disconnect context. + + + + + Gets if current context is using a secure connection. + + + + + Gets logger. + + + + + Gets remote end point + + + + + Gets stream used to send/receive data to/from remote end point. + + + + The stream can be any type of stream, do not assume that it's a network + stream. For instance, it can be a or a ZipStream. + + + + + + Gets the currently handled request + + The request. + + + + Gets the response that is going to be sent back + + The response. + + + + File sent from remote end. + + + + + Gets or sets content type. + + + + + Gets or sets name in form. + + + + + Gets or sets name original file name + + + + + Gets or sets filename for locally stored file. + + + + + Client X.509 certificate, X.509 chain, and any SSL policy errors encountered + during the SSL stream creation + + + + + Initializes a new instance of the class. + + The certificate. + Client security certificate chain. + Any SSL policy errors encountered during the SSL stream creation. + + + + Client security certificate + + + + + Client security certificate chain + + + + + Any SSL policy errors encountered during the SSL stream creation + + + + + Provides sessions. + + Type of session object + + Will always use files for sessions (utilizing the binary formatter), but can + also cache them in memory. + + If caching is enabled, it will only write sessions to disk every 20 seconds if they have + been accessed the last minute (to not keep writing dead sessions to disk). + + + + + + Initializes a new instance of the class. + + Session type must use [Serializable] attribute. + + + + Create a new session. + + + + + + Load session + + Id of session. + Session if found; otherwise null. + sessionId is null. + + + + Load session when a new request comes in. + + + + + + + Save a session to disk. + + Session to write to disk. + + You are responsible for writing sessions to disk if you are not using caching. + + + + + Start the session system and hook + + + + + + Stop session handling + + + + + Gets or sets session cookie name + + + + + Gets or sets cache + + + + + Gets current session. + + + + + Gets or sets number of seconds before a session expired. + + + A session have expired if nothing have accessed it for X seconds. This + class modifies the write time each time it's accessed. + + + + + Determines if cookie should be set in the response. + + + + + Invoked when a session have been changed and should be written to disc. + + + + + Base class for sessions. + + + Your class must be tagged with attribute to be able to use sessions. + + + + + The session have been changed and should be written to disk. + + + + + Session have been changed. + + + + + Gets or sets when session was accessed last + + + + + Gets current session. + + + + + Gets or sets session id. + + + + + Gets or sets when the session was last written to disk. + + + + + Used when the request line have been successfully parsed. + + + + + Initializes a new instance of the class. + + The HTTP method. + The URI path. + The HTTP version. + + + + Initializes a new instance of the class. + + + + + Gets or sets HTTP method. + + + Should be one of the methods declared in . + + + + + Gets or sets requested URI path. + + + + + Gets or sets the version of the SIP protocol that the client want to use. + + + + + cookie being sent back to the browser. + + + + + + Constructor. + + cookie identifier + cookie content + cookie expiration date. Use for session cookie. + id or content is null + id is empty + + + + Create a new cookie + + name identifying the cookie + cookie value + when the cookie expires. Setting will delete the cookie when the session is closed. + Path to where the cookie is valid + Domain that the cookie is valid for. + + + + Create a new cookie + + Name and value will be used + when the cookie expires. + + + + Gets the cookie HTML representation. + + cookie string + + + + Gets when the cookie expires. + + means that the cookie expires when the session do so. + + + + Gets path that the cookie is valid under. + + + + + Used to define which headers a parse is for. + + + + + Initializes a new instance of the class. + + Name of the header. + + + + Gets name of header that this parser is for. + + + + + Collection of headers. + + + + + Gets a header + + header name. + header if found; otherwise null. + + + + Something failed during parsing. + + + + + Request couldn't be parsed successfully. + + + + + Exception thrown from HTTP server. + + + + + Initializes a new instance of the class. + + HTTP status code. + Exception description. + + + + Initializes a new instance of the class. + + HTTP status code. + Exception description. + Inner exception. + + + + Gets HTTP status code. + + + + + Initializes a new instance of the class. + + Exception description. + + + + Initializes a new instance of the class. + + Exception description. + Exception description. + + + + Initializes a new instance of the class. + + Exception description. + + + + Initializes a new instance of the class. + + Exception description. + Inner exception. + + + + Provides resources. + + + + + Get all view names from a folder. + + Path to find views in. + A collection of view names (without path). + + + + Add a new resource loader. + + Provider to add. + Manager have been started. + + + + Start manager. + + + + + Check if a resource exists. + + Uri to check + true if found; otherwise false. + + + if (manager.Exists("/views/user/view.haml")) + return true + + + + + + Get a resource. + + Uri path to resource. + Resource if found; otherwise null. + + + Resource resource = manager.Get("/views/user/view.haml"); + + + + + + Gets number of resource providers + + + + + Collection of parameters. + + + or is not used since each parameter can + have multiple values. + + + + + Collection of parameters + + + + + Get a parameter. + + + + + + + Add a query string parameter. + + Parameter name + Value + + + + Checks if the specified parameter exists + + Parameter name. + true if found; otherwise false; + + + + Gets number of parameters. + + + + + Gets last value of an parameter. + + Parameter name + String if found; otherwise null. + + + + Initializes a new instance of the class. + + Collections to merge. + + Later collections will overwrite parameters from earlier collections. + + + + + Initializes a new instance of the class. + + + + + Get a list of string arrays. + + + + + + Get parameters + + Sub array (text array) + + + + + Returns an enumerator that iterates through the collection. + + + A that can be used to iterate through the collection. + + 1 + + + + Returns an enumerator that iterates through a collection. + + + An object that can be used to iterate through the collection. + + 2 + + + + Get a parameter. + + + + + + + Add a query string parameter. + + Parameter name + Value + + + + Checks if the specified parameter exists + + Parameter name. + true if found; otherwise false; + + + + Gets number of parameters. + + + + + Gets last value of an parameter. + + Parameter name + String if found; otherwise null. + + + + Result of processing. + + + + + Continue with the next handler + + + + + No more handlers can process the request. + + + The server will process the response object and + generate a HTTP response from it. + + + + + Response have been sent back by the handler. + + + This option should only be used if you are streaming + something or sending back a custom result. The server will + not process the response object or send anything back + to the client. + + + + + A HTTP context + + + + + + + + Initializes a new instance of the class. + + Socket received from HTTP listener. + Context used to parse incoming messages. + + + + Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + + 2 + + + + Disconnect context. + + + + + Close and release socket. + + + + + Create stream used to send and receive bytes from the socket. + + Socket to wrap + Stream + Stream could not be created. + + + + Interpret incoming data. + + + + + + A request was received from the parser. + + + + + + + Parse all complete requests in buffer. + + + offset in buffer where parsing stopped. + Parsing failed. + + + + Start content. + + A socket operation failed. + Reading from stream failed. + + + + Gets currently executing HTTP context. + + + + + Gets or sets description + + + + + gets factory used to build request objects + + + + + Gets socket + + + + + Gets remove end point + + + + + Gets network stream. + + + + + Gets the currently handled request + + The request. + + + + Gets the response that is going to be sent back + + The response. + + + + Gets logger. + + + + + Gets if current context is using a secure connection. + + + + + Triggered for all requests in the server (after the response have been sent) + + + + + Triggered for current request (after the response have been sent) + + + + + A new request have been received. + + + + + A new request have been received (invoked for ALL requests) + + + + + Client have been disconnected. + + + + + Client asks if he may continue. + + + If the body is too large or anything like that you should respond . + + + + + Used to store all headers that that aren't recognized. + + + + + Initializes a new instance of the class. + + The name. + The value. + + + + Gets or sets value + + + + + Gets header name + + + + + The Connection general-header field allows the sender to specify options + that are desired for that particular connection and MUST NOT be + communicated by proxies over further connections. + + + + HTTP/1.1 proxies MUST parse the Connection header field before a + message is forwarded and, for each connection-token in this field, + remove any header field(s) from the message with the same name as the + connection-token. Connection options are signaled by the presence of + a connection-token in the Connection header field, not by any + corresponding additional header field(s), since the additional header + field may not be sent if there are no parameters associated with that + connection option. + + Message headers listed in the Connection header MUST NOT include + end-to-end headers, such as Cache-Control. + + HTTP/1.1 defines the "close" connection option for the sender to + signal that the connection will be closed after completion of the + response. For example, + + Connection: close + + in either the request or the response header fields indicates that + the connection SHOULD NOT be considered `persistent' (section 8.1) + after the current request/response is complete. + + HTTP/1.1 applications that do not support persistent connections MUST + include the "close" connection option in every message. + + A system receiving an HTTP/1.0 (or lower-version) message that + includes a Connection header MUST, for each connection-token in this + field, remove and ignore any header field(s) from the message with + the same name as the connection-token. This protects against mistaken + forwarding of such header fields by pre-HTTP/1.1 proxies. See section + 19.6.2 in RFC2616. + + + + + + Header name + + + + + Default connection header for HTTP/1.0 + + + + + Default connection header for HTTP/1.1 + + + + + Initializes a new instance of the class. + + Connection type. + The parameters. + + + + Initializes a new instance of the class. + + The type. + + + + Returns data formatted as a HTTP header value. + + + A that represents the current . + + + + + Gets connection parameters. + + + + + Gets or sets connection type + + + + + Gets header name + + + + + Type of HTTP connection + + + + + Connection is closed after each request-response + + + + + Connection is kept alive for X seconds (unless another request have been made) + + + + + Parameter in + + + + + Gets *last* value. + + + Parameters can have multiple values. This property will always get the last value in the list. + + String if any value exist; otherwise null. + + + + Gets or sets name. + + + + + Gets a list of all values. + + + + + A parameter in . + + + + + Returns an enumerator that iterates through the collection. + + + A that can be used to iterate through the collection. + + 1 + + + + Returns an enumerator that iterates through a collection. + + + An object that can be used to iterate through the collection. + + 2 + + + + Gets last value. + + + Parameters can have multiple values. This property will always get the last value in the list. + + String if any value exist; otherwise null. + + + + Gets or sets name. + + + + + Gets a list of all values. + + + + + Secure version of the HTTP listener. + + + + + Http listener. + + + + + Initializes a new instance of the class. + + The address. + The port. + + + + Initializes a new instance of the class. + + The address. + The port. + The HTTP factory. + + + + Creates a new instance with default factories. + + Address that the listener should accept connections on. + Port that listener should accept connections on. + Created HTTP listener. + + + + Creates a new instance with default factories. + + Address that the listener should accept connections on. + Port that listener should accept connections on. + Factory used to create different types in the framework. + Created HTTP listener. + + + + Creates a new instance with default factories. + + Address that the listener should accept connections on. + Port that listener should accept connections on. + Certificate to use + Created HTTP listener. + + + + Create a new context + + Accepted socket + A new context. + + + Throwing exception if in debug mode and not exception handler have been specified. + + + + Start listener. + + Number of pending accepts. + + Make sure that you are subscribing on first. + + Listener have already been started. + Failed to start socket. + Invalid port number. + + + + Stop listener. + + + + + Gets HTTP factory used to create types used by this HTTP library. + + + + + Gets or sets the maximum number of bytes that the request body can contain. + + The content length limit. + + + Used when responding to 100-continue. + + + 0 = turned off. + + + + + + Gets listener address. + + + + + Gets if listener is secure. + + + + + Gets if listener have been started. + + + + + Gets or sets logger. + + + + + Gets listening port. + + + + + A new request have been received. + + + + + Can be used to reject certain clients. + + + + + A HTTP exception have been thrown. + + + Fill the body with a user friendly error page, or redirect to somewhere else. + + + + + Client asks if he may continue. + + + If the body is too large or anything like that you should respond . + + + + + Initializes a new instance of the class. + + Address to accept new connections on. + Port to accept connections on. + Certificate securing the connection. + + + + Create a new context + + Accepted socket + A new context. + + Factory is assigned by the on each incoming request. + + + + + Gets if listener is secure. + + + + + + Gets or sets SSL protocol. + + + + + Gets or sets if client certificate should be used. + + + + + A response have been received. + + + + + Initializes a new instance of the class. + + The response. + + + + Gets or sets response. + + + + + Implements HTTP Digest authentication. It's more secure than Basic auth since password is + encrypted with a "key" from the server. + + + Keep in mind that the password is encrypted with MD5. Use a combination of SSL and digest auth to be secure. + + + + + Authenticates requests + + + + + Authenticate request + + Authorization header send by web client + Realm to authenticate in, typically a domain name. + HTTP Verb used in the request. + User if authentication was successful; otherwise null. + + + + Create a authentication challenge. + + Realm that the user should authenticate in + A WWW-Authenticate header. + If realm is empty or null. + + + + Gets authenticator scheme + + + digest + + + + + Initializes a new instance of the class. + + Supplies users during authentication process. + + + + Used by test classes to be able to use hardcoded values + + + + + An authentication response have been received from the web browser. + Check if it's correct + + Contents from the Authorization header + Realm that should be authenticated + GET/POST/PUT/DELETE etc. + + Authentication object that is stored for the request. A user class or something like that. + + if authenticationHeader is invalid + If any of the parameters is empty or null. + + + + Encrypts parameters into a Digest string + + Realm that the user want to log into. + User logging in + Users password. + HTTP method. + Uri/domain that generated the login prompt. + Quality of Protection. + "Number used ONCE" + Hexadecimal request counter. + "Client Number used ONCE" + Digest encrypted string + + + + + + Md5 hex encoded "userName:realm:password", without the quotes. + Md5 hex encoded "method:uri", without the quotes + Quality of Protection + "Number used ONCE" + Hexadecimal request counter. + Client number used once + + + + + Create a authentication challenge. + + Realm that the user should authenticate in + A correct auth request. + If realm is empty or null. + + + + Gets the current nonce. + + + + + + Gets the Md5 hash bin hex2. + + To be hashed. + + + + + determines if the nonce is valid or has expired. + + nonce value (check wikipedia for info) + true if the nonce has not expired. + + + + Gets authentication scheme name + + + + + Gets authenticator scheme + + + + digest + + + + + Session in the system + + + + + Gets or sets session id. + + + + + Factory creating null logger. + + + + + Initializes a new instance of the class. + + + + + Create a new logger. + + Type that requested a logger. + Logger for the specified type; + + MUST ALWAYS return a logger. Return if no logging + should be used. + + + + + Logger instance. + + + + + HTTP methods. + + + + + Unknown method + + + + + Posting data + + + + + Get data + + + + + Update data + + + + + Remove data + + + + + Get only HTTP headers. + + + + + Options HTTP 1.1 header. + + + + + Parses . + + + + + Parse a header + + Name of header. + Reader containing value. + HTTP Header + Header value is not of the expected format. + + + + Request couldn't be parsed successfully. + + + + + Initializes a new instance of the class. + + Exception description. + + + + Initializes a new instance of the class. + + Exception description. + Exception description. + + + + Arguments for . + + + + + Initializes a new instance of the class. + + The context. + + + + Gets or sets thrown exception + + + + + Gets or sets if error page was provided. + + + + + Gets requested resource. + + + + + Gets response to send + + + + + Convention over configuration server. + + + Used to make it easy to create and use a web server. + + All resources must exist in the "YourProject.Content" namespace (or a subdirectory called "Content" relative to yourapp.exe). + + + + + + Http server. + + + + + Initializes a new instance of the class. + + Factory used to create objects used in this library. + + + + Initializes a new instance of the class. + + + + + Add a decoder. + + decoder to add + + Adding zero decoders will make the server add the + default ones which is and . + + + + + Add a new router. + + Router to add + Server have been started. + + + + Add a file module + + Module to add + module is null. + Cannot add modules when server have been started. + + + + Add a HTTP listener. + + + Listener have been started. + + + + An error have occurred and we need to send a result pack to the client + + The context. + The exception. + + Invoke base class () to send the contents + of . + + + + + Called before anything else. + + The context. + + Looks after a in the request and will + use the if found. + + + + + All server modules are about to be invoked. + + The context. + + Called when routers have been invoked but no modules yet. + + + + + A request have arrived but not yet been processed yet. + + The context. + + Default implementation adds a Date header and Server header. + + + + + Go through all modules and check if any of them can handle the current request. + + + + + + + Process result (check if it should be sent back or not) + + + + true if request was processed properly.; otherwise false. + + + + Processes all routers. + + Request context. + Processing result. + + + + Requests authentication from the user. + + Host/domain name that the server hosts. + + Used when calculating hashes in Digest authentication. + + + + + + + Send a response. + + + + + + + + Start http server. + + Number of pending connections. + + + + Stops the server + + true if all modules should be removed. + + + + Gets the authentication provider. + + + A authentication provider is used to keep track of all authentication types + that can be used. + + + + + Gets or sets number of bytes that a body can be. + + + + Used to determine the answer to a 100-continue request. + + + 0 = turned off. + + + + + + Gets current server. + + + Only valid when a request have been received and is being processed. + + + + + Gets or sets the maximum size of request body (in bytes) + + + + + Gets or sets server name. + + + Used in the "Server" header when serving requests. + + + + + Invoked just before a response is sent back to the client. + + + + + Invoked *after* the web server has tried to handled the request. + + + The event can be used to handle the request after all routes and modules + have tried to process the request. + + + + + Invoked *before* the web server has tried to handled the request. + + + Event can be used to load a session from a cookie or to force + authentication or anything other you might need t do before a request + is handled. + + + + + An error page have been requested. + + + + + Initializes a new instance of the class. + + + + + Class to make dynamic binding of redirects. Instead of having to specify a number of similar redirect rules + a regular expression can be used to identify redirect URLs and their targets. + + + [a-z0-9]+)", "/users/${target}/?find=true", RegexOptions.IgnoreCase) + ]]> + + + + + Initializes a new instance of the class. + + Expression to match URL + Expression to generate URL + + [a-zA-Z0-9]+)", "/user/${first}")); + Result of ie. /employee1 will then be /user/employee1 + ]]> + + + + + Initializes a new instance of the class. + + Expression to match URL + Expression to generate URL + Regular expression options to use, can be null + + [a-zA-Z0-9]+)", "/user/{first}", RegexOptions.IgnoreCase)); + Result of ie. /employee1 will then be /user/employee1 + ]]> + + + + + Initializes a new instance of the class. + + Expression to match URL + Expression to generate URL + Regular expression options to apply + true if request should be redirected, false if the request URI should be replaced. + + [a-zA-Z0-9]+)", "/user/${first}", RegexOptions.None)); + Result of ie. /employee1 will then be /user/employee1 + ]]> + + Argument is null. + + + + + Process the incoming request. + + Request context. + Processing result. + If any parameter is null. + + + + Load resources from disk. + + + + + Default forbidden characters. + + + + + relative to absolute path mappings. + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class. + + Request URI path + Disk path + + File names should not be included in URI or path. + + + + new FileResources("/files/user/", "C:\\intetpub\\files\users\\"); + + + + + + Add a new resource mapping. + + Request URI path + Disk path + + File names should not be included in URI or path. + + + + resources.Add("/files/", "C:\\intetpub\\files\\"); + + + absolutePath is not found. + + + + check if source contains any of the chars. + + string to check + Characters to fined + + + + + Go through all mappings and find requested Uri. + + Uri to get local path for. + Path if found; otherwise null. + + + + Checks if a resource exists in the specified directory + + Uri path to resource + true if resource was found; otherwise false. + + + if (resources.Exists("/files/user/user.png")) + Debug.WriteLine("Resource exists."); + + + + + + Gets a resource. + + Uri path to resource. + Resource + Uri contains forbidden characters. + + + Resource resource = resources.Get("/files/user/user.png"); + + + + + + Find all views in a folder/path. + + Absolute Uri path to files that should be found, can end with wild card. + Collection to add all view names to. + Uri contains forbidden characters. + + Find(" + + + + + Gets or sets forbidden characters. + + + Used to revoke access to any system files. + + + + + Gets or sets absolute path on disk, including file name. + + + + + Gets or sets relative file path. + + + + + Gets or sets Uri path, excluding file name + + + + + Used to send a response back to the client. + + + + Writes a object into a stream. + + + Important! ResponseWriter do not throw any exceptions. Instead it just logs them and + let them die peacefully. This is since the response writer is used from + catch blocks here and there. + + + + + + Sends response using the specified context. + + The context. + The response. + + + + Converts and sends a string. + + + + Encoding used to transfer string + + + + Send a body to the client + + Context containing the stream to use. + Body to send + + + + Send all headers to the client + + Response containing call headers. + Content used to send headers. + + + + Parses . + + + + + Parse a header + + Name of header. + Reader containing value. + HTTP Header + Header value is not of the expected format. + + + + Collection of headers. + + + + + Initializes a new instance of the class. + + Factory used to created headers. + + + + Adds a header + + + Will replace any existing header with the same name. + + header to add + header is null. + Header name cannot be null. + + + + Add a header. + + Header name + Header value + + Will try to parse the header and create a object. + + Header value is not correctly formatted. + name or value is null. + + + + Add a header. + + Header name + Header value + + Will try to parse the header and create a object. + + name or value is null. + + + + Get a header + + Type that it should be cast to + Name of header + Header if found and casted properly; otherwise null. + + + + Returns an enumerator that iterates through the collection. + + + A that can be used to iterate through the collection. + + 1 + + + + Returns an enumerator that iterates through a collection. + + + An object that can be used to iterate through the collection. + + 2 + + + + Gets a header + + header name. + header if found; otherwise null. + + + + Used to authenticate users + + + Authentication is requested by throwing + + + + + Implements basic authentication scheme. + + + + + Create a response that can be sent in the WWW-Authenticate header. + + Realm that the user should authenticate in + Not used by basic authentication + A WWW-Authenticate header. + Argument is null. + + + + An authentication response have been received from the web browser. + Check if it's correct + + Authorization header + Realm that should be authenticated + GET/POST/PUT/DELETE etc. + Authentication object that is stored for the request. A user class or something like that. + if authenticationHeader is invalid + If any of the paramters is empty or null. + + + + Gets authenticator scheme + + + + digest + + + + + Request implementation. + + + + + Initializes a new instance of the class. + + The method. + The path. + The version. + + + + Get a header + + Type that it should be cast to + Name of header + Header if found and casted properly; otherwise null. + + + + Add a new header. + + + + + + + Add a new header. + + Header to add. + + + + Returns an enumerator that iterates through the collection. + + + A that can be used to iterate through the collection. + + 1 + + + + Returns an enumerator that iterates through a collection. + + + An object that can be used to iterate through the collection. + + 2 + + + + Gets a header. + + + + + + + Gets request URI. + + + + + Gets cookies. + + + + + Gets all uploaded files. + + + + + Gets query string and form parameters + + + + + Gets form parameters. + + + + + Gets query string. + + + + + Gets if request is an Ajax request. + + + + + Gets or sets connection header. + + + + + Gets or sets HTTP version. + + + + + Gets or sets HTTP method. + + + + + Gets requested URI. + + + + + Kind of content in the body + + Default is text/html + + + + Gets or sets encoding + + + + + Gets headers. + + + + + Gets body stream. + + + + + Size of the body. MUST be specified before sending the header, + unless property Chunked is set to true. + + + Any specifically assigned value or Body stream length. + + + + + Initializes a new instance of the class. + + SSL protocol to use. + The socket. + The context. + Server certificate to use. + + + + Create stream used to send and receive bytes from the socket. + + Socket to wrap + Stream + Stream could not be created. + + + + Gets or sets client certificate. + + + + + Gets used protocol. + + + + + Gets or sets if client certificate should be used instead of server certificate. + + + + + A list of request cookies. + + + + + Let's copy all the cookies. + + value from cookie header. + + + + Initializes a new instance of the class. + + + + + Adds a cookie in the collection. + + cookie to add + cookie is null + Name must be specified. + + + + Remove all cookies. + + + + + Remove a cookie from the collection. + + Name of cookie. + + + + Gets a collection enumerator on the cookie list. + + collection enumerator + + + + Returns an enumerator that iterates through the collection. + + + + A that can be used to iterate through the collection. + + 1 + + + + Gets the count of cookies in the collection. + + + + + Gets the cookie of a given identifier (null if not existing). + + + + + Parses query string + + + + + Parse a query string + + string to parse + A collection + reader is null. + + + + Parse a query string + + string to parse + A collection + queryString is null. + + + + Stores sessions in files. + + + All session parameters must be serializable. + + + + + Stores sessions in your favorite store + + + + + + + + Saves the specified session. + + The session. + + + + Touches the specified session + + Session id. + + Used to prevent sessions from expiring. + + + + + Loads a session + + Session id. + Session if found; otherwise null. + + + + Delete a session + + Id of session + + + + Saves the specified session. + + The session. + + + + Touches the specified session + + Session id. + + Used to prevent sessions from expiring. + + + + + Loads a session + + Session id. + Session if found; otherwise null. + + + + Create a HTTP response object. + + + + + Initializes a new instance of the class. + + HTTP Version. + HTTP status code. + Why the status code was selected. + Version must start with 'HTTP/' + + + + Initializes a new instance of the class. + + Context that the response will be sent through. + Request that the response is for. + Version must start with 'HTTP/' + + + + Redirect user. + + Where to redirect to. + + Any modifications after a redirect will be ignored. + + + + + Add a new header. + + + + + + + Add a new header. + + Header to add. + + + + Returns an enumerator that iterates through the collection. + + + A that can be used to iterate through the collection. + + 1 + + + + Returns an enumerator that iterates through a collection. + + + An object that can be used to iterate through the collection. + + 2 + + + + Gets a header. + + + + + + + Gets connection type. + + + + + Status code that is sent to the client. + + Default is + + + + Gets HTTP version. + + + Default is HTTP/1.1 + + + + + Information about why a specific status code was used. + + + + + Size of the body. MUST be specified before sending the header, + unless property Chunked is set to true. + + + Any specifically assigned value or Body stream length. + + + + + Kind of content in the body + + Default is text/html + + + + Gets or sets encoding + + + + + Gets cookies. + + + + + Gets body stream. + + + + + Gets headers. + + + + + Loads resources that are embedded in assemblies. + + + No locks used internally since all mappings are loaded during start up. + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class. + + Path (Uri) requested by clients + Assembly that the resources exist in + Name space that the resources exist in + + + + Add a specific resource. + + Path (Uri) requested by clients + Assembly that the resources exist in + Name space to root folder under (all name spaces below the specified one are considered as folders) + Name space and name of resource. + + + Add("/", Assembly.GetExecutingAssembly(), "MyApplication.Files", "Myapplication.Files.Images.MyImage.png"); + + + + + + Add resources. + + Path (Uri) requested by clients + Assembly that the resources exist in + Name of resource, including name space. + true if file was found (and has not previously been added); otherwise false. + + + + + + Add resources in a specific path (will not work with sub folders) + + Path (Uri) requested by clients + Assembly that the resources exist in + Name space to root folder under which all name spaces exists in, + true if any files was found; otherwise false. + + + Adds all views in the specified folder. Sub folders are not supported since it's hard to determine + with parts are the path and witch parts are the filename. Use to get support + for sub folders. + + + + + Add("/user/", typeof(MyController).Assembly, "YourProject.Users.Views"); + + + + + + Add resources in a folder and it's sub folder + + + + + + This method is not going to map files but keep the mapping and + try to look up views every time they are requested. This is the method + to use to add a resource folder that has sub folders. + + + + + + Tries to load file by using previously added paths. + + Uri path including file name + + + + + Checks if a resource exists in the specified directory + + Uri path to resource + true if resource was found; otherwise false. + + + if (resources.Exists("/files/user/user.png")) + Debug.WriteLine("Resource exists."); + + + + + + Load a resource. + + Uri of resource. + Resource if found and loaded; otherwise null. + + + + Find all views in a folder/path. + + Uri path + Collection to add all view names to. + + + + Loads all files in a resource directory + + + + + + Gets or sets assembly that the resource exists in. + + + + + Gets or sets resource name. + + + + + Gets or sets full name space path to resource. + + + + + Gets or sets if this file is for a certain content type. + + + + + Gets or sets full "virtual" Uri path, excluding file name. + + + + + Gets or sets assembly + + + + + Gets or sets name space root. + + + + + Gets or sets uri path. + + + + + Something unexpected went wrong. + + + + + Initializes a new instance of the class. + + Exception description. + + + + Initializes a new instance of the class. + + Exception description. + Inner exception. + + + + Decodes URL encoded values. + + + + + + + Stream containing the content + Content type header + Stream encoding + Collection with all parameters. + Body format is invalid for the specified content type. + Failed to read all bytes from body stream. + + + + All content types that the decoder can parse. + + A collection of all content types that the decoder can handle. + + + + Parses and builds messages + + + The message factory takes care of building messages + from all end points. + + Since both message and packet protocols are used, the factory + hands out contexts to all end points. The context keeps a state + to be able to parse partial messages properly. + + + Each end point need to hand the context back to the message factory + when the client disconnects (or a message have been parsed). + + + + + + Initializes a new instance of the class. + + Factory used to create headers. + + + + Create a new message factory context. + + A new context. + + A context is used to parse messages from a specific endpoint. + + + + + Release a used factory context. + + + + + + A request have been received from one of the end points. + + + + + A response have been received from one of the end points. + + + + + Priority for log entries + + + + + + Very detailed logs to be able to follow the flow of the program. + + + + + Logs to help debug errors in the application + + + + + Information to be able to keep track of state changes etc. + + + + + Something did not go as we expected, but it's no problem. + + + + + Something that should not fail failed, but we can still keep + on going. + + + + + Something failed, and we cannot handle it properly. + + + + + Parses . + + + + + Parse a header + + Name of header. + Reader containing value. + HTTP Header + Header value is not of the expected format. + + + + Form parameters where form string arrays have been converted to real arrays. + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class. + + The name. + The value. + + + + Initializes a new instance of the class. + + Parse parameters from the this collection. + + + + Get a parameter. + + + + + + + Add a parameter + + Name of parameter, can contain a string array. + Value + + + ArrayParameterCollection array = new ArrayParameterCollection(); + array.Add("user[FirstName]", "Jonas"); + array.Add("user[FirstName]", "Arne"); + string firstName = array["user"]["FirstName"].Value; // "Arne" is returned + foreach (string value in array["user"]["FirstName"]) + Console.WriteLine(value); // each name is displayed. + + + + + + Checks if the specified parameter exists + + Parameter name. + true if found; otherwise false; + + + + Returns an enumerator that iterates through the collection. + + + A that can be used to iterate through the collection. + + 1 + + + + Gets first value of an item. + + + String if found; otherwise null. + + + + Gets number of parameters. + + + + + Gets last value of an parameter. + + Parameter name + String if found; otherwise null. + + + + Assign properties from HTTP parameters. + + + + + Used to filter out properties. + + Filter handler. + Handler have already been set. + + + + Assign properties in the specified object. + + Object to fill. + Contains all parameters that should be assigned to the properties. + Properties was not found or value could not be converted. + Any parameter is null. + + + + Used to be able to filter properties + + Model having it's properties assigned + Property about to be assigned + Value to assign + true if value can be set; otherwise false. + + + + Failed to assign properties. + + + + + Initializes a new instance of the class. + + The property errors. + + + + Gets all errors during assignment. + + + Dictionary key is property name. + + + + + Requested resource may not be accessed. + + + Normally thrown after an authentication attempt have failed too many times. + + + + + + Initializes a new instance of the class. + + Exception description. + + + + Initializes a new instance of the class. + + Exception description. + Inner exception. + + + + User needs to authenticate. + + + + + + + Initializes a new instance of the class. + + Exception description. + + + + Initializes a new instance of the class. + + Exception description. + Inner exception. + + + + First line in a response have been received + + + + + Gets or sets motivation to why the status code was used. + + + + + Gets or sets message status code + + + + + Gets or sets sip protocol version used. + + + + + Request context + + + Contains information about a HTTP request and where it came from. + + + + + Gets or sets http context. + + + + + Gets or sets http request. + + + + + Gets or sets http response. + + + + + Header for "Date" and "If-Modified-Since" + + + + The field value is an HTTP-date, as described in section 3.3.1 in RFC2616; + it MUST be sent in RFC 1123 [8]-date format. An example is + + Date: Tue, 15 Nov 1994 08:12:31 GMT + + Origin servers MUST include a Date header field in all + responses, except in these cases: + + If the response status code is 100 (Continue) or 101 (Switching + Protocols), the response MAY include a Date header field, at the server's + option. + If the response status code conveys a server error, e.g. 500 + (Internal Server Error) or 503 (Service Unavailable), and it is inconvenient + or impossible to generate a valid Date. + If the server does not have a clock that can provide a + reasonable approximation of the current time, its responses MUST NOT include + a Date header field. In this case, the rules in section 14.18.1 in RFC2616 + MUST be followed. + + + A received message that does not have a Date header field MUST + be assigned one by the recipient if the message will be cached by that + recipient or gatewayed via a protocol which requires a Date. An HTTP + implementation without a clock MUST NOT cache responses without revalidating + them on every use. An HTTP cache, especially a shared cache, SHOULD use a + mechanism, such as NTP [28], to synchronize its clock with a reliable + external standard. + Clients SHOULD only send a Date header field in messages that + include an entity-body, as in the case of the PUT and POST requests, and + even then it is optional. A client without a clock MUST NOT send a Date + header field in a request. + The HTTP-date sent in a Date header SHOULD NOT represent a date + and time subsequent to the generation of the message. It SHOULD represent + the best available approximation of the date and time of message generation, + unless the implementation has no means of generating a reasonably accurate + date and time. In theory, the date ought to represent the moment just before + the entity is generated. In practice, the date can be generated at any time + during the message origination without affecting its semantic value. + + + + + + Header name + + + + + Initializes a new instance of the class. + + Header name. + Name must not be empty. + + + + Initializes a new instance of the class. + + Header name. + Universal time. + + + + Returns data formatted as a HTTP header value. + + + A that represents the current . + + + + + Gets or sets date time. + + Should be in UTC. + + + + Gets header name + + + + + The Cache-Control general-header field is used to specify directives that + MUST be obeyed by all caching mechanisms along the request/response + chain. . + + + + The directives specify behavior intended to prevent caches from adversely + interfering with the request or response. These directives typically + override the default caching algorithms. Cache directives are + unidirectional in that the presence of a directive in a request does not + imply that the same directive is to be given in the response. + Note that HTTP/1.0 caches might not implement Cache-Control and + might only implement Pragma: no-cache (see section 14.32 in RFC2616). + Cache directives MUST be passed through by a proxy or gateway + application, regardless of their significance to that application, since the + directives might be applicable to all recipients along the request/response + chain. It is not possible to specify a cache- directive for a specific cache + + + When a directive appears without any 1#field-name parameter, the + directive applies to the entire request or response. When such a + directive appears with a 1#field-name parameter, it applies only to + the named field or fields, and not to the rest of the request or + response. This mechanism supports extensibility; implementations of + future versions of the HTTP protocol might apply these directives to + header fields not defined in HTTP/1.1. + + + The cache-control directives can be broken down into these general + categories: + + + Restrictions on what are cacheable; these may only be imposed by + the origin server. + + Restrictions on what may be stored by a cache; these may be + imposed by either the origin server or the user agent. + + Modifications of the basic expiration mechanism; these may be + imposed by either the origin server or the user agent. + + Controls over cache revalidation and reload; these may only be + imposed by a user agent. + + Control over transformation of entities. + + Extensions to the caching system. + + + + + + + + Header name + + + + + Gets header name + + + + + Authorization response + + + + A user agent that wishes to authenticate itself with a server-- + usually, but not necessarily, after receiving a 401 response--does + so by including an Authorization request-header field with the + request. The Authorization field value consists of credentials + containing the authentication information of the user agent for + the realm of the resource being requested. + + + Authorization = "Authorization" ":" credentials + + + HTTP access authentication is described in "HTTP Authentication: + Basic and Digest Access Authentication" [43]. If a request is + authenticated and a realm specified, the same credentials SHOULD + be valid for all other requests within this realm (assuming that + the authentication scheme itself does not require otherwise, such + as credentials that vary according to a challenge value or using + synchronized clocks). + When a shared cache (see section 13.7) receives a request + containing an Authorization field, it MUST NOT return the + corresponding response as a reply to any other request, unless one + of the following specific exceptions holds: + + + + If the response includes the "s-maxage" cache-control + directive, the cache MAY use that response in replying to a + subsequent request. But (if the specified maximum age has + passed) a proxy cache MUST first revalidate it with the origin + server, using the request-headers from the new request to allow + the origin server to authenticate the new request. (This is the + defined behavior for s-maxage.) If the response includes "s- + maxage=0", the proxy MUST always revalidate it before re-using + it. + + If the response includes the "must-revalidate" cache-control + directive, the cache MAY use that response in replying to a + subsequent request. But if the response is stale, all caches + MUST first revalidate it with the origin server, using the + request-headers from the new request to allow the origin server + to authenticate the new request. + + If the response includes the "public" cache-control directive, + it MAY be returned in reply to any subsequent request. + + + + + + + Name constant + + + + + Gets or sets authentication data. + + + + + Gets or sets authentication protocol. + + + + + Gets name of header. + + + + + Factory is used to create new logs in the system. + + + + + Assigns log factory being used. + + The log factory. + A factory have already been assigned. + + + + Create a new logger. + + Type that requested a logger. + Logger for the specified type; + + + + A request have been received. + + + + + + + Initializes a new instance of the class. + + context that received the request. + Received request. + Response to send. + + + + Gets context that received the request. + + + Do not forget to set to true if you are sending + back a response manually through . + + + + + Gets or sets if the request have been handled. + + + The library will not attempt to send the response object + back to the client if this property is set to true. + + + + + Gets request object. + + + + + Gets response object. + + + + + Get or create components used in the web server framework + + + + + + + + Get or create a type. + + Type to create + Created type. + + Gets or creates types in the framework. + Check for more information on which + types the factory should contain. + + + + + Parses numerical values + + + + + Parse a header + + Name of header. + Reader containing value. + HTTP Header + Header value is not of the expected format. + + + + Contains parameters for HTTP headers. + + + + + Add a parameter + + name + value + + Existing parameter with the same name will be replaced. + + + + + Parse parameters. + + Parser containing buffer to parse. + A collection with all parameters (or just a empty collection). + Expected a value after equal sign. + + + + Parse parameters. + + Parser containing buffer to parse. + Parameter delimiter + A collection with all parameters (or just a empty collection). + Expected a value after equal sign. + + + + Returns a that represents the current . + + + A that represents the current . + + + + + Gets or sets a value + + parameter name + value if found; otherwise null. + + + + Component that should be registered in the container. + + + Register using all interfaces that is specified in this assembly. + + + + + Stream-based multipart handling. + + In this incarnation deals with an HttpInputStream as we are now using + IntPtr-based streams instead of byte []. In the future, we will also + send uploads above a certain threshold into the disk (to implement + limit-less HttpInputFiles). + + + Taken from HttpRequest in mono (http://www.mono-project.com) + + + + + Interface used to write to log files. + + + If you want to use the built in filtering mechanism, create a constructor + which takes one parameter, a . + + + + + Write an entry that helps when debugging code. + + Log message + + + + Write an entry that helps when debugging code. + + Log message + Thrown exception to log. + + + + Something went wrong, but the application do not need to die. The current thread/request + cannot continue as expected. + + Log message + + + + Something went wrong, but the application do not need to die. The current thread/request + cannot continue as expected. + + Log message + Thrown exception to log. + + + + Something went very wrong, application might not recover. + + Log message + + + + Something went very wrong, application might not recover. + + Log message + Thrown exception to log. + + + + Informational message, needed when helping customer to find a problem. + + Log message + + + + Informational message, needed when helping customer to find a problem. + + Log message + Thrown exception to log. + + + + Write a entry that helps when trying to find hard to find bugs. + + Log message + + + + Write a entry that helps when trying to find hard to find bugs. + + Log message + Thrown exception to log. + + + + Something is not as we expect, but the code can continue to run without any changes. + + Log message + + + + Something is not as we expect, but the code can continue to run without any changes. + + Log message + Thrown exception to log. + + + + Used to create all key types in the HTTP server. + + + Should have factory methods at least for the following types: + , , + , , + , , + , , + . + + Check the default implementations to see which constructor + parameters you will get. + + + HttpFactory.Add(typeof(IRequest), (type, args) => new MyRequest((string)args[0])); + + + + + + Initializes a new instance of the class. + + + + + Add a factory method for a type. + + Type to create + Method creating the type. + + + + Used to + + + + + + + Setup our singleton. + + + + + + We want to use a singleton, but we also want to be able + to let the developer to setup his own header factory. + Therefore we use this method to create our own factory only if the user + have not specified one. + + + + + Small method to create a message factory singleton and replace then default delegate method. + + + + + + + + Create a type. + + Type to create + Created type. + + + + Gets http factory for the current listener. + + + + + Delegate used to create a certain type + + Created type. + + Method must never fail. + + + + + Contains numerical value. + + + + + Initializes a new instance of the class. + + The name. + The value. + + + + Returns data formatted as a HTTP header value. + + + A that represents the current . + + + + + Gets value + + + + + Gets header name + + + + + Contents of a cookie header. + + + + + Initializes a new instance of the class. + + The collection. + collection is null. + + + + Gets cookie collection + + + + + Gets header name + + + + + Gets value as it would be sent back to client. + + + + + + Data decoded from a POST body. + + + + + Initializes a new instance of the class. + + + + + Gets or sets decoded files. + + + + + Gets or sets decoded parameters. + + + + + Collection of body decoders. + + + Body decoders are used to parse request body and convert it + into a and a . + + + + + Add another body decoder. + + + + + + Decode body stream + + Stream containing the content + Content type header + Stream encoding + Decoded data. + Body format is invalid for the specified content type. + Something unexpected failed. + + + + Returns an enumerator that iterates through the collection. + + + A that can be used to iterate through the collection. + + 1 + + + + Returns an enumerator that iterates through a collection. + + + An object that can be used to iterate through the collection. + + 2 + + + + Gets number of decoders. + + + + + Credits and description: http://theinstructionlimit.com/?p=76 + + + Converted to .Net 2.0 + + + + + Type cached for fast property value modifications. + + + + + Get a property value. + + Instance to get value from. + Name of property. + Property value. + + + + Assign a value, try to convert it if it's not the same type as the property type. + + Object containing the property + Name of property + Value to convert and assign + Failed to find property. + Could not convert value type to property type. + + + + Assign value to a property + + Object containing the property + Name of property + Value to assign, must be of the same type as the property. + Failed to find property. + + + + Used to cache property information + + + + + Gets the property. + + The name. + + Failed to find property. + + + InvalidCastException. + + + + Get a property value. + + Instance to get value from. + Name of property. + Property value. + + + + Assign a value, try to convert it if it's not the same type as the property type. + + Object containing the property + Name of property + Value to convert and assign + Failed to find property. + Could not convert value type to property type. + + + + Assign value to a property + + Object containing the property + Name of property + Value to assign, must be of the same type as the property. + Failed to find property. + + + + Gets or sets member info + + + + + Gets or sets member type + + + + + A request have been received. + + + + + Initializes a new instance of the class. + + The request. + End point that the request was received from. + + + + End point that the message was received from. + + + + + Received request. + + + + + Creates a single message for one of the end points. + + + The factory is + + + + + Initializes a new instance of the class. + + The MSG factory. + The factory. + The parser. + + + + Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + + 2 + + + + Received a header from parser + + + + + + + Will continue the parsing until nothing more can be parsed. + + buffer to parse + where to start in the buffer + number of bytes to process. + Position where parser stopped parsing. + Parsing failed. + + + + Reset parser. + + + Something failed, reset parser so it can start on a new request. + + + + + A request have been successfully parsed. + + + + + A response have been successfully parsed. + + + + + Client asks if he may continue. + + + If the body is too large or anything like that you should respond . + + + + + Used to notify about 100-continue header. + + + + + Initializes a new instance of the class. + + request that want to continue. + + + + Gets request that want to continue + + + + + Default log writer, writes everything to void (nowhere). + + + + + + The logging instance. + + + + + Write an entry that helps when debugging code. + + Log message + + + + Write an entry that helps when debugging code. + + Log message + Thrown exception to log. + + + + Write a entry needed when following through code during hard to find bugs. + + Log message + + + + Write a entry that helps when trying to find hard to find bugs. + + Log message + Thrown exception to log. + + + + Informational message, needed when helping customer to find a problem. + + Log message + + + + Informational message, needed when helping customer to find a problem. + + Log message + Thrown exception to log. + + + + Something is not as we expect, but the code can continue to run without any changes. + + Log message + + + + Something is not as we expect, but the code can continue to run without any changes. + + Log message + Thrown exception to log. + + + + Something went wrong, but the application do not need to die. The current thread/request + cannot continue as expected. + + Log message + + + + Something went wrong, but the application do not need to die. The current thread/request + cannot continue as expected. + + Log message + Thrown exception to log. + + + + Something went very wrong, application might not recover. + + Log message + + + + Something went very wrong, application might not recover. + + Log message + Thrown exception to log. + + + + This class writes to the console. + + + It colors the output depending on the log level + and includes a 3-level stack trace (in debug mode) + + + + + + Initializes a new instance of the class. + + Type being logged. + Log filter. + + + + Get color for the specified log level + + Level for the log entry + A for the level + + + + Write an entry + + Importance of the log message + The message. + + + + Write an entry that helps when debugging code. + + Log message + + + + Write an entry that helps when debugging code. + + Log message + Thrown exception to log. + + + + Write a entry needed when following through code during hard to find bugs. + + Log message + + + + Write a entry that helps when trying to find hard to find bugs. + + Log message + Thrown exception to log. + + + + Informational message, needed when helping customer to find a problem. + + Log message + + + + Informational message, needed when helping customer to find a problem. + + Log message + Thrown exception to log. + + + + Something is not as we expect, but the code can continue to run without any changes. + + Log message + + + + Something is not as we expect, but the code can continue to run without any changes. + + Log message + Thrown exception to log. + + + + Something went wrong, but the application do not need to die. The current thread/request + cannot continue as expected. + + Log message + + + + Something went wrong, but the application do not need to die. The current thread/request + cannot continue as expected. + + Log message + Thrown exception to log. + + + + Something went very wrong, application might not recover. + + Log message + + + + Something went very wrong, application might not recover. + + Log message + Thrown exception to log. + + + + Gets or sets type that the logger is for + + + + + Creates a console logger. + + + + + Initializes a new instance of the class. + + The filter. + + + + Create a new logger. + + Type that requested a logger. + Logger for the specified type; + + MUST ALWAYS return a logger. Return if no logging + should be used. + + + + + Cookies that should be set. + + + + + Adds a cookie in the collection. + + cookie to add + cookie is null + Name and Content must be specified. + + + + Copy a request cookie + + + When the cookie should expire + + + + Remove all cookies + + + + + Gets a collection enumerator on the cookie list. + + collection enumerator + + + + Returns an enumerator that iterates through the collection. + + + + A that can be used to iterate through the collection. + + 1 + + + + Gets the count of cookies in the collection. + + + + + Gets the cookie of a given identifier. + + Cookie if found; otherwise null. + + + + Provider returning user to be authenticated. + + + + + Lookups the specified user + + User name. + Typically web server domain name. + User if found; otherwise null. + + User name can basically be anything. For instance name entered by user when using + basic or digest authentication, or SID when using Windows authentication. + + + + + Gets the principal to use. + + Successfully authenticated user. + + + Invoked when a user have successfully been authenticated. + + + + + + + User information used during authentication process. + + + + + Gets or sets user name used during authentication. + + + + + Gets or sets unencrypted password. + + + Password as clear text. You could use instead if your passwords + are encrypted in the database. + + + + + Gets or sets HA1 hash. + + + + Digest authentication requires clear text passwords to work. If you + do not have that, you can store a HA1 hash in your database (which is part of + the Digest authentication process). + + + A HA1 hash is simply a Md5 encoded string: "UserName:Realm:Password". The quotes should + not be included. Realm is the currently requested Host (as in Request.Headers["host"]). + + + Leave the string as null if you are not using HA1 hashes. + + + + + + Provides authentication in the web server. + + + To initiate authentication you just need to throw a Una + + + + + Add a authenticator. + + + + + + Authenticate request. + + + + + Requires that a AuthorizationHeader have been sent by the client. If not, + request one by sending a WWW-Authentication header (can be generated by the Challenge method). + + Authorization header was not found in the request. + Requested authentication scheme is not supported. + + + + Create a challenge header (WWW-authenticate) + + Response that the authentication header should be added to + Realm that the user should authenticate in + WWW-Authenticate header. + + + Scheme can currently be basic or digest. Basic is not very safe, but easier to use. + Digest is quite safe. + + + + Requested scheme is not supported. + + + diff --git a/TShockAPI/Commands.cs b/TShockAPI/Commands.cs index 9fc50466..fed39020 100644 --- a/TShockAPI/Commands.cs +++ b/TShockAPI/Commands.cs @@ -1,4 +1,4 @@ -/* +/* TShock, a server mod for Terraria Copyright (C) 2011 The TShock Team @@ -18,7 +18,7 @@ along with this program. If not, see . using System; using System.Collections.Generic; using System.Diagnostics; -using System.Drawing; + using System.IO; using System.Linq; using System.Net; @@ -36,7 +36,7 @@ namespace TShockAPI public string Message { get; private set; } public TSPlayer Player { get; private set; } /// - /// Parameters passed to the arguement. Does not include the command name. + /// Parameters passed to the arguement. Does not include the command name. /// IE '/kick "jerk face"' will only have 1 argument /// public List Parameters { get; private set; } @@ -137,6 +137,7 @@ namespace TShockAPI add(Permissions.tp, Spawn, "spawn"); add(Permissions.tp, TP, "tp"); add(Permissions.tphere, TPHere, "tphere"); + add(Permissions.tphere, SendWarp, "sendwarp", "sw"); add(Permissions.warp, UseWarp, "warp"); add(Permissions.managewarp, SetWarp, "setwarp"); add(Permissions.managewarp, DeleteWarp, "delwarp"); @@ -151,6 +152,7 @@ namespace TShockAPI add(Permissions.cfg, ShowConfiguration, "showconfig"); add(Permissions.cfg, ServerPassword, "serverpassword"); add(Permissions.cfg, Save, "save"); + add(Permissions.cfg, Settle, "settle"); add(Permissions.cfg, MaxSpawns, "maxspawns"); add(Permissions.cfg, SpawnRate, "spawnrate"); add(Permissions.time, Time, "time"); @@ -164,6 +166,7 @@ namespace TShockAPI add(null, AuthToken, "auth"); add(null, ThirdPerson, "me"); add(null, PartyChat, "p"); + add(null, Motd, "motd"); add(null, Rules, "rules"); add(Permissions.logs, DisplayLogs, "displaylogs"); ChatCommands.Add(new Command(PasswordUser, "password") { DoLog = false }); @@ -181,6 +184,7 @@ namespace TShockAPI add(Permissions.butcher, Butcher, "butcher"); add(Permissions.item, Item, "item", "i"); add(Permissions.item, Give, "give"); + add(Permissions.clearitems, ClearItems, "clearitems"); add(Permissions.heal, Heal, "heal"); add(Permissions.buff, Buff, "buff"); add(Permissions.buffplayer, GBuff, "gbuff", "buffplayer"); @@ -350,7 +354,6 @@ namespace TShockAPI private static void PasswordUser(CommandArgs args) { - try { if (args.Player.IsLoggedIn && args.Parameters.Count == 2) @@ -430,6 +433,13 @@ namespace TShockAPI // return; //} + // This guy needs to be here so that people don't get exceptions when they type /user + if (args.Parameters.Count < 1) + { + args.Player.SendMessage("Invalid user syntax. Try /user help.", Color.Red); + return; + } + string subcmd = args.Parameters[0]; // Add requires a username:password pair/ip address and a group specified. @@ -899,7 +909,6 @@ namespace TShockAPI Tools.ForceKickAll("Server shutting down for update!"); WorldGen.saveWorld(); Netplay.disconnect = true; - } #endregion Server Maintenence Commands @@ -918,7 +927,7 @@ namespace TShockAPI int penis57 = Main.rand.Next(Main.maxTilesX - 50) + 100; penis57 *= 0x10; int penis58 = Main.rand.Next((int)(Main.maxTilesY * 0.05)) * 0x10; - PointF vector = new PointF(penis57, penis58); + Vector2 vector = new Vector2(penis57, penis58); float speedX = Main.rand.Next(-100, 0x65); float speedY = Main.rand.Next(200) + 100; float penis61 = (float)Math.Sqrt(((speedX * speedX) + (speedY * speedY))); @@ -1202,6 +1211,42 @@ namespace TShockAPI } } + private static void SendWarp(CommandArgs args) + { + if (args.Parameters.Count < 2) + { + args.Player.SendMessage("Invalid syntax! Proper syntax: /sendwarp [player] [warpname]", Color.Red); + return; + } + + var foundplr = Tools.FindPlayer(args.Parameters[0]); + if (foundplr.Count == 0) + { + args.Player.SendMessage("Invalid player!", Color.Red); + return; + } + else if (foundplr.Count > 1) + { + args.Player.SendMessage(string.Format("More than one ({0}) player matched!", args.Parameters.Count), Color.Red); + return; + } + string warpName = String.Join(" ", args.Parameters[1]); + var warp = TShock.Warps.FindWarp(warpName); + var plr = foundplr[0]; + if (warp.WarpPos != Vector2.Zero) + { + if (plr.Teleport((int)warp.WarpPos.X, (int)warp.WarpPos.Y + 3)) + { + plr.SendMessage(string.Format("{0} Warped you to {1}", args.Player.Name, warpName), Color.Yellow); + args.Player.SendMessage(string.Format("You warped {0} to {1}.", plr.Name, warpName), Color.Yellow); + } + } + else + { + args.Player.SendMessage("Specified warp not found", Color.Red); + } + } + private static void SetWarp(CommandArgs args) { if (args.Parameters.Count > 0) @@ -1327,7 +1372,7 @@ namespace TShockAPI { string warpName = String.Join(" ", args.Parameters); var warp = TShock.Warps.FindWarp(warpName); - if (warp.WarpPos != PointF.Empty) + if (warp.WarpPos != Vector2.Zero) { if (args.Player.Teleport((int)warp.WarpPos.X, (int)warp.WarpPos.Y + 3)) args.Player.SendMessage("Warped to " + warpName, Color.Yellow); @@ -1337,7 +1382,6 @@ namespace TShockAPI args.Player.SendMessage("Specified warp not found", Color.Red); } } - } #endregion Teleport Commands @@ -1538,9 +1582,21 @@ namespace TShockAPI SaveWorld.Start(); } - private static void MaxSpawns(CommandArgs args) + private static void Settle(CommandArgs args) { + if (Liquid.panicMode) + { + args.Player.SendMessage("Liquid is already settling!", Color.Red); + return; + } + Liquid.StartPanic(); + Tools.Broadcast("Settling all liquids..."); + + } + + private static void MaxSpawns(CommandArgs args) + { if (args.Parameters.Count != 1) { args.Player.SendMessage("Invalid syntax! Proper syntax: /maxspawns ", Color.Red); @@ -1688,7 +1744,6 @@ namespace TShockAPI } switch (cmd) { - case "name": { { @@ -1697,7 +1752,6 @@ namespace TShockAPI } break; } - case "set": { int choice = 0; @@ -1718,7 +1772,7 @@ namespace TShockAPI { if (args.Parameters.Count > 1) { - if (!args.Player.TempPoints.Any(p => p == PointF.Empty)) + if (!args.Player.TempPoints.Any(p => p == Point.Zero)) { string regionName = String.Join(" ", args.Parameters.GetRange(1, args.Parameters.Count - 1)); var x = Math.Min(args.Player.TempPoints[0].X, args.Player.TempPoints[1].X); @@ -1728,8 +1782,8 @@ namespace TShockAPI if (TShock.Regions.AddRegion(x, y, width, height, regionName, Main.worldID.ToString())) { - args.Player.TempPoints[0] = Point.Empty; - args.Player.TempPoints[1] = Point.Empty; + args.Player.TempPoints[0] = Point.Zero; + args.Player.TempPoints[1] = Point.Zero; args.Player.SendMessage("Set region " + regionName, Color.Yellow); } else @@ -1788,8 +1842,8 @@ namespace TShockAPI } case "clear": { - args.Player.TempPoints[0] = Point.Empty; - args.Player.TempPoints[1] = Point.Empty; + args.Player.TempPoints[0] = Point.Zero; + args.Player.TempPoints[1] = Point.Zero; args.Player.SendMessage("Cleared temp area", Color.Yellow); args.Player.AwaitingTempPoint = 0; break; @@ -1950,6 +2004,62 @@ namespace TShockAPI args.Player.SendMessage("Invalid syntax! Proper syntax: /region info [name]", Color.Red); } + break; + } + case "resize": + case "expand": + { + if (args.Parameters.Count == 4) + { + int direction; + switch (args.Parameters[3]) + { + case "u": + case "up": + { + direction = 0; + break; + } + case "r": + case "right": + { + direction = 1; + break; + } + case "d": + case "down": + { + direction = 2; + break; + } + case "l": + case "left": + { + direction = 3; + break; + } + default: + { + direction = -1; + break; + } + } + int addAmount; + int.TryParse(args.Parameters[2], out addAmount); + if (TShock.Regions.resizeRegion(args.Parameters[1], addAmount, direction)) + { + args.Player.SendMessage("Region Resized Successfully!", Color.Yellow); + TShock.Regions.ReloadAllRegions(); + } + else + { + args.Player.SendMessage("Invalid syntax! Proper syntax: /region resize [regionname] [u/d/l/r] [amount]", Color.Red); + } + } + else + { + args.Player.SendMessage("Invalid syntax! Proper syntax: /region resize [regionname] [u/d/l/r] [amount]1", Color.Red); + } break; } case "help": @@ -1960,10 +2070,10 @@ namespace TShockAPI args.Player.SendMessage("/region name (provides region name)", Color.Yellow); args.Player.SendMessage("/region delete [name] /region clear (temporary region)", Color.Yellow); args.Player.SendMessage("/region allow [name] [regionname]", Color.Yellow); + args.Player.SendMessage("/region resize [regionname] [u/d/l/r] [amount]", Color.Yellow); break; } } - } #endregion World Protection Commands @@ -2117,6 +2227,11 @@ namespace TShockAPI args.Player.SendMessage("You are not in a party!", 255, 240, 20); } } + + private static void Motd(CommandArgs args) + { + Tools.ShowFileToUser(args.Player, "motd.txt"); + } private static void Rules(CommandArgs args) { @@ -2185,6 +2300,7 @@ namespace TShockAPI (new Thread(ply.Whoopie)).Start(annoy); } } + #endregion General Commands #region Cheat Commands @@ -2359,6 +2475,50 @@ namespace TShockAPI } } + public static void ClearItems(CommandArgs args) + { + + int radius = 50; + if (args.Parameters.Count > 0) + { + + if (args.Parameters[0].ToLower() == "all") + { + + radius = Int32.MaxValue / 16; + + } + else + { + + try + { + + radius = Convert.ToInt32(args.Parameters[0]); + + } + catch (Exception) { args.Player.SendMessage("Please either enter the keyword \"all\", or the block radius you wish to delete all items from.", Color.Red); return; } + + } + + } + int count = 0; + for (int i = 0; i < 200; i++) + { + + if ((Math.Sqrt(Math.Pow(Main.item[i].position.X - args.Player.X, 2) + Math.Pow(Main.item[i].position.Y - args.Player.Y, 2)) < radius * 16) && (Main.item[i].active)) + { + + Main.item[i].active = false; + NetMessage.SendData(0x15, -1, -1, "", i, 0f, 0f, 0f, 0); + count++; + } + + } + args.Player.SendMessage("All " + count.ToString() + " items within a radius of " + radius.ToString() + " have been deleted."); + + } + private static void Heal(CommandArgs args) { TSPlayer playerToHeal; @@ -2563,8 +2723,10 @@ namespace TShockAPI args.Player.SendMessage("Unknown plant!", Color.Red); return; } - args.Player.SendMessage("You have grown a " + name, Color.Green); + args.Player.SendTileSquare(x, y); + args.Player.SendMessage("Tried to grow a " + name, Color.Green); } + #endregion Cheat Comamnds } } diff --git a/TShockAPI/ConfigFile.cs b/TShockAPI/ConfigFile.cs index 3faf935f..7a243147 100644 --- a/TShockAPI/ConfigFile.cs +++ b/TShockAPI/ConfigFile.cs @@ -187,6 +187,18 @@ namespace TShockAPI [Description("This will announce a player's location on join")] public bool EnableGeoIP = false; + [Description("This will turn on a token requirement for the /status API endpoint.")] + public bool EnableTokenEndpointAuthentication = false; + + [Description("This is used when the API endpoint /status is queried.")] + public string ServerNickname = "TShock Server"; + + [Description("Enable/Disable the rest api.")] + public bool RestApiEnabled = false; + + [Description("This is the port which the rest api will listen on.")] + public int RestApiPort = 7878; + public static ConfigFile Read(string path) { if (!File.Exists(path)) diff --git a/TShockAPI/DB/GroupManager.cs b/TShockAPI/DB/GroupManager.cs index 70e444d2..1fd408a3 100644 --- a/TShockAPI/DB/GroupManager.cs +++ b/TShockAPI/DB/GroupManager.cs @@ -154,8 +154,10 @@ namespace TShockAPI.DB permissions.AddRange(group.permissions.Where(s => !permissions.Contains(s))); if (database.Query("UPDATE GroupList SET Commands=@0 WHERE GroupName=@1", String.Join(",", permissions), name) != 0) + { message = "Group " + name + " has been modified successfully."; - + group.SetPermission( permissions ); + } return message; } @@ -168,11 +170,13 @@ namespace TShockAPI.DB var group = Tools.GetGroup(name); //Only get permissions that exist in the group. - var newperms = permissions.Where(s => group.permissions.Contains(s)); + var newperms = group.permissions.Except( permissions ); if (database.Query("UPDATE GroupList SET Commands=@0 WHERE GroupName=@1", String.Join(",", newperms), name) != 0) + { message = "Group " + name + " has been modified successfully."; - + group.SetPermission( newperms.ToList() ); + } return message; } diff --git a/TShockAPI/DB/RegionManager.cs b/TShockAPI/DB/RegionManager.cs index cd4c2faf..5c78241b 100644 --- a/TShockAPI/DB/RegionManager.cs +++ b/TShockAPI/DB/RegionManager.cs @@ -20,7 +20,7 @@ using System; using System.Collections.Generic; using System.Data; using System.Diagnostics.CodeAnalysis; -using System.Drawing; + using System.IO; using System.Linq; using System.Xml; @@ -378,6 +378,68 @@ namespace TShockAPI.DB { return MergedIDs.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList(); } + + public bool resizeRegion(string regionName, int addAmount, int direction) + { + //0 = up + //1 = right + //2 = down + //3 = left + int X = 0; + int Y = 0; + int height = 0; + int width = 0; + try + { + using (var reader = database.QueryReader("SELECT X1, Y1, height, width FROM Regions WHERE RegionName=@0 AND WorldID=@1", regionName, Main.worldID.ToString())) + { + if (reader.Read()) + X = reader.Get("X1"); + width = reader.Get("width"); + Y = reader.Get("Y1"); + height = reader.Get("height"); + } + if (!(direction == 0)) + { + if (!(direction == 1)) + { + if (!(direction == 2)) + { + if (!(direction == 3)) + { + return false; + } + else + { + X -= addAmount; + width += addAmount; + } + } + else + { + height += addAmount; + } + } + else + { + width += addAmount; + } + } + else + { + Y -= addAmount; + height += addAmount; + } + int q = database.Query("UPDATE Regions SET X1 = @0, Y1 = @1, width = @2, height = @3 WHERE RegionName = @4 AND WorldID=@5", X, Y, width, height, regionName, Main.worldID.ToString()); + if (q > 0) + return true; + } + catch (Exception ex) + { + Log.Error(ex.ToString()); + } + return false; + } public bool RemoveUser(string regionName, string userName) { diff --git a/TShockAPI/DB/RememberPosManager.cs b/TShockAPI/DB/RememberPosManager.cs index 4bb546dc..71a9bc5e 100644 --- a/TShockAPI/DB/RememberPosManager.cs +++ b/TShockAPI/DB/RememberPosManager.cs @@ -18,7 +18,7 @@ along with this program. If not, see . using System; using System.Data; -using System.Drawing; + using MySql.Data.MySqlClient; using Terraria; @@ -43,7 +43,7 @@ namespace TShockAPI.DB creator.EnsureExists(table); } - public PointF GetLeavePos(string name, string IP) + public Vector2 GetLeavePos(string name, string IP) { try { @@ -51,7 +51,7 @@ namespace TShockAPI.DB { if (reader.Read()) { - return new PointF(reader.Get("X"), reader.Get("Y")); + return new Vector2(reader.Get("X"), reader.Get("Y")); } } } @@ -60,12 +60,12 @@ namespace TShockAPI.DB Log.Error(ex.ToString()); } - return new PointF(); + return new Vector2(); } public void InsertLeavePos(string name, string IP, int X, int Y) { - if (GetLeavePos(name, IP) == PointF.Empty) + if (GetLeavePos(name, IP) == Vector2.Zero) { try { diff --git a/TShockAPI/DB/WarpsManager.cs b/TShockAPI/DB/WarpsManager.cs index d265caa9..c1599e0b 100644 --- a/TShockAPI/DB/WarpsManager.cs +++ b/TShockAPI/DB/WarpsManager.cs @@ -19,7 +19,7 @@ along with this program. If not, see . using System; using System.Collections.Generic; using System.Data; -using System.Drawing; + using System.IO; using System.Xml; using MySql.Data.MySqlClient; @@ -173,11 +173,11 @@ namespace TShockAPI.DB { try { - return new Warp(new PointF(reader.Get("X"), reader.Get("Y")), reader.Get("WarpName"), reader.Get("WorldID"), reader.Get("Private")); + return new Warp(new Vector2(reader.Get("X"), reader.Get("Y")), reader.Get("WarpName"), reader.Get("WorldID"), reader.Get("Private")); } catch { - return new Warp(new PointF(reader.Get("X"), reader.Get("Y")), reader.Get("WarpName"), reader.Get("WorldID"), "0"); + return new Warp(new Vector2(reader.Get("X"), reader.Get("Y")), reader.Get("WarpName"), reader.Get("WorldID"), "0"); } } } @@ -247,12 +247,12 @@ namespace TShockAPI.DB public class Warp { - public PointF WarpPos { get; set; } + public Vector2 WarpPos { get; set; } public string WarpName { get; set; } public string WorldWarpID { get; set; } public string Private { get; set; } - public Warp(PointF warppos, string name, string worldid, string hidden) + public Warp(Vector2 warppos, string name, string worldid, string hidden) { WarpPos = warppos; WarpName = name; @@ -262,7 +262,7 @@ namespace TShockAPI.DB public Warp() { - WarpPos = PointF.Empty; + WarpPos = Vector2.Zero; WarpName = null; WorldWarpID = string.Empty; Private = "0"; diff --git a/TShockAPI/Extensions/DbExt.cs b/TShockAPI/Extensions/DbExt.cs index 52f5c011..66d7ac8b 100644 --- a/TShockAPI/Extensions/DbExt.cs +++ b/TShockAPI/Extensions/DbExt.cs @@ -52,6 +52,20 @@ namespace TShockAPI.DB } } + public static QueryResult QueryReaderDict(this IDbConnection olddb, string query, Dictionary values) + { + var db = olddb.CloneEx(); + db.Open(); + using (var com = db.CreateCommand()) + { + com.CommandText = query; + foreach(var kv in values) + com.AddParameter("@" + kv.Key, kv.Value); + + return new QueryResult(db, com.ExecuteReader()); + } + } + public static IDbDataParameter AddParameter(this IDbCommand command, string name, object data) { var parm = command.CreateParameter(); @@ -157,10 +171,14 @@ namespace TShockAPI.DB public bool Read() { + if (Reader == null) + return false; return Reader.Read(); } public T Get(string column) { + if (Reader == null) + return default(T); return Reader.Get(Reader.GetOrdinal(column)); } } diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs index d6341b86..62d0fcb1 100644 --- a/TShockAPI/GetDataHandlers.cs +++ b/TShockAPI/GetDataHandlers.cs @@ -18,13 +18,13 @@ along with this program. If not, see . using System; using System.Collections.Generic; using System.Diagnostics; -using System.Drawing; + using System.IO; using System.Text; using Terraria; -using TerrariaAPI; + using TShockAPI.Net; -using XNAHelpers; +using System.IO.Streams; namespace TShockAPI { @@ -349,6 +349,13 @@ namespace TShockAPI args.Player.SendTileSquare(x, y); return true; } + if (type == 1 && tiletype == 21 && Tools.MaxChests()) + { + args.Player.SendMessage("Reached world's max chest limit, unable to place more!", Color.Red); + Log.Info("Reached world's chest limit, unable to place more."); + args.Player.SendTileSquare(x, y); + return true; + } } if (!args.Player.Group.HasPermission(Permissions.editspawn) && !TShock.Regions.CanBuild(x, y, args.Player) && TShock.Regions.InArea(x, y)) { @@ -393,9 +400,9 @@ namespace TShockAPI if (type == 0 && BlacklistTiles[Main.tile[x, y].type] && args.Player.Active) { args.Player.TileThreshold++; - var coords = new PointF(x, y); + var coords = new Vector2(x, y); if (!args.Player.TilesDestroyed.ContainsKey(coords)) - args.Player.TilesDestroyed.Add(coords, Main.tile[x, y]); + args.Player.TilesDestroyed.Add(coords, Main.tile[x, y].Data); } if ((DateTime.UtcNow - args.Player.LastExplosive).TotalMilliseconds < 1000) @@ -480,12 +487,18 @@ namespace TShockAPI return true; } - if (type == 23 && (vely == 0f || velx == 0f)) //float.IsNaN((float)Math.Sqrt((double)(velx * velx + vely * vely)))) + if (type == 23) { - Tools.HandleGriefer(args.Player, TShock.Config.ProjectileAbuseReason); - return true; + if (velx == 0f && vely == 0f && dmg == 99) + { + Tools.HandleGriefer(args.Player, TShock.Config.ProjectileAbuseReason); + return true; + } + else if (velx == 0f || vely == 0f) + return true; } + if (type == 29 || type == 28 || type == 37) { Log.Debug(string.Format("Explosive(PlyXY:{0}_{1}, Type:{2})", args.Player.TileX, args.Player.TileY, type)); diff --git a/TShockAPI/Group.cs b/TShockAPI/Group.cs index a7fbddb3..c089ff16 100644 --- a/TShockAPI/Group.cs +++ b/TShockAPI/Group.cs @@ -73,6 +73,14 @@ namespace TShockAPI { permissions.Add(permission); } + public void SetPermission( List permission) + { + permissions.Clear(); + foreach( string s in permission ) + { + permissions.Add( s ); + } + } } public class SuperAdminGroup : Group diff --git a/TShockAPI/Net/BaseMsg.cs b/TShockAPI/Net/BaseMsg.cs index ed41cf71..77fa041c 100644 --- a/TShockAPI/Net/BaseMsg.cs +++ b/TShockAPI/Net/BaseMsg.cs @@ -1,9 +1,10 @@ using System; using System.Collections.Generic; +using System.IO.Streams; using System.Linq; using System.Text; -using TerrariaAPI; -using XNAHelpers; + +using System.IO.Streams; namespace TShockAPI.Net { diff --git a/TShockAPI/Net/DisconnectMsg.cs b/TShockAPI/Net/DisconnectMsg.cs index ad1ebf57..a8318e6b 100644 --- a/TShockAPI/Net/DisconnectMsg.cs +++ b/TShockAPI/Net/DisconnectMsg.cs @@ -1,10 +1,6 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; +using System.IO; +using System.IO.Streams; using System.Text; -using TerrariaAPI; -using XNAHelpers; namespace TShockAPI.Net { diff --git a/TShockAPI/Net/NetTile.cs b/TShockAPI/Net/NetTile.cs index be269a61..8871065f 100644 --- a/TShockAPI/Net/NetTile.cs +++ b/TShockAPI/Net/NetTile.cs @@ -19,7 +19,7 @@ along with this program. If not, see . using System; using System.IO; using Terraria; -using XNAHelpers; +using System.IO.Streams; namespace TShockAPI.Net { diff --git a/TShockAPI/Net/SpawnMsg.cs b/TShockAPI/Net/SpawnMsg.cs index 29e9e4c9..dc851379 100644 --- a/TShockAPI/Net/SpawnMsg.cs +++ b/TShockAPI/Net/SpawnMsg.cs @@ -1,8 +1,5 @@ -using System.Collections.Generic; -using System.IO; -using System.Linq; -using TerrariaAPI; -using XNAHelpers; +using System.IO; +using System.IO.Streams; namespace TShockAPI.Net { diff --git a/TShockAPI/Net/WorldInfoMsg.cs b/TShockAPI/Net/WorldInfoMsg.cs index 1ba56691..8726ced4 100644 --- a/TShockAPI/Net/WorldInfoMsg.cs +++ b/TShockAPI/Net/WorldInfoMsg.cs @@ -19,8 +19,8 @@ along with this program. If not, see . using System; using System.IO; using System.Text; -using TerrariaAPI; -using XNAHelpers; + +using System.IO.Streams; namespace TShockAPI.Net { diff --git a/TShockAPI/PacketBufferer.cs b/TShockAPI/PacketBufferer.cs index 3b698a60..0257c78f 100644 --- a/TShockAPI/PacketBufferer.cs +++ b/TShockAPI/PacketBufferer.cs @@ -5,8 +5,8 @@ using System.IO; using System.Net.Sockets; using System.Text; using Terraria; -using TerrariaAPI; -using TerrariaAPI.Hooks; + +using Hooks; namespace TShockAPI { diff --git a/TShockAPI/Permissions.cs b/TShockAPI/Permissions.cs index 3d757948..60feba1b 100644 --- a/TShockAPI/Permissions.cs +++ b/TShockAPI/Permissions.cs @@ -123,6 +123,9 @@ namespace TShockAPI [Description("User can spawn items")] public static readonly string item; + [Description("User can clear item drops.")] + public static readonly string clearitems; + [Description("")] public static readonly string heal; diff --git a/TShockAPI/Properties/AssemblyInfo.cs b/TShockAPI/Properties/AssemblyInfo.cs index f2f36cc1..024b84db 100644 --- a/TShockAPI/Properties/AssemblyInfo.cs +++ b/TShockAPI/Properties/AssemblyInfo.cs @@ -36,5 +36,5 @@ using System.Runtime.InteropServices; // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("3.3.0.0905")] -[assembly: AssemblyFileVersion("3.3.0.0905")] +[assembly: AssemblyVersion("3.3.4.0926")] +[assembly: AssemblyFileVersion("3.3.4.0926")] \ No newline at end of file diff --git a/TShockAPI/RconHandler.cs b/TShockAPI/RconHandler.cs index ec34f563..d407a144 100644 --- a/TShockAPI/RconHandler.cs +++ b/TShockAPI/RconHandler.cs @@ -24,7 +24,7 @@ using System.Net.Sockets; using System.Text; using System.Threading; using Terraria; -using XNAHelpers; +using System.IO.Streams; namespace TShockAPI { @@ -38,13 +38,30 @@ namespace TShockAPI public static string Response = ""; private static bool Started; private static UdpClient listener; + private static Thread startThread; + private static Thread heartbeat; + private static Thread listen; + + public static void ShutdownAllThreads() + { + if (Started) + { + startThread.Abort(); + heartbeat.Abort(); + listen.Abort(); + Started = false; + } + } public static void StartThread() { if (!Started) { - (new Thread(Start)).Start(); - (new Thread(SendHeartbeat)).Start(); + startThread = new Thread(Start); + startThread.Start(); + + heartbeat = new Thread(SendHeartbeat); + heartbeat.Start(); } Started = true; } @@ -57,7 +74,7 @@ namespace TShockAPI Console.WriteLine(string.Format("RconHandler is running at UDP port {0} and password is {1}", ListenPort, Password)); - Thread listen = new Thread(Listener); + listen = new Thread(Listener); listen.Start(); while (true) { @@ -161,8 +178,8 @@ namespace TShockAPI } else { - response = "Bad rconpassword.\n"; - Log.ConsoleInfo("Bad rconpassword from " + EP); + response = "Bad rcon password.\n"; + Log.ConsoleInfo("Bad rcon password from " + EP); } } else @@ -170,7 +187,7 @@ namespace TShockAPI } else { - response = "No rconpassword set on the server.\n"; + response = "No rcon password set on the server.\n"; Log.Info("No password for rcon set"); } } @@ -328,7 +345,7 @@ namespace TShockAPI { if ((DateTime.UtcNow - LastHeartbeat).Seconds >= 30) { - var packet = ConstructPacket("heartbeat TERRARIA", false); + var packet = ConstructPacket("heartbeat TerrariaShock", false); if (listener == null) try { diff --git a/TShockAPI/Rest/Rest.cs b/TShockAPI/Rest/Rest.cs new file mode 100644 index 00000000..4c9c9e9f --- /dev/null +++ b/TShockAPI/Rest/Rest.cs @@ -0,0 +1,141 @@ +using System; +using System.Collections.Generic; +using System.Net; +using System.Text; +using System.Text.RegularExpressions; +using HttpServer; +using HttpServer.Headers; +using Newtonsoft.Json; +using HttpListener = HttpServer.HttpListener; + +namespace Rests +{ + /// + /// Rest command delegate + /// + /// Parameters in the url + /// {x} in urltemplate + /// Response object or null to not handle request + public delegate object RestCommandD(RestVerbs verbs, IParameterCollection parameters); + public class Rest : IDisposable + { + readonly List commands = new List(); + HttpListener listener; + public IPAddress Ip { get; set; } + public int Port { get; set; } + + public Rest(IPAddress ip, int port) + { + Ip = ip; + Port = port; + } + public virtual void Start() + { + if (listener == null) + { + listener = HttpListener.Create(Ip, Port); + listener.RequestReceived += OnRequest; + listener.Start(int.MaxValue); + } + } + public void Start(IPAddress ip, int port) + { + Ip = ip; + Port = port; + Start(); + } + public virtual void Stop() + { + listener.Stop(); + } + + public void Register(string path, RestCommandD callback) + { + AddCommand(new RestCommand(path, callback)); + } + + public void Register(RestCommand com) + { + AddCommand(com); + } + + protected void AddCommand(RestCommand com) + { + commands.Add(com); + } + + protected virtual void OnRequest(object sender, RequestEventArgs e) + { + var obj = ProcessRequest(sender, e); + if (obj == null) + throw new NullReferenceException("obj"); + + var str = JsonConvert.SerializeObject(obj, Formatting.Indented); + e.Response.Connection.Type = ConnectionType.Close; + e.Response.Body.Write(Encoding.ASCII.GetBytes(str), 0, str.Length); + e.Response.Status = HttpStatusCode.OK; + return; + } + + protected virtual object ProcessRequest(object sender, RequestEventArgs e) + { + var uri = e.Request.Uri.AbsolutePath; + uri = uri.TrimEnd('/'); + + foreach (var com in commands) + { + var verbs = new RestVerbs(); + if (com.HasVerbs) + { + var match = Regex.Match(uri, com.UriVerbMatch); + if (!match.Success) + continue; + if ((match.Groups.Count - 1) != com.UriVerbs.Length) + continue; + + for (int i = 0; i < com.UriVerbs.Length; i++) + verbs.Add(com.UriVerbs[i], match.Groups[i + 1].Value); + } + else if (com.UriTemplate.ToLower() != uri.ToLower()) + { + continue; + } + + var obj = ExecuteCommand(com, verbs, e.Request.Parameters); + if (obj != null) + return obj; + + } + return new Dictionary { { "status", "404" }, { "error", "Specified API endpoint doesn't exist. Refer to the documentation for a list of valid endpoints." } }; + } + + protected virtual object ExecuteCommand(RestCommand cmd, RestVerbs verbs, IParameterCollection parms) + { + return cmd.Callback(verbs, parms); + } + + #region Dispose + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + if (listener != null) + { + listener.Stop(); + listener = null; + } + } + } + ~Rest() + { + Dispose(false); + } + + #endregion + } +} diff --git a/TShockAPI/Rest/RestCommand.cs b/TShockAPI/Rest/RestCommand.cs new file mode 100644 index 00000000..5409282f --- /dev/null +++ b/TShockAPI/Rest/RestCommand.cs @@ -0,0 +1,47 @@ +using System.Linq; +using System.Text.RegularExpressions; + +namespace Rests +{ + public class RestCommand + { + public string Name { get; protected set; } + public string UriTemplate { get; protected set; } + public string UriVerbMatch { get; protected set; } + public string[] UriVerbs { get; protected set; } + public RestCommandD Callback { get; protected set; } + public bool RequiresToken { get; set; } + + /// + /// + /// + /// Used for identification + /// Url template + /// Rest Command callback + public RestCommand(string name, string uritemplate, RestCommandD callback) + { + Name = name; + UriTemplate = uritemplate; + UriVerbMatch = string.Format("^{0}$", string.Join("([^/]*)", Regex.Split(uritemplate, "\\{[^\\{\\}]*\\}"))); + var matches = Regex.Matches(uritemplate, "\\{([^\\{\\}]*)\\}"); + UriVerbs = (from Match match in matches select match.Groups[1].Value).ToArray(); + Callback = callback; + RequiresToken = true; + } + /// + /// + /// + /// Url template + /// Rest Command callback + public RestCommand(string uritemplate, RestCommandD callback) + : this(string.Empty, uritemplate, callback) + { + + } + + public bool HasVerbs + { + get { return UriVerbs.Length > 0; } + } + } +} \ No newline at end of file diff --git a/TShockAPI/Rest/RestManager.cs b/TShockAPI/Rest/RestManager.cs new file mode 100644 index 00000000..4c11b64e --- /dev/null +++ b/TShockAPI/Rest/RestManager.cs @@ -0,0 +1,448 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using HttpServer; +using Rests; +using Terraria; + +namespace TShockAPI +{ + + public class RestManager + { + private Rest Rest; + public RestManager(Rest rest) + { + Rest = rest; + } + + public void RegisterRestfulCommands() + { + Rest.Register(new RestCommand("/status", Status) { RequiresToken = false }); + Rest.Register(new RestCommand("/tokentest", TokenTest) { RequiresToken = true }); + + Rest.Register(new RestCommand("/users/read/{user}/info", UserInfo) { RequiresToken = true }); + Rest.Register(new RestCommand("/users/destroy/{user}", UserDestroy) { RequiresToken = true }); + Rest.Register(new RestCommand("/users/update/{user}", UserUpdate) { RequiresToken = true }); + + Rest.Register(new RestCommand("/bans/create", BanCreate) { RequiresToken = true }); + Rest.Register(new RestCommand("/bans/read/{user}/info", BanInfo) { RequiresToken = true }); + Rest.Register(new RestCommand("/bans/destroy/{user}", BanDestroy) { RequiresToken = true }); + + + Rest.Register(new RestCommand("/lists/players", UserList) { RequiresToken = true }); + + Rest.Register(new RestCommand("/world/read", WorldRead) { RequiresToken = true }); + Rest.Register(new RestCommand("/world/meteor", WorldMeteor) { RequiresToken = true }); + Rest.Register(new RestCommand("/world/bloodmoon/{bool}", WorldBloodmoon) { RequiresToken = true }); + + Rest.Register(new RestCommand("/players/read/{player}", PlayerRead) { RequiresToken = true }); + Rest.Register(new RestCommand("/players/{player}/kick", PlayerKick) { RequiresToken = true }); + Rest.Register(new RestCommand("/players/{player}/ban", PlayerBan) { RequiresToken = true }); + //RegisterExamples(); + } + + #region RestMethods + + object TokenTest(RestVerbs verbs, IParameterCollection parameters) + { + return new Dictionary { { "status", "200" }, { "response", "Token is valid and was passed through correctly." } }; + } + + object Status(RestVerbs verbs, IParameterCollection parameters) + { + if (TShock.Config.EnableTokenEndpointAuthentication) + return new RestObject("403") { Error = "Server settings require a token for this API call." }; + + var activeplayers = Main.player.Where(p => p != null && p.active).ToList(); + string currentPlayers = string.Join(", ", activeplayers.Select(p => p.name)); + + var ret = new RestObject("200"); + ret["name"] = TShock.Config.ServerNickname; + ret["port"] = Convert.ToString(TShock.Config.ServerPort); + ret["playercount"] = Convert.ToString(activeplayers.Count()); + ret["players"] = currentPlayers; + + return ret; + } + + #endregion + + #region RestUserMethods + + object UserList(RestVerbs verbs, IParameterCollection parameters) + { + var activeplayers = Main.player.Where(p => p != null && p.active).ToList(); + string currentPlayers = string.Join(", ", activeplayers.Select(p => p.name)); + var ret = new RestObject("200"); + ret["players"] = currentPlayers; + return ret; + } + + object UserUpdate(RestVerbs verbs, IParameterCollection parameters) + { + var returnBlock = new Dictionary(); + var password = parameters["password"]; + var group = parameters["group"]; + + if (group == null && password == null) + { + returnBlock.Add("status", "400"); + returnBlock.Add("error", "No parameters were passed."); + return returnBlock; + } + + var user = TShock.Users.GetUserByName(verbs["user"]); + if (user == null) + { + returnBlock.Add("status", "400"); + returnBlock.Add("error", "The specefied user doesn't exist."); + return returnBlock; + } + + if (password != null) + { + TShock.Users.SetUserPassword(user, password); + returnBlock.Add("password-response", "Password updated successfully."); + } + + if (group != null) + { + TShock.Users.SetUserGroup(user, group); + returnBlock.Add("group-response", "Group updated successfully."); + } + + returnBlock.Add("status", "200"); + return returnBlock; + } + + object UserDestroy(RestVerbs verbs, IParameterCollection parameters) + { + var user = TShock.Users.GetUserByName(verbs["user"]); + if (user == null) + { + return new Dictionary { { "status", "400" }, { "error", "The specified user account does not exist." } }; + } + var returnBlock = new Dictionary(); + try + { + TShock.Users.RemoveUser(user); + } + catch (Exception) + { + returnBlock.Add("status", "400"); + returnBlock.Add("error", "The specified user was unable to be removed."); + return returnBlock; + } + returnBlock.Add("status", "200"); + returnBlock.Add("response", "User deleted successfully."); + return returnBlock; + } + + object UserInfo(RestVerbs verbs, IParameterCollection parameters) + { + var user = TShock.Users.GetUserByName(verbs["user"]); + if (user == null) + { + return new Dictionary { { "status", "400" }, { "error", "The specified user account does not exist." } }; + } + + var returnBlock = new Dictionary(); + returnBlock.Add("status", "200"); + returnBlock.Add("group", user.Group); + returnBlock.Add("id", user.ID.ToString()); + return returnBlock; + } + + #endregion + + #region RestBanMethods + + object BanCreate(RestVerbs verbs, IParameterCollection parameters) + { + var returnBlock = new Dictionary(); + var ip = parameters["ip"]; + var name = parameters["name"]; + var reason = parameters["reason"]; + + if (ip == null && name == null) + { + returnBlock.Add("status", "400"); + returnBlock.Add("error", "Required parameters were missing from this API endpoint."); + return returnBlock; + } + + if (ip == null) + { + ip = ""; + } + + if (name == null) + { + name = ""; + } + + if (reason == null) + { + reason = ""; + } + + try + { + TShock.Bans.AddBan(ip, name, reason); + } + catch (Exception) + { + returnBlock.Add("status", "400"); + returnBlock.Add("error", "The specified ban was unable to be created."); + return returnBlock; + } + returnBlock.Add("status", "200"); + returnBlock.Add("response", "Ban created successfully."); + return returnBlock; + } + + object BanDestroy(RestVerbs verbs, IParameterCollection parameters) + { + var returnBlock = new Dictionary(); + + var type = parameters["type"]; + if (type == null) + { + returnBlock.Add("Error", "Invalid Type"); + return returnBlock; + } + + var ban = new DB.Ban(); + if (type == "ip") ban = TShock.Bans.GetBanByIp(verbs["user"]); + else if (type == "name") ban = TShock.Bans.GetBanByName(verbs["user"]); + else + { + returnBlock.Add("Error", "Invalid Type"); + return returnBlock; + } + + if (ban == null) + { + return new Dictionary { { "status", "400" }, { "error", "The specified ban does not exist." } }; + } + + try + { + TShock.Bans.RemoveBan(ban.IP); + } + catch (Exception) + { + returnBlock.Add("status", "400"); + returnBlock.Add("error", "The specified ban was unable to be removed."); + return returnBlock; + } + returnBlock.Add("status", "200"); + returnBlock.Add("response", "Ban deleted successfully."); + return returnBlock; + } + + object BanInfo(RestVerbs verbs, IParameterCollection parameters) + { + var returnBlock = new Dictionary(); + + var type = parameters["type"]; + if (type == null) + { + returnBlock.Add("Error", "Invalid Type"); + return returnBlock; + } + + var ban = new DB.Ban(); + if (type == "ip") ban = TShock.Bans.GetBanByIp(verbs["user"]); + else if (type == "name") ban = TShock.Bans.GetBanByName(verbs["user"]); + else + { + returnBlock.Add("Error", "Invalid Type"); + return returnBlock; + } + + if (ban == null) + { + return new Dictionary { { "status", "400" }, { "error", "The specified ban does not exist." } }; + } + + returnBlock.Add("status", "200"); + returnBlock.Add("name", ban.Name); + returnBlock.Add("ip", ban.IP); + returnBlock.Add("reason", ban.Reason); + return returnBlock; + } + + #endregion + + #region RestWorldMethods + object WorldRead(RestVerbs verbs, IParameterCollection parameters) + { + var returnBlock = new Dictionary(); + returnBlock.Add("status", "200"); + returnBlock.Add("name", Main.worldName); + returnBlock.Add("size", Main.maxTilesX + "*" + Main.maxTilesY); + returnBlock.Add("time", Main.time); + returnBlock.Add("daytime", Main.dayTime); + returnBlock.Add("bloodmoon", Main.bloodMoon); + returnBlock.Add("invasionsize", Main.invasionSize); + return returnBlock; + } + + object WorldMeteor(RestVerbs verbs, IParameterCollection parameters) + { + WorldGen.dropMeteor(); + var returnBlock = new Dictionary(); + returnBlock.Add("status", "200"); + returnBlock.Add("response", "Meteor has been spawned."); + return returnBlock; + } + + object WorldBloodmoon(RestVerbs verbs, IParameterCollection parameters) + { + var returnBlock = new Dictionary(); + var bloodmoonVerb = verbs["bool"]; + bool bloodmoon; + if (bloodmoonVerb == null) + { + returnBlock.Add("status", "400"); + returnBlock.Add("error", "No parameter was passed."); + return returnBlock; + } + if (!bool.TryParse(bloodmoonVerb, out bloodmoon)) + { + returnBlock.Add("status", "400"); + returnBlock.Add("error", "Unable to parse parameter."); + return returnBlock; + } + Main.bloodMoon = bloodmoon; + returnBlock.Add("status", "200"); + returnBlock.Add("response", "Blood Moon has been set to " + bloodmoon.ToString()); + return returnBlock; + } + #endregion + + #region RestPlayerMethods + object PlayerRead(RestVerbs verbs, IParameterCollection parameters) + { + var returnBlock = new Dictionary(); + var playerParam = parameters["player"]; + var found = Tools.FindPlayer(playerParam.ToString()); + if (found.Count == 0) + { + returnBlock.Add("status", "400"); + returnBlock.Add("error", "Name " + playerParam.ToString() + " was not found"); + } + else if (found.Count > 1) + { + returnBlock.Add("status", "400"); + returnBlock.Add("error", "Name " + playerParam.ToString() + " matches " + playerParam.Count().ToString() + " players"); + } + else if (found.Count == 1) + { + var player = found[0]; + returnBlock.Add("status", "200"); + returnBlock.Add("nickname", player.Name); + returnBlock.Add("username", player.UserAccountName == null ? "" : player.UserAccountName); + returnBlock.Add("ip", player.IP); + returnBlock.Add("group", player.Group.Name); + returnBlock.Add("position", player.TileX.ToString() + "," + player.TileY.ToString()); + var activeItems = player.TPlayer.inventory.Where(p => p.active).ToList(); + returnBlock.Add("inventory", string.Join(", ", activeItems.Select(p => p.name))); + returnBlock.Add("buffs", string.Join(", ", player.TPlayer.buffType)); + } + return returnBlock; + } + object PlayerKick(RestVerbs verbs, IParameterCollection parameters) + { + var returnBlock = new Dictionary(); + var playerParam = parameters["player"]; + var found = Tools.FindPlayer(playerParam.ToString()); + var reason = verbs["reason"]; + if (found.Count == 0) + { + returnBlock.Add("status", "400"); + returnBlock.Add("error", "Name " + playerParam.ToString() + " was not found"); + } + else if (found.Count > 1) + { + returnBlock.Add("status", "400"); + returnBlock.Add("error", "Name " + playerParam.ToString() + " matches " + playerParam.Count().ToString() + " players"); + } + else if (found.Count == 1) + { + var player = found[0]; + Tools.ForceKick(player, reason == null ? "Kicked via web" : reason.ToString()); + returnBlock.Add("status", "200"); + returnBlock.Add("response", "Player " + player.Name + " was kicked"); + } + return returnBlock; + } + object PlayerBan(RestVerbs verbs, IParameterCollection parameters) + { + var returnBlock = new Dictionary(); + var playerParam = parameters["player"]; + var found = Tools.FindPlayer(playerParam.ToString()); + var reason = verbs["reason"]; + if (found.Count == 0) + { + returnBlock.Add("status", "400"); + returnBlock.Add("error", "Name " + playerParam.ToString() + " was not found"); + } + else if (found.Count > 1) + { + returnBlock.Add("status", "400"); + returnBlock.Add("error", "Name " + playerParam.ToString() + " matches " + playerParam.Count().ToString() + " players"); + } + else if (found.Count == 1) + { + var player = found[0]; + TShock.Bans.AddBan(player.IP, player.Name, reason == null ? "Banned via web" : reason.ToString()); + Tools.ForceKick(player, reason == null ? "Banned via web" : reason.ToString()); + returnBlock.Add("status", "200"); + returnBlock.Add("response", "Player " + player.Name + " was banned"); + } + return returnBlock; + } + #endregion + + #region RestExampleMethods + + public void RegisterExamples() + { + Rest.Register(new RestCommand("/HelloWorld/name/{username}", UserTest) { RequiresToken = false }); + Rest.Register(new RestCommand("/wizard/{username}", Wizard) { RequiresToken = false }); + } + + //The Wizard example, for demonstrating the response convention: + object Wizard(RestVerbs verbs, IParameterCollection parameters) + { + var returnBack = new Dictionary(); + returnBack.Add("status", "200"); //Keep this in everything, 200 = ok, etc. Standard http status codes. + returnBack.Add("error", "(If this failed, you would have a different status code and provide the error object.)"); //And only include this if the status isn't 200 or a failure + returnBack.Add("Verified Wizard", "You're a wizard, " + verbs["username"]); //Outline any api calls and possible responses in some form of documentation somewhere + return returnBack; + } + + //http://127.0.0.1:8080/HelloWorld/name/{username}?type=status + object UserTest(RestVerbs verbs, IParameterCollection parameters) + { + var ret = new Dictionary(); + var type = parameters["type"]; + if (type == null) + { + ret.Add("Error", "Invalid Type"); + return ret; + } + if (type == "status") + { + ret.Add("Users", "Info here"); + return ret; + } + return null; + } + #endregion + } +} diff --git a/TShockAPI/Rest/RestObject.cs b/TShockAPI/Rest/RestObject.cs new file mode 100644 index 00000000..eb0631d9 --- /dev/null +++ b/TShockAPI/Rest/RestObject.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; + +namespace Rests +{ + [Serializable] + public class RestObject : Dictionary + { + public string Status + { + get { return this["status"] as string; } + set { this["status"] = value; } + } + public string Error + { + get { return this["error"] as string; } + set { this["error"] = value; } + } + public string Response + { + get { return this["response"] as string; } + set { this["response"] = value; } + } + + public RestObject(string status) + { + Status = status; + } + + /// + /// Gets value safely, if it does not exist, return null. Sets/Adds value safely, if null it will remove. + /// + /// + /// + /// Returns null if key does not exist. + public new object this[string key] + { + get + { + object ret; + if (TryGetValue(key, out ret)) + return ret; + return null; + } + set + { + if (!ContainsKey(key)) + { + if (value == null) + return; + Add(key, value); + } + else + { + if (value != null) + base[key] = value; + else + Remove(key); + } + } + } + } +} \ No newline at end of file diff --git a/TShockAPI/Rest/RestVerbs.cs b/TShockAPI/Rest/RestVerbs.cs new file mode 100644 index 00000000..bbad41d3 --- /dev/null +++ b/TShockAPI/Rest/RestVerbs.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; + +namespace Rests +{ + [Serializable] + public class RestVerbs : Dictionary + { + /// + /// Gets value safely, if it does not exist, return null. Sets/Adds value safely, if null it will remove. + /// + /// + /// + /// Returns null if key does not exist. + public new string this[string key] + { + get + { + string ret; + if (TryGetValue(key, out ret)) + return ret; + return null; + } + set + { + if (!ContainsKey(key)) + { + if (value == null) + return; + Add(key, value); + } + else + { + if (value != null) + base[key] = value; + else + Remove(key); + } + } + } + } +} \ No newline at end of file diff --git a/TShockAPI/Rest/SecureRest.cs b/TShockAPI/Rest/SecureRest.cs new file mode 100644 index 00000000..db12f1fe --- /dev/null +++ b/TShockAPI/Rest/SecureRest.cs @@ -0,0 +1,91 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Text; +using HttpServer; +using TShockAPI; + +namespace Rests +{ + /// + /// + /// + /// Username to verify + /// Password to verify + /// Returning a restobject with a null error means a successful verification. + public delegate RestObject VerifyD(string username, string password); + public class SecureRest : Rest + { + public Dictionary Tokens { get; protected set; } + public event VerifyD Verify; + public SecureRest(IPAddress ip, int port) + : base(ip, port) + { + Tokens = new Dictionary(); + Register(new RestCommand("/token/create/{username}/{password}", NewToken) { RequiresToken = false }); + Register(new RestCommand("/token/destroy/{token}", DestroyToken) { RequiresToken = true }); + } + + object DestroyToken(RestVerbs verbs, IParameterCollection parameters) + { + var token = verbs["token"]; + try + { + Tokens.Remove(token); + } + catch (Exception) + { + return new Dictionary { { "status", "400" }, { "error", "The specified token queued for destruction failed to be deleted." } }; + } + return new Dictionary { { "status", "200" }, { "response", "Requested token was successfully destroyed." } }; + } + + object NewToken(RestVerbs verbs, IParameterCollection parameters) + { + var user = verbs["username"]; + var pass = verbs["password"]; + + RestObject obj = null; + if (Verify != null) + obj = Verify(user, pass); + + if (obj == null) + obj = new RestObject("401") { Error = "Invalid username/password combination provided. Please re-submit your query with a correct pair." }; + + if (obj.Error != null) + return obj; + + string hash; + var rand = new Random(); + var randbytes = new byte[32]; + do + { + rand.NextBytes(randbytes); + hash = randbytes.Aggregate("", (s, b) => s + b.ToString("X2")); + } while (Tokens.ContainsKey(hash)); + + Tokens.Add(hash, user); + + obj["token"] = hash; + return obj; + } + + + + protected override object ExecuteCommand(RestCommand cmd, RestVerbs verbs, IParameterCollection parms) + { + if (cmd.RequiresToken) + { + var strtoken = parms["token"]; + if (strtoken == null) + return new Dictionary { { "status", "401" }, { "error", "Not authorized. The specified API endpoint requires a token." } }; + + object token; + if (!Tokens.TryGetValue(strtoken, out token)) + return new Dictionary { { "status", "403" }, { "error", "Not authorized. The specified API endpoint requires a token, but the provided token was not valid." } }; + } + return base.ExecuteCommand(cmd, verbs, parms); + } + } +} diff --git a/TShockAPI/TSPlayer.cs b/TShockAPI/TSPlayer.cs index 30abe815..9afef6e8 100644 --- a/TShockAPI/TSPlayer.cs +++ b/TShockAPI/TSPlayer.cs @@ -17,13 +17,12 @@ along with this program. If not, see . */ using System; using System.Collections.Generic; -using System.Drawing; + using System.IO; using System.Threading; using Terraria; -using TerrariaAPI; + using TShockAPI.Net; -using XNAHelpers; namespace TShockAPI { @@ -32,7 +31,7 @@ namespace TShockAPI public static readonly TSServerPlayer Server = new TSServerPlayer(); public static readonly TSPlayer All = new TSPlayer("All"); public int TileThreshold { get; set; } - public Dictionary TilesDestroyed { get; protected set; } + public Dictionary TilesDestroyed { get; protected set; } public bool SyncHP { get; set; } public bool SyncMP { get; set; } public Group Group { get; set; } @@ -46,10 +45,10 @@ namespace TShockAPI public DateTime LastTileChangeNotify { get; set; } public bool InitSpawn; public bool DisplayLogs = true; - public PointF oldSpawn = PointF.Empty; + public Vector2 oldSpawn = Vector2.Zero; public TSPlayer LastWhisper; public int LoginAttempts { get; set; } - public PointF TeleportCoords = new PointF(-1, -1); + public Vector2 TeleportCoords = new Vector2(-1, -1); public string UserAccountName { get; set; } public bool HasBeenSpammedWithBuildMessage; public bool IsLoggedIn; @@ -69,7 +68,7 @@ namespace TShockAPI } public bool ConnectionAlive { - get { return RealPlayer ? Netplay.serverSock[Index] != null && Netplay.serverSock[Index].active && !Netplay.serverSock[Index].kill : false; } + get { return RealPlayer && (Netplay.serverSock[Index] != null && Netplay.serverSock[Index].active && !Netplay.serverSock[Index].kill); } } public string IP { @@ -145,14 +144,14 @@ namespace TShockAPI public TSPlayer(int index) { - TilesDestroyed = new Dictionary(); + TilesDestroyed = new Dictionary(); Index = index; Group = new Group("null"); } protected TSPlayer(String playerName) { - TilesDestroyed = new Dictionary(); + TilesDestroyed = new Dictionary(); Index = -1; FakePlayer = new Player { name = playerName, whoAmi = -1 }; Group = new Group("null"); @@ -213,7 +212,7 @@ namespace TShockAPI //150 Should avoid all client crash errors //The error occurs when a tile trys to update which the client hasnt load yet, Clients only update tiles withen 150 blocks //Try 300 if it does not work (Higher number - Longer load times - Less chance of error) - if (!SendTileSquare(tilex, tiley, 150)) + if (!SendTileSquare(tilex, tiley)) { InitSpawn = true; SendWorldInfo(Main.spawnTileX, Main.spawnTileY, false); @@ -225,6 +224,9 @@ namespace TShockAPI SendWorldInfo(Main.spawnTileX, Main.spawnTileY, false); + TPlayer.position.X = tilex; + TPlayer.position.Y = tiley; + return true; } @@ -406,17 +408,17 @@ namespace TShockAPI NetMessage.SendData((int)PacketTypes.NpcStrike, -1, -1, "", npcid, damage, knockBack, hitDirection); } - public void RevertKillTile(Dictionary destroyedTiles) + public void RevertKillTile(Dictionary destroyedTiles) { // Update Main.Tile first so that when tile sqaure is sent it is correct - foreach (KeyValuePair entry in destroyedTiles) + foreach (KeyValuePair entry in destroyedTiles) { - Main.tile[(int)entry.Key.X, (int)entry.Key.Y] = entry.Value; + Main.tile[(int)entry.Key.X, (int)entry.Key.Y].Data = entry.Value; Log.Debug(string.Format("Reverted DestroyedTile(TileXY:{0}_{1}, Type:{2})", entry.Key.X, entry.Key.Y, Main.tile[(int)entry.Key.X, (int)entry.Key.Y].type)); } // Send all players updated tile sqaures - foreach (PointF coords in destroyedTiles.Keys) + foreach (Vector2 coords in destroyedTiles.Keys) { All.SendTileSquare((int)coords.X, (int)coords.Y, 3); } diff --git a/TShockAPI/TShock.cs b/TShockAPI/TShock.cs index 1b06aaef..be8a4eb4 100644 --- a/TShockAPI/TShock.cs +++ b/TShockAPI/TShock.cs @@ -29,17 +29,15 @@ using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Diagnostics; -using System.Drawing; using System.IO; using System.Net; using System.Reflection; -using System.Linq; using System.Threading; using Community.CsharpSqlite.SQLiteClient; +using Hooks; using MySql.Data.MySqlClient; +using Rests; using Terraria; -using TerrariaAPI; -using TerrariaAPI.Hooks; using TShockAPI.DB; using TShockAPI.Net; @@ -49,7 +47,7 @@ namespace TShockAPI public class TShock : TerrariaPlugin { public static readonly Version VersionNum = Assembly.GetExecutingAssembly().GetName().Version; - public static readonly string VersionCodename = "And believe me, we are still alive."; + public static readonly string VersionCodename = "Try the new slim model."; public static string SavePath = "tshock"; @@ -67,6 +65,8 @@ namespace TShockAPI public static bool OverridePort; public static PacketBufferer PacketBuffer; public static MaxMind.GeoIPCountry Geo; + public static SecureRest RestApi; + public static RestManager RestManager; /// /// Called after TShock is initialized. Useful for plugins that needs hooks before tshock but also depend on tshock being loaded. @@ -142,7 +142,7 @@ namespace TShockAPI var hostport = Config.MySqlHost.Split(':'); DB = new MySqlConnection(); DB.ConnectionString = - String.Format("Server='{0}'; Port='{1}'; Database='{2}'; Uid='{3}'; Pwd='{4}';", + String.Format("Server={0}; Port={1}; Database={2}; Uid={3}; Pwd={4};", hostport[0], hostport.Length > 1 ? hostport[1] : "3306", Config.MySqlDbName, @@ -172,8 +172,15 @@ namespace TShockAPI Regions = new RegionManager(DB); Itembans = new ItemManager(DB); RememberedPos = new RemeberedPosManager(DB); - if (Config.EnableGeoIP) - Geo = new MaxMind.GeoIPCountry(Path.Combine(SavePath, "GeoIP.dat")); + RestApi = new SecureRest(Netplay.serverListenIP, 8080); + RestApi.Verify += RestApi_Verify; + RestApi.Port = Config.RestApiPort; + RestManager = new RestManager(RestApi); + RestManager.RegisterRestfulCommands(); + + var geoippath = Path.Combine(SavePath, "GeoIP.dat"); + if (Config.EnableGeoIP && File.Exists(geoippath)) + Geo = new MaxMind.GeoIPCountry(geoippath); Log.ConsoleInfo(string.Format("TShock Version {0} ({1}) now running.", Version, VersionCodename)); @@ -209,23 +216,50 @@ namespace TShockAPI } } - public override void DeInitialize() + RestObject RestApi_Verify(string username, string password) { - GameHooks.PostInitialize -= OnPostInit; - GameHooks.Update -= OnUpdate; - ServerHooks.Join -= OnJoin; - ServerHooks.Leave -= OnLeave; - ServerHooks.Chat -= OnChat; - ServerHooks.Command -= ServerHooks_OnCommand; - NetHooks.GetData -= OnGetData; - NetHooks.SendData -= NetHooks_SendData; - NetHooks.GreetPlayer -= OnGreetPlayer; - NpcHooks.StrikeNpc -= NpcHooks_OnStrikeNpc; - if (File.Exists(Path.Combine(SavePath, "tshock.pid"))) + var userAccount = TShock.Users.GetUserByName(username); + if (userAccount == null) { - Console.WriteLine("Thanks for using TShock! Process ID file is now being destroyed."); - File.Delete(Path.Combine(SavePath, "tshock.pid")); + return new RestObject("401") { Error = "Invalid username/password combination provided. Please re-submit your query with a correct pair." }; } + + if (Tools.HashPassword(password).ToUpper() != userAccount.Password.ToUpper()) + { + return new RestObject("401") { Error = "Invalid username/password combination provided. Please re-submit your query with a correct pair." }; + } + + if (!Tools.GetGroup(userAccount.Group).HasPermission("api") && userAccount.Group != "superadmin") + { + return new RestObject("403") { Error = "Although your account was successfully found and identified, your account lacks the permission required to use the API. (api)" }; + } + + return new RestObject("200") { Response = "Successful login" }; //Maybe return some user info too? + } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + GameHooks.PostInitialize -= OnPostInit; + GameHooks.Update -= OnUpdate; + ServerHooks.Join -= OnJoin; + ServerHooks.Leave -= OnLeave; + ServerHooks.Chat -= OnChat; + ServerHooks.Command -= ServerHooks_OnCommand; + NetHooks.GetData -= OnGetData; + NetHooks.SendData -= NetHooks_SendData; + NetHooks.GreetPlayer -= OnGreetPlayer; + NpcHooks.StrikeNpc -= NpcHooks_OnStrikeNpc; + if (File.Exists(Path.Combine(SavePath, "tshock.pid"))) + { + Console.WriteLine("Thanks for using TShock! Process ID file is now being destroyed."); + File.Delete(Path.Combine(SavePath, "tshock.pid")); + } + RestApi.Dispose(); + } + + base.Dispose(disposing); } /// @@ -352,6 +386,8 @@ namespace TShockAPI AuthToken = 0; } Regions.ReloadAllRegions(); + if (Config.RestApiEnabled) + RestApi.Start(); } @@ -624,7 +660,7 @@ namespace TShockAPI NetMessage.SendData((int)PacketTypes.TimeSet, -1, -1, "", 0, 0, Main.sunModY, Main.moonModY); NetMessage.syncPlayers(); - if (Config.EnableGeoIP) + if (Config.EnableGeoIP && Geo != null) { var code = Geo.TryGetCountryCode(IPAddress.Parse(player.IP)); player.Country = code == null ? "N/A" : MaxMind.GeoIPCountry.GetCountryNameByCode(code); @@ -813,11 +849,11 @@ namespace TShockAPI public static bool CheckSpawn(int x, int y) { - PointF tile = new PointF(x, y); - PointF spawn = new PointF(Main.spawnTileX, Main.spawnTileY); + Vector2 tile = new Vector2(x, y); + Vector2 spawn = new Vector2(Main.spawnTileX, Main.spawnTileY); return Distance(spawn, tile) <= Config.SpawnProtectionRadius; } - public static float Distance(PointF value1, PointF value2) + public static float Distance(Vector2 value1, Vector2 value2) { float num2 = value1.X - value2.X; float num = value1.Y - value2.Y; diff --git a/TShockAPI/TShockAPI.csproj b/TShockAPI/TShockAPI.csproj index 523752e5..cfebb727 100644 --- a/TShockAPI/TShockAPI.csproj +++ b/TShockAPI/TShockAPI.csproj @@ -32,7 +32,7 @@ true full false - ..\..\serverplugins\ + ..\..\..\Downloads\TShock 3.3.4.924\ServerPlugins\ DEBUG;TRACE prompt 4 @@ -52,6 +52,9 @@ False ..\SqlBins\Community.CsharpSqlite.SQLiteClient.dll + + ..\HttpBins\HttpServer.dll + False ..\SqlBins\MySql.Data.dll @@ -67,7 +70,6 @@ - @@ -79,10 +81,6 @@ ..\TerrariaServerBins\TerrariaServer.exe False - - False - ..\TerrariaServerBins\TerrariaServerAPI.dll - @@ -121,6 +119,12 @@ True Resources.resx + + + + + + @@ -177,7 +181,7 @@ - +