Пример #1
0
func handleList(args []string, s *session, c *textproto.Conn) error {
	ltype := "active"
	if len(args) > 0 {
		ltype = strings.ToLower(args[0])
	}

	if ltype == "overview.fmt" {
		return handleListOverviewFmt(c)
	}

	groups, err := s.backend.ListGroups(-1)
	if err != nil {
		return err
	}
	c.PrintfLine("215 list of newsgroups follows")
	dw := c.DotWriter()
	defer dw.Close()
	for _, g := range groups {
		switch ltype {
		case "active":
			fmt.Fprintf(dw, "%s %d %d %v\r\n",
				g.Name, g.High, g.Low, g.Posting)
		case "newsgroups":
			fmt.Fprintf(dw, "%s %s\r\n", g.Name, g.Description)
		}
	}

	return nil
}
Пример #2
0
func collectLines(c *textproto.Conn) ([]string, error) {
	var ex error
	var line string
	var msg []string
	var ended bool

	line, ex = c.ReadLine()

	if ex != nil {
		return nil, ex
	}

	if !validLine(line) {
		return nil, ErrShortResponse
	}

	msg = append(msg, line)

	ended = line[3] != '-'

	for ex == nil && !ended {
		line, ex = c.ReadLine()

		if ex != nil {
			return nil, ex
		}

		msg = append(msg, line)
		ended = line[3] != '-'
	}

	return msg, nil
}
Пример #3
0
func GetRequest(request Request, client *textproto.Conn) error {
	var err error
	defer func() {
		if err != nil {
			if err == io.EOF {
			} else {
				log.Println("Conn died with err %s", err)
			}
		}
	}()

	requestHeaders, err := client.ReadMIMEHeader()
	if err != nil {
		return err
	}

	response := fmt.Sprintf("Hello from Baboon!\nHave I seen you before?"+
		"\nI know a bit about you.\n"+
		"For example, your User Agent is %s", requestHeaders["User-Agent"])
	serverHeaders := map[string]string{}
	serverHeaders["Server"] = "Baboon/0.001"
	serverHeaders["Content-Type"] = "text/plain"
	serverHeaders["Content-Length"] = strconv.Itoa(len(response))

	client.PrintfLine("HTTP/1.1 200 OK")
	for key, value := range serverHeaders {
		client.PrintfLine("%s: %s", key, value)
	}
	client.PrintfLine("")
	client.PrintfLine(response)
	return nil
}
Пример #4
0
func processConnData(conn *textproto.Conn) response {
	res := response{Data: make([]string, 0)}
	for {
		line, err := conn.ReadLine()
		if err != nil {
			res.Err = err
			break
		}
		if line == "OK" {
			break
		}
		match := mpdErrorRegexp.FindStringSubmatch(line)
		if match != nil {
			ack, err := strconv.ParseUint(match[1], 0, 0)
			if err != nil {
				res.Err = err
				break
			}
			cln, err := strconv.ParseUint(match[2], 0, 0)
			if err != nil {
				res.Err = err
				break
			}
			res.MPDErr = &MPDError{uint(ack), uint(cln), match[3], match[4]}
			break
		}
		res.Data = append(res.Data, line)
	}
	return res
}
Пример #5
0
func (self *nntpConnection) startReader(daemon *NNTPDaemon, conn *textproto.Conn) {
	log.Println(self.name, "run reader mode")
	for {
		var err error
		select {
		case chnl := <-self.die:
			// we were asked to die
			// send quit
			conn.PrintfLine("QUIT")
			chnl <- true
			break
		case msgid := <-self.article:
			// next article to ask for
			log.Println(self.name, "obtaining", msgid)
			self.messageSetPendingState(msgid, "article")
			err = self.requestArticle(daemon, conn, msgid)
			self.messageSetProcessed(msgid)
			if err != nil {
				log.Println(self.name, "error while in reader mode:", err)
				break
			}
		}
	}
	// close connection
	conn.Close()
}
Пример #6
0
func handleMode(args []string, s *session, c *textproto.Conn) error {
	if s.backend.AllowPost() {
		c.PrintfLine("200 Posting allowed")
	} else {
		c.PrintfLine("201 Posting prohibited")
	}
	return nil
}
Пример #7
0
func handle(c *textproto.Conn, verifyOnly bool) {
	defer c.Close()
	defer func() {
		if r := recover(); r != nil {
			log.Println("Something went wrong:", r)
		}
	}()

	converse(c, verifyOnly)
}
Пример #8
0
func converse(c *textproto.Conn, verifyOnly bool) {
	write(c, "220 At your service")

	var msg Msg

	for {
		s, err := read(c)
		if err == io.EOF {
			return
		}

		if verifyOnly {
			log.Println("Incoming:", s)
		}

		cmd := strings.ToUpper(s[:4])

		switch cmd {
		case "EHLO":
			write(c, "250-8BITMIME")
			fallthrough
		case "HELO":
			write(c, "250 I need orders")
		case "MAIL":
			msg.From = addrRegex.FindStringSubmatch(s)[1]
			write(c, "250 In your name")
		case "RCPT":
			addr := addrRegex.FindStringSubmatch(s)[1]
			msg.To = append(msg.To, addr)
			write(c, "250 Defending your honour")
		case "DATA":
			if verifyOnly {
				write(c, "502 Verification service only")
				return
			}

			write(c, "354 Give me a quest!")
			data, err := c.ReadDotBytes()
			if err != nil {
				panic(err)
			}
			msg.Data = data

			defaultHandle(&msg)

			write(c, "250 We move")
		case "RSET":
			write(c, "250 OK")
		case "QUIT":
			write(c, "221 For the king")
		default:
			log.Println("Unknown command:", s)
		}
	}
}
Пример #9
0
func handleBody(args []string, s *session, c *textproto.Conn) error {
	article, err := s.getArticle(args)
	if err != nil {
		return err
	}
	c.PrintfLine("222 1 %s", article.MessageId())
	dw := c.DotWriter()
	defer dw.Close()
	_, err = io.Copy(dw, article.Body)
	return err
}
Пример #10
0
func newClient(conn *textproto.Conn) (*Conn, error) {
	_, msg, err := conn.ReadCodeLine(200)
	if err != nil {
		return nil, err
	}

	return &Conn{
		conn:   conn,
		Banner: msg,
	}, nil
}
Пример #11
0
func (self *nntpConnection) startReader(daemon NNTPDaemon, conn *textproto.Conn) {
	log.Println(self.name, "run reader mode")
	var err error
	for err == nil {
		// next article to ask for
		msgid := <-self.article
		err = self.requestArticle(daemon, conn, msgid)
	}
	// report error and close connection
	log.Println(self.name, "error while in reader mode:", err)
	conn.Close()
}
Пример #12
0
func read(c *textproto.Conn) (string, error) {
	s, err := c.ReadLine()
	if err == io.EOF {
		return s, err
	}

	if err != nil {
		panic(err)
	}

	return s, err
}
Пример #13
0
func handleHead(args []string, s *session, c *textproto.Conn) error {
	article, err := s.getArticle(args)
	if err != nil {
		return err
	}
	c.PrintfLine("221 1 %s", article.MessageId())
	dw := c.DotWriter()
	defer dw.Close()
	for k, v := range article.Header {
		fmt.Fprintf(dw, "%s: %s\r\n", k, v[0])
	}
	return nil
}
Пример #14
0
func handleIHave(args []string, s *session, c *textproto.Conn) error {
	if !s.backend.AllowPost() {
		return NotWanted
	}

	// XXX:  See if we have it.
	article, err := s.backend.GetArticle(nil, args[0])
	if article != nil {
		return NotWanted
	}

	c.PrintfLine("335 send it")
	article = new(nntp.Article)
	article.Header, err = c.ReadMIMEHeader()
	if err != nil {
		return PostingFailed
	}
	article.Body = c.DotReader()
	err = s.backend.Post(article)
	if err != nil {
		return err
	}
	c.PrintfLine("235 article received OK")
	return nil
}
Пример #15
0
func handleListOverviewFmt(dw io.Writer, c *textproto.Conn) error {
	err := c.PrintfLine("215 list of newsgroups follows")
	if err != nil {
		return err
	}
	_, err = fmt.Fprintln(dw, `Subject:
From:
Date:
Message-ID:
References:
:bytes
:lines`)
	return err
}
Пример #16
0
func handleAuthInfo(args []string, s *session, c *textproto.Conn) error {
	if len(args) < 2 {
		return SyntaxError
	}
	if strings.ToLower(args[0]) != "user" {
		return SyntaxError
	}

	if s.backend.Authorized() {
		return c.PrintfLine("250 authenticated")
	}

	c.PrintfLine("350 Continue")
	a, err := c.ReadLine()
	parts := strings.SplitN(a, " ", 3)
	if strings.ToLower(parts[0]) != "authinfo" || strings.ToLower(parts[1]) != "pass" {
		return SyntaxError
	}
	b, err := s.backend.Authenticate(args[1], parts[2])
	if err == nil {
		c.PrintfLine("250 authenticated")
		if b != nil {
			s.backend = b
		}
	}
	return err
}
Пример #17
0
func handleCap(args []string, s *session, c *textproto.Conn) error {
	c.PrintfLine("101 Capability list:")
	dw := c.DotWriter()
	defer dw.Close()

	fmt.Fprintf(dw, "VERSION 2\n")
	fmt.Fprintf(dw, "READER\n")
	if s.backend.AllowPost() {
		fmt.Fprintf(dw, "POST\n")
		fmt.Fprintf(dw, "IHAVE\n")
	}
	fmt.Fprintf(dw, "OVER\n")
	fmt.Fprintf(dw, "XOVER\n")
	fmt.Fprintf(dw, "LIST ACTIVE NEWSGROUPS OVERVIEW.FMT\n")
	return nil
}
Пример #18
0
func handleListOverviewFmt(c *textproto.Conn) error {
	err := c.PrintfLine("215 Order of fields in overview database.")
	if err != nil {
		return err
	}
	dw := c.DotWriter()
	defer dw.Close()
	_, err = fmt.Fprintln(dw, `Subject:
From:
Date:
Message-ID:
References:
:bytes
:lines`)
	return err
}
Пример #19
0
func handleGroup(args []string, s *session, c *textproto.Conn) error {
	if len(args) < 1 {
		return NoSuchGroup
	}

	group, err := s.backend.GetGroup(args[0])
	if err != nil {
		return err
	}

	s.group = group

	c.PrintfLine("211 %d %d %d %s",
		group.Count, group.Low, group.High, group.Name)
	return nil
}
Пример #20
0
// ask for an article from the remote server
// feed it to the daemon if we get it
func (self *nntpConnection) requestArticle(daemon NNTPDaemon, conn *textproto.Conn, msgid string) (err error) {
	log.Println(self.name, "asking for", msgid)
	// send command
	err = conn.PrintfLine("ARTICLE %s", msgid)
	// read response
	code, line, err := conn.ReadCodeLine(-1)
	if code == 220 {
		// awwww yeh we got it
		var hdr textproto.MIMEHeader
		// read header
		hdr, err = conn.ReadMIMEHeader()
		if err == nil {
			// prepare to read body
			dr := conn.DotReader()
			// check header and decide if we want this
			reason, err := self.checkMIMEHeader(daemon, hdr)
			if err == nil {
				if len(reason) > 0 {
					log.Println(self.name, "discarding", msgid, reason)
					// we don't want it, discard
					io.Copy(ioutil.Discard, dr)
					daemon.database.BanArticle(msgid, reason)
				} else {
					// yeh we want it open up a file to store it in
					f := daemon.store.CreateTempFile(msgid)
					if f == nil {
						// already being loaded elsewhere
					} else {
						// write header to file
						writeMIMEHeader(f, hdr)
						// write article body to file
						_, _ = io.Copy(f, dr)
						// close file
						f.Close()
						log.Println(msgid, "obtained via reader from", self.name)
						// tell daemon to load article via infeed
						daemon.infeed_load <- msgid
					}
				}
			} else {
				// error happened while processing
				log.Println(self.name, "error happend while processing MIME header", err)
			}
		} else {
			// error happened while reading header
			log.Println(self.name, "error happened while reading MIME header", err)
		}
	} else if code == 430 {
		// they don't know it D:
		log.Println(msgid, "not known by", self.name)
	} else {
		// invalid response
		log.Println(self.name, "invald response to ARTICLE:", code, line)
	}
	return
}
Пример #21
0
// switch modes
func (self *nntpConnection) modeSwitch(mode string, conn *textproto.Conn) (success bool, err error) {
	self.access.Lock()
	mode = strings.ToUpper(mode)
	conn.PrintfLine("MODE %s", mode)
	var code int
	code, _, err = conn.ReadCodeLine(-1)
	if code >= 200 && code < 300 {
		// accepted mode change
		if len(self.mode) > 0 {
			log.Printf(self.name, "mode switch %s -> %s", self.mode, mode)
		} else {
			log.Println(self.name, "switched to mode", mode)
		}
		self.mode = mode
		success = len(self.mode) > 0
	}
	self.access.Unlock()
	return
}
Пример #22
0
func NewCommandRequest(c *textproto.Conn) (*CommandRequest, error) {
	verb, err := c.ReadLine()
	if err != nil {
		return nil, err
	}

	headers, err := c.ReadMIMEHeader()
	if err != nil {
		return nil, err
	}

	// read body here

	return &CommandRequest{
		Method:  verb,
		Headers: headers,
		//Body: body,
	}, nil
}
Пример #23
0
// handle streaming events
// this function should send only
func (self *nntpConnection) handleStreaming(daemon *NNTPDaemon, conn *textproto.Conn) (err error) {
	for err == nil {
		select {
		case chnl := <-self.die:
			// someone asked us to die
			conn.PrintfLine("QUIT")
			conn.Close()
			chnl <- true
			return
		case msgid := <-self.check:
			err = self.handleStreamEvent(nntpCHECK(msgid), daemon, conn)
			self.messageSetPendingState(msgid, "check")
		case msgid := <-self.takethis:
			self.messageSetPendingState(msgid, "takethis")
			err = self.handleStreamEvent(nntpTAKETHIS(msgid), daemon, conn)
		}
	}
	return
}
Пример #24
0
func cmd(c *textproto.Conn, expectedCode int, format string, args ...interface{}) error {
	id, err := c.Cmd(format, args...)
	if err != nil {
		return err
	}

	c.StartResponse(id)
	_, _, err = c.ReadResponse(expectedCode)
	c.EndResponse(id)

	return err
}
Пример #25
0
func CloseConn(conn *textproto.Conn) error {
	id, err := conn.Cmd("close")
	if err != nil {
		return err
	}
	conn.StartResponse(id)
	conn.EndResponse(id)
	err = conn.Close()
	if err != nil {
		return err
	}
	return nil
}
Пример #26
0
func (s *server) readRequest(p *textproto.Conn) (*request, error) {
	line, err := p.ReadLine()
	if err == io.EOF {
		return nil, err
	}
	if err != nil {
		log.Printf("reading request failed: %v\n", err)
		return nil, err
	}
	args := parseArgs(line)
	if len(args) == 0 {
		return &request{typ: simple, args: args}, nil
	}
	switch args[0] {
	case "command_list_ok_begin":
		var cmdList [][]string
		for {
			line, err := p.ReadLine()
			if err == io.EOF {
				return nil, err
			}
			if err != nil {
				log.Printf("reading request failed: %v\n", err)
				return nil, err
			}
			args = parseArgs(line)
			if len(args) > 0 && args[0] == "command_list_end" {
				break
			}
			cmdList = append(cmdList, args)
		}
		return &request{typ: commandListOk, cmdList: cmdList}, nil

	case "idle":
		return &request{typ: idle, args: args}, nil

	case "noidle":
		return &request{typ: noIdle, args: args}, nil
	}
	return &request{typ: simple, args: args}, nil
}
Пример #27
0
func (s *server) writeIdleResponse(p *textproto.Conn, id uint, quit chan bool, subsystems []string) {
	p.StartResponse(id)
	defer p.EndResponse(id)

	req := &idleRequest{
		endTokenc:  make(chan uint),
		eventc:     make(chan string, 1),
		subsystems: subsystems,
	}
	s.idleStartc <- req
	token := <-req.endTokenc
	select {
	case name := <-req.eventc:
		p.PrintfLine("changed: %s", name)
		p.PrintfLine("OK")
		<-quit
	case <-quit:
		p.PrintfLine("OK")
	}
	s.idleEndc <- token
}
Пример #28
0
// handle sending 1 stream event
func (self *nntpConnection) handleStreamEvent(ev nntpStreamEvent, daemon *NNTPDaemon, conn *textproto.Conn) (err error) {
	if ValidMessageID(ev.MessageID()) {
		cmd, msgid := ev.Command(), ev.MessageID()
		if cmd == "TAKETHIS" {
			// open message for reading
			var rc io.ReadCloser
			rc, err = daemon.store.OpenMessage(msgid)
			if err == nil {
				err = conn.PrintfLine("%s", ev)
				// time to send
				dw := conn.DotWriter()
				_, err = io.Copy(dw, rc)
				err = dw.Close()
				rc.Close()
				self.messageSetPendingState(msgid, "sent")
			} else {
				log.Println(self.name, "didn't send", msgid, err)
				self.messageSetProcessed(msgid)
				// ignore this error
				err = nil
			}
		} else if cmd == "CHECK" {
			conn.PrintfLine("%s", ev)
		} else {
			log.Println("invalid stream command", ev)
		}
	}
	return
}
Пример #29
0
// handle streaming event
// this function should send only
func (self *nntpConnection) handleStreaming(daemon NNTPDaemon, reader bool, conn *textproto.Conn) (err error) {
	for err == nil {
		ev := <-self.stream
		log.Println(self.name, ev)
		if ValidMessageID(ev.MessageID()) {
			cmd, msgid := ev.Command(), ev.MessageID()
			if cmd == "TAKETHIS" {
				fname := daemon.store.GetFilename(msgid)
				if CheckFile(fname) {
					f, err := os.Open(fname)
					if err == nil {
						err = conn.PrintfLine("%s", ev)
						// time to send
						dw := conn.DotWriter()
						_, err = io.Copy(dw, f)
						err = dw.Close()
						f.Close()
					}
				} else {
					log.Println(self.name, "didn't send", msgid, "we don't have it locally")
				}
			} else if cmd == "CHECK" {
				conn.PrintfLine("%s", ev)
			} else {
				log.Println("invalid stream command", ev)
			}
		}
	}
	return
}
Пример #30
0
// handle streaming event
// this function should send only
func (self nntpConnection) handleStreaming(daemon NNTPDaemon, reader bool, conn *textproto.Conn) (err error) {
	select {
	case msgid := <-self.check:
		log.Println(self.name, "CHECK", msgid)
		err = conn.PrintfLine("CHECK %s", msgid)
	case msgid := <-self.take:
		// send a file via TAKETHIS
		if ValidMessageID(msgid) {
			fname := daemon.store.GetFilename(msgid)
			if CheckFile(fname) {
				f, err := os.Open(fname)
				if err == nil {
					// time to send
					err = conn.PrintfLine("TAKETHIS %s", msgid)
					dw := conn.DotWriter()
					_, err = io.Copy(dw, f)
					err = dw.Close()
					f.Close()
				}
			} else {
				log.Println(self.name, "didn't send", msgid, "we don't have it locally")
			}
		}
	}
	return
}