コード例 #1
0
        protected override void DataReceived(string data, int clientNumber)
        {
            try
            {
                Stopwatch sw = new Stopwatch();

                sw.Start();

                NntpCommand nntpCommand = null;
                var         client      = GetClient(clientNumber);
                string      response;

                if (client == null)
                {
                    throw new Exception("Client object for [" + clientNumber + "] is not available");
                }

                //LogMessage(clientNumber, client.AuthenticatedClientUsername, data, NO_LOGGING, string.Empty);
                //LogMessage(clientNumber, string.Empty, data, NO_LOGGING, string.Empty);

                // log receive data size
                PerfCounters.IncrementCounterBy(PerfCounterName.BytesReceived, data.Length);

                bool   parseCommand   = false;
                string additionalData = string.Empty;

                if (client.PreviousCommand == Command.POST)
                {
                    Traces.NntpServerTraceEvent(TraceEventType.Verbose, client, "DataReceived: Client is posting data");

                    //System.Diagnostics.Debug.WriteLine("Buffer: {0}", client.Buffer);
                    //System.Diagnostics.Debug.WriteLine("Recv: {0}", data);
                    // client is posting data,
                    // keep buffering until dotted terminator reached
                    string postData = data;

                    /*
                     * string ascSeq = string.Empty;
                     * for (int i = 0; i < postData.Length; i++)
                     * {
                     *  ascSeq += (int)postData[i] + " ";
                     * }
                     * //System.Diagnostics.Trace.WriteLine("ascSeq - " + ascSeq);
                     */

                    // Append the data to the internal buffer
                    client.Buffer.Append(postData);

                    // Then extract (at least) the last 5 chars (or min the number of currently received bytes) to determine the termination...
                    string lastChars = string.Empty;
                    if (client.Buffer.Length >= 5)
                    {
                        int len = Math.Max(postData.Length, 5);
                        lastChars = client.Buffer.ToString(client.Buffer.Length - len, len);
                    }

                    // Check for "termination" signal...
                    if (lastChars.IndexOf("\r\n.\r\n") >= 0)
                    {
                        //System.Diagnostics.Trace.WriteLine("Termination sequence sent");
                        var buf = client.Buffer.ToString();

                        // extract post data up to the dot terminator
                        client.Buffer = new StringBuilder(buf.Substring(0, buf.IndexOf("\r\n.\r\n")));

                        // grab any data received after the terminator
                        additionalData = buf.Substring(buf.IndexOf("\r\n.\r\n") + 5);

                        // flag to say we wish to process the received data
                        parseCommand = true;
                    }
                    //else if (lastChars.StartsWith(".\r\n"))
                    //{
                    //    // WHAT does this mean???
                    //    // no post data in this request
                    //    postData = string.Empty;

                    //    // grab any data received after the terminator
                    //    additionalData = data.Substring(3);

                    //    // flag to say we wish to process the received data
                    //    parseCommand = true;
                    //}

                    //client.Buffer.Append(postData);

                    if (parseCommand)
                    {
                        //System.Diagnostics.Trace.WriteLine("Posting article");

                        // create a new command
                        nntpCommand =
                            new NntpCommandPostData
                        {
                            Provider = _dataProvider
                        };
                        // TODO: nntpCommand.ClientUsername = client.AuthenticatedClientUsername;

                        // log command
                        PerfCounters.IncrementCounter(PerfCounterName.TotalNntpCommandPostData);

                        // ensure command executed in context of authenticated user
                        // TODO: client.ImpersonateClient();

                        Traces.NntpServerTraceEvent(TraceEventType.Verbose, client, "Received: {0}: {1}", nntpCommand.Command, client.Buffer.ToString());

                        // post the article
                        response = nntpCommand.Parse(client.Buffer.ToString(), null, client);

                        Traces.NntpServerTraceEvent(TraceEventType.Verbose, client, "Response: {0}", response);

                        // revert to service security context
                        // TODO: client.RevertImpersonation();

                        // send back success/fail message
                        SendData(response, clientNumber);

                        PerfCounters.IncrementCounter(PerfCounterName.CommandsProcessedPerSecond);

                        // clear down buffer & reset command
                        client.Buffer          = new StringBuilder();
                        client.PreviousCommand = Command.NOTRECOGNISED;
                        nntpCommand            = null;
                    }
                }
                else
                {
                    //System.Diagnostics.Trace.WriteLine("Client not posting data");
                    // client is not posting data,
                    // wait until CR-LF pair is reached
                    string postData = data;
                    if (postData.IndexOf("\r\n") >= 0)
                    {
                        //System.Diagnostics.Trace.WriteLine("CR-LF pair received");

                        // extract up to end of line
                        postData = postData.Substring(0, postData.IndexOf("\r\n"));

                        // obtain further data (should not normally be present)
                        additionalData = data.Substring(data.IndexOf("\r\n") + 2);

                        parseCommand = true;
                    }
                    client.Buffer.Append(postData);

                    if (parseCommand)
                    {
                        // determine type of command and extract parameters
                        nntpCommand = ClassifyCommand(client);

                        // clear down buffer
                        client.Buffer = new StringBuilder();
                    }
                }

                if (nntpCommand != null)
                {
                    // ensure command executed in context of authenticated user
                    // TODO: client.ImpersonateClient();

                    // execute the command
                    var             dataSendInAction = false;
                    Action <string> streamWriter     = p =>
                    {
                        SendData(p, client.ClientNumber);
                        dataSendInAction = true;
                        Traces.NntpServerTraceEvent(TraceEventType.Verbose, client, "Received: Response: {0}", p);
                    };

                    Traces.NntpServerTraceEvent(TraceEventType.Verbose, client, "Received: Command: {0}, Parameters: {1}", nntpCommand.Command, client.CommandParameters);

                    response = nntpCommand.Parse(client.CommandParameters, streamWriter, client);


                    // revert to service security context
                    // TODO: client.RevertImpersonation();

                    // log command
                    PerfCounterName perfCounterNameForCommand = GetTotalCounterFromCommand(client.PreviousCommand);
                    PerfCounters.IncrementCounter(perfCounterNameForCommand);

                    // client attempting to authenticate more than once
                    // then re-authenticate
                    if (client.PreviousCommand == Command.AUTHINFO &&
                        nntpCommand.AuthToken == null)
                    {
                        if (client.Authenticated)
                        {
                            // TODO: client.AuthServerContext.Dispose();
                            // TODO: client.AuthServerContext = null;
                            client.Authenticated = false;
                        }
                    }

                    // steps 2 and 3 of the authentication process
                    if (client.PreviousCommand == Command.AUTHINFO &&
                        nntpCommand.AuthToken != null)
                    {
                        try
                        {
                            // TODO: ServerCredential serverCredential = new ServerCredential(Credential.Package.NTLM);
                            //if (client.AuthServerContext == null)
                            //{
                            //    client.AuthServerContext = new ServerContext(serverCredential, nntpCommand.AuthToken);
                            //    response = response.Replace("<token>", Convert.ToBase64String(client.AuthServerContext.Token));
                            //}
                            //else
                            //{
                            //client.AuthServerContext.Accept(nntpCommand.AuthToken);
                            client.Authenticated = true;
                            response             = GeneralResponses.AuthenticationAccepted;
                            //    PerfCounters.IncrementCounter(PerfCounterName.ResponseAuthenticationAccepted);
                            //}
                        }
                        catch (Exception ex)
                        {
                            // error during authentication (e.g. access denied)
                            // return response to client
                            Traces.NntpServerTraceEvent(TraceEventType.Critical, client, "Failed to authenticate: {0}", Traces.ExceptionToString((ex)));
                            // TODO: client.AuthServerContext.Dispose();
                            // TODO: client.AuthServerContext = null;
                            client.Authenticated = false;
                            response             = GeneralResponses.AccessDenied;
                            PerfCounters.IncrementCounter(PerfCounterName.ResponseAccessDenied);
                        }
                    }

                    //// if user not logged in, send back authenticated required
                    //// message
                    //if (client.PreviousCommand != Command.MODE &&
                    //    client.PreviousCommand != Command.AUTHINFO &&
                    //    (!client.Authenticated ||
                    //      (client.Authenticated &&
                    //       client.AuthenticatedClientUsername.Length == 0)))
                    //{
                    //    response = GeneralResponses.AuthenticationRequired;
                    //    PerfCounters.IncrementCounter(PerfCounterName.ResponseAuthenticationRequired);
                    //}

                    // send response to client
                    if (dataSendInAction == false)
                    {
                        if (string.IsNullOrEmpty(response) == false)
                        {
                            SendData(response, clientNumber);

                            Traces.NntpServerTraceEvent(TraceEventType.Verbose, client, "Received: Response: {0}", response);


                            PerfCounters.IncrementCounter(PerfCounterName.CommandsProcessedPerSecond);

                            // log sent data size
                            PerfCounters.IncrementCounterBy(PerfCounterName.BytesSent, response.Length);
                        }
                        else
                        {
                            throw new Exception("No data returned from parsed command [" + client.PreviousCommand + "]");
                        }
                    }


                    // adjust client state after command execution
                    switch (client.PreviousCommand)
                    {
                    case Command.POST:
                        if (nntpCommand.PostCancelled)
                        {
                            Trace.WriteLine("Posting is not allowed, reset status on client object");
                            client.PreviousCommand = Command.NOTRECOGNISED;
                        }
                        break;

                    case Command.QUIT:
                        DisconnectClient(clientNumber);
                        break;
                    }
                }

                // continue processing if needed
                // additional commands may follow the command
                // or post data just processed
                if (additionalData.Trim().Length > 0)
                {
                    DataReceived(additionalData, clientNumber);
                }

                sw.Stop();

                lock (_perfCounterLock)
                {
                    PerfCounters.IncrementCounterBy(PerfCounterName.AverageProcessingTime, sw.ElapsedTicks);
                    PerfCounters.IncrementCounter(PerfCounterName.AverageProcessingTimeBase);
                }
            }
            catch (Exception ex)
            {
                Traces.NntpServerTraceEvent(TraceEventType.Critical, "[Client {0}] DataReceived failed: {1}", clientNumber, Traces.ExceptionToString(ex));
                if (clientNumber > 0)
                {
                    PerfCounters.IncrementCounter(PerfCounterName.ResponseProgramFault);
                    // INFO: Reply with more specific error message:

                    //if (DetailedErrorResponse)
                    //{

                    var resp = string.Format(
                        "503 program fault - command not performed {0}\r\n",
                        GetErrorResponseFromExeption(ex));
                    SendData(resp, clientNumber);
                    //}
                    //else
                    //{
                    //    SendData(GeneralResponses.ProgramFault, clientNumber);
                    //}
                }
            }
        }
