diff --git a/go.mod b/go.mod index 9b604df..bc80f97 100644 --- a/go.mod +++ b/go.mod @@ -4,13 +4,11 @@ go 1.17 require ( github.com/BurntSushi/toml v1.0.0 + github.com/dlclark/regexp2 v1.4.0 github.com/google/uuid v1.3.0 github.com/jmoiron/sqlx v1.3.4 github.com/mattn/go-sqlite3 v1.14.10 github.com/pressly/goose/v3 v3.5.0 ) -require ( - github.com/dlclark/regexp2 v1.4.0 // indirect - github.com/pkg/errors v0.9.1 // indirect -) +require github.com/pkg/errors v0.9.1 // indirect diff --git a/internal/models/article.go b/internal/models/article.go index 39e04e4..3acdc1f 100644 --- a/internal/models/article.go +++ b/internal/models/article.go @@ -14,68 +14,3 @@ type Article struct { Body string `db:"body"` Thread sql.NullString `db:"thread"` } - -//func ParseArticle(lines []string) (Article, error) { -// article := Article{} -// headerBlock := true -// for _, v := range lines { -// if v == "" { -// headerBlock = false -// } -// -// if headerBlock { -// kv := strings.Split(v, ":") -// if len(kv) < 2 { -// return Article{}, fmt.Errorf("invalid header format") -// } -// -// kv[0] = strings.TrimSpace(kv[0]) -// kv[1] = strings.TrimSpace(kv[1]) -// -// if !protocol.IsMessageHeaderAllowed(kv[0]) { -// return Article{}, fmt.Errorf("invalid header element") -// } -// if kv[1] == "" { -// return Article{}, fmt.Errorf("header value should not be empty") -// } -// -// switch kv[0] { -// case "Archive": -// { -// if kv[1] == "yes" { -// article.Archive = true -// } else { -// article.Archive = false -// } -// } -// case "Injection-Date": -// { -// date, err := mail.ParseDate(kv[1]) -// if err != nil { -// return Article{}, err -// } -// article.InjectionDate = date -// } -// case "Date": -// { -// date, err := mail.ParseDate(kv[1]) -// if err != nil { -// return Article{}, err -// } -// article.Date = date -// } -// case "Expires": -// { -// date, err := mail.ParseDate(kv[1]) -// if err != nil { -// return Article{}, err -// } -// article.Expires = date -// } -// } -// -// } else { -// } -// } -// return article, nil -//} diff --git a/internal/protocol/constants.go b/internal/protocol/constants.go index 3e0fcfe..86d9ea5 100644 --- a/internal/protocol/constants.go +++ b/internal/protocol/constants.go @@ -70,14 +70,3 @@ const ( CapabilityNameImplementation = "IMPLEMENTATION" CapabilityNameModeReader = "MODE-READER" ) - -const ( - MessageNNTPServiceReadyPostingProhibited = "201 YANS NNTP Service Ready, posting prohibited" - MessageReaderModePostingProhibited = "201 Reader mode, posting prohibited" - MessageNNTPServiceExitsNormally = "205 NNTP Service exits normally, bye!" - MessageErrorHappened = "403 Failed to process command:" - MessageListOfNewsgroupsFollows = "215 list of newsgroups follows" - MessageNoSuchGroup = "411 No such newsgroup" - MessageInputArticle = "340 Input article; end with ." - MessageArticleReceived = "240 Article received OK" -) diff --git a/internal/server/handler.go b/internal/server/handler.go index 92c51d0..fb30de6 100644 --- a/internal/server/handler.go +++ b/internal/server/handler.go @@ -49,11 +49,11 @@ func (h *Handler) handleCapabilities(s *Session, arguments []string, id uint) er func (h *Handler) handleDate(s *Session, arguments []string, id uint) error { s.tconn.StartResponse(id) defer s.tconn.EndResponse(id) - return s.tconn.PrintfLine("111 %s", time.Now().UTC().Format("20060102150405")) + return s.tconn.PrintfLine(protocol.NNTPResponse{Code: 111, Message: time.Now().UTC().Format("20060102150405")}.String()) } func (h *Handler) handleQuit(s *Session, arguments []string, id uint) error { - s.tconn.PrintfLine(protocol.MessageNNTPServiceExitsNormally) + s.tconn.PrintfLine(protocol.NNTPResponse{Code: 205, Message: "NNTP Service exits normally, bye!"}.String()) s.conn.Close() return nil } @@ -85,7 +85,7 @@ func (h *Handler) handleList(s *Session, arguments []string, id uint) error { if err != nil { return err } - sb.Write([]byte(protocol.MessageListOfNewsgroupsFollows + protocol.CRLF)) + sb.Write([]byte(protocol.NNTPResponse{Code: 215, Message: "list of newsgroups follows"}.String() + protocol.CRLF)) for _, v := range groups { // TODO set actual post permission status c, err := h.backend.GetArticlesCount(&v) @@ -120,7 +120,7 @@ func (h *Handler) handleList(s *Session, arguments []string, id uint) error { return err } - sb.Write([]byte(protocol.MessageListOfNewsgroupsFollows + protocol.CRLF)) + sb.Write([]byte(protocol.NNTPResponse{Code: 215, Message: "list of newsgroups follows"}.String() + protocol.CRLF)) for _, v := range groups { desc := "" if v.Description == nil { @@ -156,7 +156,7 @@ func (h *Handler) handleModeReader(s *Session, arguments []string, id uint) erro (&s.capabilities).Add(protocol.Capability{Type: protocol.ListCapability, Params: "ACTIVE NEWSGROUPS"}) s.mode = SessionModeReader - return s.tconn.PrintfLine(protocol.MessageReaderModePostingProhibited) // TODO vary on auth status + return s.tconn.PrintfLine(protocol.NNTPResponse{Code: 201, Message: "Reader mode, posting prohibited"}.String()) // TODO vary on auth status } func (h *Handler) handleGroup(s *Session, arguments []string, id uint) error { @@ -170,7 +170,7 @@ func (h *Handler) handleGroup(s *Session, arguments []string, id uint) error { g, err := h.backend.GetGroup(arguments[0]) if err != nil { if err == sql.ErrNoRows { - return s.tconn.PrintfLine(protocol.MessageNoSuchGroup) + return s.tconn.PrintfLine(protocol.NNTPResponse{Code: 411, Message: "No such newsgroup"}.String()) } else { return err } @@ -266,7 +266,7 @@ func (h *Handler) handlePost(s *Session, arguments []string, id uint) error { return s.tconn.PrintfLine(protocol.ErrSyntaxError.String()) } - if err := s.tconn.PrintfLine(protocol.MessageInputArticle); err != nil { + if err := s.tconn.PrintfLine(protocol.NNTPResponse{Code: 340, Message: "Input article; end with ."}.String()); err != nil { return err } @@ -324,7 +324,7 @@ func (h *Handler) handlePost(s *Session, arguments []string, id uint) error { return s.tconn.PrintfLine(protocol.NNTPResponse{Code: 441, Message: err.Error()}.String()) } - return s.tconn.PrintfLine(protocol.MessageArticleReceived) + return s.tconn.PrintfLine(protocol.NNTPResponse{Code: 240, Message: "Article received OK"}.String()) } func (h *Handler) handleListgroup(s *Session, arguments []string, id uint) error { diff --git a/internal/server/session.go b/internal/server/session.go index 8a2dcb5..73213d5 100644 --- a/internal/server/session.go +++ b/internal/server/session.go @@ -2,6 +2,7 @@ package server import ( "context" + "fmt" "github.com/ChronosX88/yans/internal/models" "github.com/ChronosX88/yans/internal/protocol" "io" @@ -61,7 +62,7 @@ func (s *Session) loop() { close(s.closed) }() - err := s.tconn.PrintfLine(protocol.MessageNNTPServiceReadyPostingProhibited) // by default access mode is read-only + err := s.tconn.PrintfLine(protocol.NNTPResponse{Code: 201, Message: "YANS NNTP Service Ready, posting prohibited"}.String()) // by default access mode is read-only if err != nil { s.conn.Close() return @@ -90,7 +91,7 @@ func (s *Session) loop() { err = s.h.Handle(s, message, id) if err != nil { log.Print(err) - s.tconn.PrintfLine("%s %s", protocol.MessageErrorHappened, err.Error()) + s.tconn.PrintfLine(protocol.NNTPResponse{Code: 403, Message: fmt.Sprintf("Failed to process command: %s", err.Error())}.String()) s.conn.Close() return }