mirror of
https://github.com/ChronosX88/yans.git
synced 2024-11-22 11:42:19 +00:00
Implement basic functionality of IHAVE command
This commit is contained in:
parent
564947e75c
commit
54413c5143
@ -66,6 +66,7 @@ const (
|
|||||||
CommandNext = "NEXT"
|
CommandNext = "NEXT"
|
||||||
CommandOver = "OVER"
|
CommandOver = "OVER"
|
||||||
CommandXover = "XOVER"
|
CommandXover = "XOVER"
|
||||||
|
CommandIHave = "IHAVE"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -6,18 +6,20 @@ import (
|
|||||||
"database/sql"
|
"database/sql"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"net/mail"
|
||||||
|
"path"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/ChronosX88/yans/internal/backend"
|
"github.com/ChronosX88/yans/internal/backend"
|
||||||
"github.com/ChronosX88/yans/internal/models"
|
"github.com/ChronosX88/yans/internal/models"
|
||||||
"github.com/ChronosX88/yans/internal/protocol"
|
"github.com/ChronosX88/yans/internal/protocol"
|
||||||
"github.com/ChronosX88/yans/internal/utils"
|
"github.com/ChronosX88/yans/internal/utils"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/jhillyerd/enmime"
|
"github.com/jhillyerd/enmime"
|
||||||
"io/ioutil"
|
|
||||||
"net/mail"
|
|
||||||
"path"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Handler struct {
|
type Handler struct {
|
||||||
@ -50,6 +52,7 @@ func NewHandler(b backend.StorageBackend, serverDomain, uploadPath string) *Hand
|
|||||||
protocol.CommandNext: h.handleNext,
|
protocol.CommandNext: h.handleNext,
|
||||||
protocol.CommandOver: h.handleOver,
|
protocol.CommandOver: h.handleOver,
|
||||||
protocol.CommandXover: h.handleOver,
|
protocol.CommandXover: h.handleOver,
|
||||||
|
protocol.CommandIHave: h.handleIHave,
|
||||||
|
|
||||||
// project-specific extensions
|
// project-specific extensions
|
||||||
"NEWTHREADS": h.handleNewThreads,
|
"NEWTHREADS": h.handleNewThreads,
|
||||||
@ -319,6 +322,21 @@ func (h *Handler) handlePost(s *Session, command string, arguments []string, id
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
h.saveArticle(envelope, true)
|
||||||
|
if err != nil {
|
||||||
|
if err.Error() == "no such message you are replying to" {
|
||||||
|
return s.tconn.PrintfLine(protocol.NNTPResponse{Code: 441, Message: "no such message you are replying to"}.String())
|
||||||
|
} else if err.Error() == "disallowed attachment type" {
|
||||||
|
return s.tconn.PrintfLine(protocol.NNTPResponse{Code: 441, Message: "disallowed attachment type"}.String())
|
||||||
|
}
|
||||||
|
return s.tconn.PrintfLine(protocol.NNTPResponse{Code: 441, Message: err.Error()}.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.tconn.PrintfLine(protocol.NNTPResponse{Code: 240, Message: "Article received OK"}.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) saveArticle(envelope *enmime.Envelope, generateHeaders bool) error {
|
||||||
|
if generateHeaders {
|
||||||
// generate message id
|
// generate message id
|
||||||
messageID := fmt.Sprintf("<%s@%s>", uuid.New().String(), h.serverDomain)
|
messageID := fmt.Sprintf("<%s@%s>", uuid.New().String(), h.serverDomain)
|
||||||
envelope.SetHeader("Message-ID", []string{messageID})
|
envelope.SetHeader("Message-ID", []string{messageID})
|
||||||
@ -328,6 +346,7 @@ func (h *Handler) handlePost(s *Session, command string, arguments []string, id
|
|||||||
|
|
||||||
// set date header
|
// set date header
|
||||||
envelope.AddHeader("Date", time.Now().UTC().Format(time.RFC1123Z))
|
envelope.AddHeader("Date", time.Now().UTC().Format(time.RFC1123Z))
|
||||||
|
}
|
||||||
|
|
||||||
headerJson, err := json.Marshal(envelope.Root.Header)
|
headerJson, err := json.Marshal(envelope.Root.Header)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -348,8 +367,9 @@ func (h *Handler) handlePost(s *Session, command string, arguments []string, id
|
|||||||
if envelope.GetHeader("In-Reply-To") != "" {
|
if envelope.GetHeader("In-Reply-To") != "" {
|
||||||
parentMessage, err := h.backend.GetArticle(envelope.GetHeader("In-Reply-To"))
|
parentMessage, err := h.backend.GetArticle(envelope.GetHeader("In-Reply-To"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
return err
|
||||||
if err == sql.ErrNoRows {
|
if err == sql.ErrNoRows {
|
||||||
return s.tconn.PrintfLine(protocol.NNTPResponse{Code: 441, Message: "no such message you are replying to"}.String())
|
return fmt.Errorf("no such message you are replying to")
|
||||||
} else {
|
} else {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -368,7 +388,7 @@ func (h *Handler) handlePost(s *Session, command string, arguments []string, id
|
|||||||
// save attachments
|
// save attachments
|
||||||
for _, v := range envelope.Attachments {
|
for _, v := range envelope.Attachments {
|
||||||
if v.ContentType != "image/jpeg" && v.ContentType != "image/png" && v.ContentType != "image/gif" {
|
if v.ContentType != "image/jpeg" && v.ContentType != "image/png" && v.ContentType != "image/gif" {
|
||||||
return s.tconn.PrintfLine(protocol.NNTPResponse{Code: 441, Message: "disallowed attachment type"}.String())
|
return fmt.Errorf("disallowed attachment type")
|
||||||
}
|
}
|
||||||
ext_ := strings.Split(v.FileName, ".")
|
ext_ := strings.Split(v.FileName, ".")
|
||||||
ext := ext_[len(ext_)-1]
|
ext := ext_[len(ext_)-1]
|
||||||
@ -386,10 +406,10 @@ func (h *Handler) handlePost(s *Session, command string, arguments []string, id
|
|||||||
|
|
||||||
err = h.backend.SaveArticle(a, strings.Split(a.Header.Get("Newsgroups"), ","))
|
err = h.backend.SaveArticle(a, strings.Split(a.Header.Get("Newsgroups"), ","))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return s.tconn.PrintfLine(protocol.NNTPResponse{Code: 441, Message: err.Error()}.String())
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return s.tconn.PrintfLine(protocol.NNTPResponse{Code: 240, Message: "Article received OK"}.String())
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) handleListgroup(s *Session, command string, arguments []string, id uint) error {
|
func (h *Handler) handleListgroup(s *Session, command string, arguments []string, id uint) error {
|
||||||
@ -938,6 +958,47 @@ func (h *Handler) handleThread(s *Session, command string, arguments []string, i
|
|||||||
return dw.Close()
|
return dw.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *Handler) handleIHave(s *Session, command string, arguments []string, id uint) error {
|
||||||
|
s.tconn.StartResponse(id)
|
||||||
|
defer s.tconn.EndResponse(id)
|
||||||
|
|
||||||
|
if len(arguments) != 1 {
|
||||||
|
return s.tconn.PrintfLine(protocol.ErrSyntaxError.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := h.backend.GetArticle(arguments[0]); err == nil {
|
||||||
|
return s.tconn.PrintfLine(protocol.NNTPResponse{Code: 435, Message: "Duplicate"}.String())
|
||||||
|
} else {
|
||||||
|
log.Print(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := s.tconn.PrintfLine(protocol.NNTPResponse{Code: 335, Message: "Send it; end with <CR-LF>.<CR-LF>"}.String()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// TODO restrict sending the same article from other users
|
||||||
|
|
||||||
|
dr := s.tconn.DotReader()
|
||||||
|
|
||||||
|
envelope, err := enmime.ReadEnvelope(dr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
msgID := envelope.GetHeader("Message-ID")
|
||||||
|
if msgID == "" {
|
||||||
|
return s.tconn.PrintfLine(protocol.NNTPResponse{Code: 436, Message: "Transfer failed"}.String())
|
||||||
|
}
|
||||||
|
// TODO also check whether message id in the article is the same as was previously
|
||||||
|
|
||||||
|
err = h.saveArticle(envelope, false)
|
||||||
|
if err != nil {
|
||||||
|
// TODO add proper error handling
|
||||||
|
return s.tconn.PrintfLine(protocol.NNTPResponse{Code: 436, Message: fmt.Sprintf("Transfer failed: %s", err.Error())}.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.tconn.PrintfLine(protocol.NNTPResponse{Code: 235, Message: "Article transferred OK"}.String())
|
||||||
|
}
|
||||||
|
|
||||||
func (h *Handler) Handle(s *Session, message string, id uint) error {
|
func (h *Handler) Handle(s *Session, message string, id uint) error {
|
||||||
splittedMessage := strings.Split(message, " ")
|
splittedMessage := strings.Split(message, " ")
|
||||||
for i, v := range splittedMessage {
|
for i, v := range splittedMessage {
|
||||||
|
@ -22,6 +22,7 @@ var (
|
|||||||
{Type: protocol.ImplementationCapability, Params: fmt.Sprintf("%s %s", common.ServerName, common.ServerVersion)},
|
{Type: protocol.ImplementationCapability, Params: fmt.Sprintf("%s %s", common.ServerName, common.ServerVersion)},
|
||||||
{Type: protocol.OverCapability, Params: "MSGID"},
|
{Type: protocol.OverCapability, Params: "MSGID"},
|
||||||
{Type: protocol.ModeReaderCapability},
|
{Type: protocol.ModeReaderCapability},
|
||||||
|
{Type: protocol.IHaveCapability},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user