コード例 #2
0
        protected void DisconnectClient(int clientNumber)
        {
            try
            {
                Socket workerSocket;

                try
                {
                    lock (_workerSockets)
                    {
                        workerSocket = _workerSockets[clientNumber];
                    }
                }
                catch
                {
                    //System.Diagnostics.Trace.WriteLine("Server::DisconnectClient - unable to access entry [" + clientNumber + "]");
                    return;
                }

                if (workerSocket != null)
                {
                    workerSocket.Close();

                    try
                    {
                        lock (_workerSockets)
                        {
                            _workerSockets.Remove(clientNumber);
                        }
                    }
// ReSharper disable EmptyGeneralCatchClause
                    catch
// ReSharper restore EmptyGeneralCatchClause
                    {
                        // continue
                        //System.Diagnostics.Trace.WriteLine("Server::DisconnectClient - unable to remove entry [" + clientNumber + "]");
                    }

                    ClientDisconnected(clientNumber);
                }
            }
            catch (Exception ex)
            {
                Traces.NntpServerTraceEvent(System.Diagnostics.TraceEventType.Error, "[Client {0}] Server.DisconnectClient failed: {1}", clientNumber, Traces.ExceptionToString(ex));
            }
        }
コード例 #3
0
        public void Start(int port, int pendingConnectionsLength, bool bindToWorld, out string errorString)
        {
            errorString = null;
            try
            {
                _primarySocket = new Socket(AddressFamily.InterNetwork,
                                            SocketType.Stream,
                                            ProtocolType.Tcp);

                IPEndPoint ipLocal;
                if (bindToWorld)
                {
                    ipLocal = new IPEndPoint(IPAddress.Any, port);
                }
                else
                {
                    ipLocal = new IPEndPoint(IPAddress.Loopback, port);
                }

                // bind to local address
                _primarySocket.Bind(ipLocal);

                // start listening
                _primarySocket.Listen(pendingConnectionsLength);

                // call back for client connections
                _primarySocket.BeginAccept(new AsyncCallback(OnClientConnect), null);
            }
            catch (SocketException se)
            {
                errorString = se.Message;
                Traces.NntpServerTraceEvent(System.Diagnostics.TraceEventType.Critical, "Server.Start failed: {0}", Traces.ExceptionToString(se));
            }
            catch (Exception ex)
            {
                // TODO: Logging.Error("Failed to establish master listener on port [" + port.ToString() + "]", ex);
                Traces.NntpServerTraceEvent(System.Diagnostics.TraceEventType.Critical, "Server.Start failed: {0}", Traces.ExceptionToString(ex));
                errorString = ex.Message;

                throw new Exception("Failed to establish master listener", ex);
            }
        }
コード例 #4
0
        protected void SendData(string data, int clientNumber)
        {
            byte[] buffer;

            try
            {
                buffer = _encodingSend.GetBytes(data);
            }
            catch (Exception ex)
            {
                Traces.NntpServerTraceEvent(System.Diagnostics.TraceEventType.Critical, "[Client {0}] Server.SendData failed to encode data: {1}\r\n{2}", clientNumber, data, Traces.ExceptionToString(ex));
                return;
            }

            Socket workerSocket;

            try
            {
                lock (_workerSockets)
                {
                    workerSocket = _workerSockets[clientNumber];
                }
            }
            catch
            {
                // continue
                //System.Diagnostics.Trace.WriteLine("Server::SendData - unable to access entry [" + clientNumber + "]");
                return;
            }
            if (workerSocket == null)
            {
                Traces.NntpServerTraceEvent(System.Diagnostics.TraceEventType.Warning, "[Client {0}] Server.SendData failed (client removed from the worker list)", clientNumber);
                return;
            }
            try
            {
                if (_workerSendCallBack == null)
                {
                    _workerSendCallBack = new AsyncCallback(OnDataSend);
                }
                var socketPacket = new SocketPacket(workerSocket, clientNumber);

                workerSocket.BeginSend(buffer,
                                       0,
                                       buffer.Length,
                                       SocketFlags.None,
                                       _workerSendCallBack,
                                       socketPacket);
            }
            catch (ObjectDisposedException)
            {
                //System.Diagnostics.Trace.WriteLine("#" + clientNumber.ToString() + " - OnDataSend: Socket has been closed");
                return;
            }
            catch (SocketException se)
            {
                if (se.SocketErrorCode == SocketError.ConnectionReset) // connection reset by peer
                {
                    // remove worker socket of closed client
                    DisconnectClient(clientNumber);
                }
                else if (se.SocketErrorCode == SocketError.ConnectionAborted) // connection aborted
                {
                    // remove worker socket of closed client
                    DisconnectClient(clientNumber);
                }
                else
                {
                    Traces.NntpServerTraceEvent(System.Diagnostics.TraceEventType.Critical, "[Client {0}] Server.SendData failed: {1}", clientNumber, Traces.ExceptionToString(se));
                }
                return;
            }
            catch (Exception ex)
            {
                Traces.NntpServerTraceEvent(System.Diagnostics.TraceEventType.Critical, "[Client {0}] Server.SendData failed: {1}", clientNumber, Traces.ExceptionToString(ex));
            }
        }
コード例 #5
0
        protected void CloseSockets()
        {
            try
            {
                if (_primarySocket != null)
                {
                    _primarySocket.Close();
                }

                lock (_workerSockets)
                {
                    foreach (KeyValuePair <int, Socket> key in _workerSockets)
                    {
                        Socket workerSocket = key.Value;

                        if (workerSocket != null)
                        {
                            workerSocket.Close();
                        }
                    }

                    _workerSockets.Clear();
                    _clients = 0;
                }
            }
            catch (Exception ex)
            {
                Traces.NntpServerTraceEvent(System.Diagnostics.TraceEventType.Error, "Server.CloseSockets failed: {0}", Traces.ExceptionToString(ex));
            }
        }
コード例 #6
0
        public void OnDataSend(IAsyncResult ar)
        {
            var socketPacket = (SocketPacket)ar.AsyncState;

            try
            {
                socketPacket.ClientSocket.EndSend(ar);
            }
            catch (ObjectDisposedException)
            {
                //System.Diagnostics.Trace.WriteLine("#" + socketPacket.ClientNumber.ToString() + " - OnDataSend: Socket has been closed");
                return;
            }
            catch (SocketException se)
            {
                if (se.SocketErrorCode == SocketError.ConnectionReset) // connection reset by peer
                {
                    // remove worker socket of closed client
                    DisconnectClient(socketPacket.ClientNumber);
                }
                else if (se.SocketErrorCode == SocketError.ConnectionAborted) // connection aborted
                {
                    // remove worker socket of closed client
                    DisconnectClient(socketPacket.ClientNumber);
                }
                else
                {
                    Traces.NntpServerTraceEvent(System.Diagnostics.TraceEventType.Critical, "[Client {0}] Server.OnDataSend failed: {1}", socketPacket.ClientNumber, Traces.ExceptionToString(se));
                }
                return;
            }
            catch (Exception ex)
            {
                Traces.NntpServerTraceEvent(System.Diagnostics.TraceEventType.Critical, "[Client {0}] Server.OnDataSend failed: {1}", socketPacket.ClientNumber, Traces.ExceptionToString(ex));
            }
        }
コード例 #7
0
        public void OnDataReceived(IAsyncResult ar)
        {
            var socketPacket = (SocketPacket)ar.AsyncState;

            try
            {
                // complete BeginReceive() - returns number of characters received
                int charsReceived = socketPacket.ClientSocket.EndReceive(ar);

                if (charsReceived > 0)
                {
                    // extract data
                    string data = EncodingRecv.GetString(socketPacket.Buffer, 0, charsReceived);

                    DataReceived(data, socketPacket.ClientNumber);

                    // continue to receive data if still connected
                    WaitForData(socketPacket.ClientSocket, socketPacket.ClientNumber);
                }
                else
                {
                    DisconnectClient(socketPacket.ClientNumber);
                }
            }
            catch (ObjectDisposedException)
            {
                //System.Diagnostics.Trace.WriteLine("#" + socketPacket.ClientNumber.ToString() + " - OnDataReceived: Socket has been closed");
                return;
            }
            catch (SocketException se)
            {
                if (se.SocketErrorCode == SocketError.ConnectionReset) // connection reset by peer
                {
                    // remove worker socket of closed client
                    DisconnectClient(socketPacket.ClientNumber);
                }
                else if (se.SocketErrorCode == SocketError.ConnectionAborted) // connection aborted
                {
                    // remove worker socket of closed client
                    DisconnectClient(socketPacket.ClientNumber);
                }
                else
                {
                    Traces.NntpServerTraceEvent(System.Diagnostics.TraceEventType.Critical, "[Client {0}] Server.OnDataReceived failed: {1}", socketPacket.ClientNumber, Traces.ExceptionToString(se));
                }
                return;
            }
            catch (Exception ex)
            {
                Traces.NntpServerTraceEvent(System.Diagnostics.TraceEventType.Critical, "[Client {0}] Server.OnDataReceived failed: {1}", socketPacket.ClientNumber, Traces.ExceptionToString(ex));
            }
        }
コード例 #8
0
        public void WaitForData(Socket socket, int clientNumber)
        {
            try
            {
                if (_workerReceiveCallBack == null)
                {
                    _workerReceiveCallBack = new AsyncCallback(OnDataReceived);
                }
                var socketPacket = new SocketPacket(socket, clientNumber);

                socket.BeginReceive(socketPacket.Buffer,
                                    0,
                                    socketPacket.Buffer.Length,
                                    SocketFlags.None,
                                    _workerReceiveCallBack,
                                    socketPacket);
            }
            catch (ObjectDisposedException)
            {
                //System.Diagnostics.Trace.WriteLine("#" + clientNumber.ToString() + " - WaitForData: Socket has been closed");
                return;
            }
            catch (SocketException se)
            {
                if (se.SocketErrorCode == SocketError.ConnectionReset) // connection reset by peer
                {
                    // remove worker socket of closed client
                    DisconnectClient(clientNumber);
                }
                else if (se.SocketErrorCode == SocketError.ConnectionAborted) // connection aborted
                {
                    // remove worker socket of closed client
                    DisconnectClient(clientNumber);
                }
                else
                {
                    Traces.NntpServerTraceEvent(System.Diagnostics.TraceEventType.Critical, "[Client {0}] Server.WaitForData failed: {1}", clientNumber, Traces.ExceptionToString(se));
                }
                return;
            }
            catch (Exception ex)
            {
                Traces.NntpServerTraceEvent(System.Diagnostics.TraceEventType.Critical, "[Client {0}] Server.WaitForData failed: {1}", clientNumber, Traces.ExceptionToString(ex));
            }
        }
コード例 #9
0
        public void OnClientConnect(IAsyncResult ar)
        {
            int currentClient = 0;

            try
            {
                // get the worker socket for this connection
                Socket workerSocket = _primarySocket.EndAccept(ar);

                lock (_workerSockets)
                {
                    Interlocked.Increment(ref _clients);
                    currentClient = _clients;
                    _workerSockets.Add(currentClient, workerSocket);
                }

                ClientConnected(currentClient);
                WaitForData(workerSocket, currentClient);
            }
            catch (ObjectDisposedException)
            {
                //System.Diagnostics.Trace.WriteLine("#" + currentClient.ToString() + " - OnClientConnection: Socket has been closed");
                //Logging.Error("OnClientConnect dispose error", ex);
                return;
            }
            catch (SocketException se)
            {
                if (se.SocketErrorCode == SocketError.ConnectionReset) // connection reset by peer
                {
                    // remove worker socket of closed client
                    if (currentClient > 0)
                    {
                        DisconnectClient(currentClient);
                    }
                }
                else if (se.SocketErrorCode == SocketError.ConnectionAborted) // connection aborted
                {
                    // remove worker socket of closed client
                    if (currentClient > 0)
                    {
                        DisconnectClient(currentClient);
                    }
                }
                else
                {
                    Traces.NntpServerTraceEvent(System.Diagnostics.TraceEventType.Critical, "[Client {0}] Server.OnClientConnect failed: {1}", currentClient, Traces.ExceptionToString(se));
                }
            }
            catch (Exception ex)
            {
                Traces.NntpServerTraceEvent(System.Diagnostics.TraceEventType.Critical, "[Client {0}] Server.OnClientConnect failed: {1}", currentClient, Traces.ExceptionToString(ex));
            }
            finally
            {
                try
                {
                    // register for another connection
                    _primarySocket.BeginAccept(new AsyncCallback(OnClientConnect), null);
                }
                catch (ObjectDisposedException)
                {
                    // This occurs when the main socket will be closed
                }
            }
        }
コード例 #10
0
        /// <summary>
        /// Persists an article to the backing store
        /// </summary>
        /// <param name="clientUsername">Authenticated username</param>
        /// <param name="data">Article data posted from NNTP client</param>
        /// <returns>String which will be returned to the client</returns>
        public string PostArticle(string clientUsername, string data)
        {
            try
            {
                if (data.Length > MaxPostLengthBytes)
                {
                    //System.Diagnostics.Trace.WriteLine("Posting failed - maximum post length exceeded");
                    //return PostStatus.FailedExcessiveLength;
                    return(GeneralResponses.PostingFailedExcessiveLength);
                }

                var articleBody = new StringBuilder();
                var article     = new Article {
                    ContentType = string.Empty
                };
                char[] delimiter  = { '\r' };
                bool   isHeader   = true;
                bool   isMimePost = false;

                // undo dot stuffing
                //data = data.Replace("\r\n..\r\n", "\r\n.\r\n");
                //data = data.Replace("\r\n..", "\r\n.");
                string[] lines = data.Split(delimiter);
                //Regex extendedChars = new Regex("[^\\u0009-\\u007e]", RegexOptions.Multiline | RegexOptions.IgnoreCase);

                string lastKeyValue = string.Empty;
                string line;
                foreach (var lineIter in lines)
                {
                    line = lineIter.Replace("\n", string.Empty);
                    //line = extendedChars.Replace(line, string.Empty);
                    //System.Diagnostics.Trace.WriteLine("Processing line -|" + line + "|");
                    if (isHeader && string.IsNullOrEmpty(line))
                    {
                        isHeader = false;
                        continue;
                    }

                    if (isHeader)
                    {
                        var nameValuePair = new ArrayList(2);
                        if (line.IndexOf(": ") > 0)
                        {
                            nameValuePair.Add(line.Substring(0, line.IndexOf(": ")).Trim());
                            lastKeyValue = nameValuePair[0].ToString();
                        }
                        else
                        {
                            nameValuePair.Add(string.Empty);
                        }
                        nameValuePair.Add(line.Substring(line.IndexOf(": ") + 2).Trim());

                        string keyValue = nameValuePair[0].ToString();
                        if (string.Compare(keyValue, HeaderNames.From, StringComparison.InvariantCultureIgnoreCase) == 0)
                        {
                            article.From = nameValuePair[1].ToString();
                        }
                        else if (string.Compare(keyValue, HeaderNames.Date, StringComparison.InvariantCultureIgnoreCase) == 0)
                        {
                            article.Date = nameValuePair[1].ToString();
                        }
                        else if (string.Compare(keyValue, HeaderNames.Subject, StringComparison.InvariantCultureIgnoreCase) == 0)
                        {
                            // Also support newreaders with post the "subject" in multiple lines
                            article.Subject = nameValuePair[1].ToString();
                        }
                        else if (string.Compare(keyValue, HeaderNames.Newsgroups, StringComparison.InvariantCultureIgnoreCase) == 0)
                        {
                            article.Newsgroups = nameValuePair[1].ToString().Replace("\"", string.Empty).Replace("'", string.Empty);
                        }
                        else if (string.Compare(keyValue, HeaderNames.UserAgent, StringComparison.InvariantCultureIgnoreCase) == 0)
                        {
                            article.UserAgent = nameValuePair[1].ToString();
                        }
                        else if (string.Compare(keyValue, HeaderNames.XNewsreader, StringComparison.InvariantCultureIgnoreCase) == 0)
                        {
                            if (string.IsNullOrEmpty(article.UserAgent))
                            {
                                article.UserAgent = nameValuePair[1].ToString();  // The "User-Agent" is embedded into the html, so either use "User-Agent" or "X-Newsreader"
                            }
                            article.XNewsreader = nameValuePair[1].ToString();
                        }
                        // TODO: Also support of "X-Mailer:" !?
                        else if (string.Compare(keyValue, HeaderNames.References, StringComparison.InvariantCultureIgnoreCase) == 0)
                        {
                            article.References = nameValuePair[1].ToString();
                        }
                        else if (string.Compare(keyValue, HeaderNames.ContentType, StringComparison.InvariantCultureIgnoreCase) == 0)
                        {
                            // Also support newreaders with post the "content-type" in multiple lines, like:
                            // Content-Type: text/plain;
                            //      format=flowed;
                            //      charset="iso-8859-1";
                            //      reply-type=original

                            article.ContentType = nameValuePair[1].ToString();
                        }
                        else if (string.Compare(keyValue, HeaderNames.ContentTransferEncoding, StringComparison.InvariantCultureIgnoreCase) == 0)
                        {
                            article.ContentTransferEncoding = nameValuePair[1].ToString();
                        }
                        else if (keyValue.Length == 0)
                        {
                            // Multi-Line Header:
                            if (string.Compare(lastKeyValue, HeaderNames.From, StringComparison.InvariantCultureIgnoreCase) == 0)
                            {
                                article.From += nameValuePair[1].ToString();
                            }
                            else if (string.Compare(lastKeyValue, HeaderNames.Date, StringComparison.InvariantCultureIgnoreCase) == 0)
                            {
                                article.Date += nameValuePair[1].ToString();
                            }
                            else if (string.Compare(lastKeyValue, HeaderNames.Subject, StringComparison.InvariantCultureIgnoreCase) == 0)
                            {
                                article.Subject += nameValuePair[1].ToString();
                            }
                            else if (string.Compare(lastKeyValue, HeaderNames.Newsgroups, StringComparison.InvariantCultureIgnoreCase) == 0)
                            {
                                article.Newsgroups += nameValuePair[1].ToString().Replace("\"", string.Empty).Replace("'", string.Empty);
                            }
                            else if (string.Compare(lastKeyValue, HeaderNames.UserAgent, StringComparison.InvariantCultureIgnoreCase) == 0)
                            {
                                article.UserAgent += nameValuePair[1].ToString();
                            }
                            else if (string.Compare(lastKeyValue, HeaderNames.XNewsreader, StringComparison.InvariantCultureIgnoreCase) == 0)
                            {
                                //if (string.IsNullOrEmpty(article.UserAgent))
                                //  article.UserAgent = nameValuePair[1].ToString();  // The "User-Agent" is embedded into the html, so either use "User-Agent" or "X-Newsreader"
                                article.XNewsreader += nameValuePair[1].ToString();
                            }
                            // TODO: Also support of "X-Mailer:" !?
                            else if (string.Compare(lastKeyValue, HeaderNames.References, StringComparison.InvariantCultureIgnoreCase) == 0)
                            {
                                article.References += nameValuePair[1].ToString();
                            }
                            else if (string.Compare(lastKeyValue, HeaderNames.ContentType, StringComparison.InvariantCultureIgnoreCase) == 0)
                            {
                                article.ContentType += nameValuePair[1].ToString();
                            }
                            else if (string.Compare(lastKeyValue, HeaderNames.ContentTransferEncoding, StringComparison.InvariantCultureIgnoreCase) == 0)
                            {
                                article.ContentTransferEncoding += nameValuePair[1].ToString();
                            }
                        }
                        else
                        {
                        }
                    }  // isHeader
                    else
                    {
                        // Body:
                        // undo dot stuff (remove the first dott, if there are two dots...
                        if (line.IndexOf("..", StringComparison.InvariantCultureIgnoreCase) == 0)
                        {
                            line = line.Substring(1);
                        }
                        articleBody.Append(line + "\n");
                    }
                }  // foreach

                article.Body = articleBody.ToString();

                // Check for mimePostings:
                if (article.ContentType.IndexOf("multipart", StringComparison.InvariantCultureIgnoreCase) == 0)
                {
                    isMimePost = true;
                }


                if (isMimePost)
                {
                    var mime = new Mime {
                        Text = article.Body
                    };

                    // Exract boundary:
                    var m2 = _bondaryRegex.Match(article.ContentType);
                    if (m2.Success)
                    {
                        mime.Boundary = m2.Groups[1].Value;
                    }

                    string textPlain            = null;
                    string textPlainContentType = null;
                    string textHtml             = null;
                    string textHtmlContentType  = null;

                    foreach (var mimePart in mime.MimeParts)
                    {
                        var ct = mimePart.GetPropertyValue("Content-Type");
                        if (ct.IndexOf("text/plain", StringComparison.InvariantCultureIgnoreCase) >= 0)
                        {
                            textPlainContentType = ct;
                            textPlain            = (string)mimePart.Decode();
                        }
                        if (ct.IndexOf("text/html", StringComparison.InvariantCultureIgnoreCase) >= 0)
                        {
                            textHtmlContentType = ct;
                            textHtml            = (string)mimePart.Decode();
                        }
                        if ((textPlain != null) && (textHtml != null))
                        {
                            break;
                        }
                    }

                    if ((textPlain == null) && (textHtml == null))
                    {
                        //System.Diagnostics.Trace.WriteLine("Posting failed - text part not found");
                        //return PostStatus.FailedTextPartMissingInHtml;
                        return(GeneralResponses.PostingFailedTextPartMissingInMime);
                    }
                    if (InMimeUseHtml && (textHtml != null))
                    {
                        article.Body        = textHtml;
                        article.ContentType = textHtmlContentType;
                        Traces.NntpServerTraceEvent(TraceEventType.Verbose, "MIME-Part: HTML selected");
                    }
                    else
                    {
                        if (textPlain != null)
                        {
                            article.Body        = textPlain;
                            article.ContentType = textPlainContentType;
                            Traces.NntpServerTraceEvent(TraceEventType.Verbose, "MIME-Part: plain/text selected");
                        }
                        else
                        {
                            article.Body        = textHtml;
                            article.ContentType = textHtmlContentType;
                            Traces.NntpServerTraceEvent(TraceEventType.Verbose, "MIME-Part: HTML selected (no plain/text available)");
                        }
                    }
                }

                // Transcode the "body" according to the "charset", if one is specified:
                var    charSetMatch = _charSetRegex.Match(article.ContentType);
                string charSet      = Server.EncodingRecv.HeaderName; // default
                if (charSetMatch.Success)
                {
                    charSet = charSetMatch.Groups[1].Value;
                }

                if (isMimePost == false)
                {
                    if (article.ContentTransferEncoding.IndexOf("quoted-printable", StringComparison.InvariantCultureIgnoreCase) >= 0)
                    {
                        article.Body = MimePart.DecodeQuotedPrintable(article.Body);
                    }
                    else if (article.ContentTransferEncoding.IndexOf("base64", StringComparison.InvariantCultureIgnoreCase) >= 0)
                    {
                        article.Body = MimePart.DecodeBase64(article.Body, charSet);
                    }
                }

                // Re-Encode after all data is now in the body...
                ReEncode(article, charSet);

                // post must have subject
                if (article.Subject.Trim().Length == 0)
                {
                    //System.Diagnostics.Trace.WriteLine("Posting failed - no subject line");
                    //return PostStatus.FailedSubjectLineBlank;
                    return(GeneralResponses.PostingFailedSubjectLineBlank);
                }

                // Decode Subject
                article.Subject = Mime.DecodeEncodedWordValue(article.Subject);

                var articles = new List <Article>();

                // Disabled cross posting (2010-06-06)
                //// Cross-Postings (Multiple-Postings) are allowed for "primary messages":
                //if ( (string.IsNullOrEmpty(article.References)) && (article.Newsgroups.IndexOf(",", StringComparison.InvariantCultureIgnoreCase) > 0) )
                //{
                //    string[] groupNames = article.Newsgroups.Split(',');
                //    foreach (var groupName in groupNames)
                //    {
                //        Newsgroup group = GetNewsgroupFromCacheOrServer(groupName.Trim());
                //        if (group != null && group.PostingAllowed)
                //        {
                //            // copy the article...
                //            var crossPostArticle = new Article();
                //            crossPostArticle.From = article.From;
                //            crossPostArticle.Body = article.Body;
                //            crossPostArticle.Date = article.Date;
                //            crossPostArticle.Subject = article.Subject;
                //            crossPostArticle.ParentNewsgroup = group.GroupName;
                //            //crossPostArticle.References = article.References;
                //            crossPostArticle.Newsgroups = article.Newsgroups;
                //            crossPostArticle.UserAgent = article.UserAgent;
                //            crossPostArticle.ContentType = article.ContentType;
                //            crossPostArticle.ContentTransferEncoding = article.ContentTransferEncoding;
                //            crossPostArticle.XNewsreader = article.XNewsreader;

                //            // add cross-posted footnote
                //            //crossPostArticle.Body += "\n\n[X-Posted To: " + article.Newsgroups + "]\n";

                //            articles.Add(crossPostArticle);
                //        }
                //        else
                //        {
                //            // indicate posting failure
                //            //System.Diagnostics.Trace.WriteLine("Posting failed - user [" + clientUsername + "] does not have permission to post to group [" + groupName + "]");
                //            return PostStatus.FailedAccessDenied;
                //        }
                //    }  // foreach

                //    if (articles.Count <= 0)
                //    {
                //        return PostStatus.FailedGroupNotFound;
                //    }
                //    else
                //    {
                //        SaveArticles(clientUsername, articles);
                //    }
                //}
                //else
                {
                    // Only one group or a reply:
                    if (article.Newsgroups.IndexOf(",", StringComparison.InvariantCultureIgnoreCase) > 0)
                    {
                        // Cross-Post are not allowed fro answers!
                        return(GeneralResponses.PostingFailedAccessDeniedMultipost);
                    }
                    var group = GetNewsgroupFromCacheOrServer(article.Newsgroups);
                    if (group != null && group.PostingAllowed)
                    {
                        article.ParentNewsgroup = group.GroupName;
                        articles.Add(article);
                        SaveArticles(clientUsername, articles);
                    }
                    else
                    {
                        // indicate posting failure
                        if (group != null)
                        {
                            //System.Diagnostics.Trace.WriteLine("Posting failed - user [" + clientUsername + "] does not have permission to post to group [" + group.GroupName + "]");
                            //return PostStatus.FailedAccessDenied;
                            return(GeneralResponses.PostingFailedAccessDenied);
                        }
                        //System.Diagnostics.Trace.WriteLine("Posting failed - newsgroup [" + article.Newsgroups + "] could not be found");
                        //return PostStatus.FailedGroupNotFound;
                        return(GeneralResponses.PostingFailedGroupNotFound);
                    }
                }

                return(GeneralResponses.ArticlePostedOk);
            }
            catch (Exception exp)
            {
                //System.Diagnostics.Trace.WriteLine("Error in DataProvider.PostArticle - " + ex.Message + " :: " + ex.StackTrace);
                Traces.NntpServerTraceEvent(System.Diagnostics.TraceEventType.Critical, "Error in DataProvider.PostArticle: {0}", Traces.ExceptionToString(exp));

                var resp = string.Format("441 posting failed {0}\r\n", NntpServer.GetErrorResponseFromExeption(exp));

                //return GeneralResponses.PostingFailed;

                return(resp);
            }
        }
コード例 #11
0
 public static string DecodeBase64(string text, string charSet)
 {
     if (string.IsNullOrEmpty(text))
     {
         return(text);
     }
     try
     {
         var    enc  = Encoding.GetEncoding(charSet);
         byte[] data = Convert.FromBase64String(text);
         return(enc.GetString(data));
     }
     catch (Exception exp)
     {
         Traces.NntpServerTraceEvent(TraceEventType.Error, "Error converting base64 text: {0}\r\n\r\n{1}", text, Traces.ExceptionToString(exp));
     }
     return(text);
 }
コード例 #12
0
 public static string DecodeQuotedPrintable(string text)
 {
     if (string.IsNullOrEmpty(text))
     {
         return(text);
     }
     try
     {
         var returnValue = qpRegEx.Replace(text, new MatchEvaluator(ReplaceOctet));
         return(returnValue.Replace("=\n", " "));
     }
     catch (Exception exp)
     {
         Traces.NntpServerTraceEvent(TraceEventType.Error, "Error converting QP text: {0}\r\n\r\n{1}", text, Traces.ExceptionToString(exp));
     }
     return(text);
 }