Exemplo n.º 1
0
Arquivo: get.go Projeto: jkbbwr/Baboon
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
}
Exemplo n.º 2
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
}
Exemplo n.º 3
0
Arquivo: nntp.go Projeto: 4cdn/srndv2
// 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
}
Exemplo n.º 4
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
}
Exemplo n.º 5
0
func handlePost(args []string, s *session, c *textproto.Conn) error {
	if !s.backend.AllowPost() {
		return PostingNotPermitted
	}

	c.PrintfLine("340 Go ahead")
	var err error
	var article 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("240 article received OK")
	return nil
}
Exemplo n.º 6
0
func (self nntpConnection) handleLine(daemon NNTPDaemon, code int, line string, conn *textproto.Conn) (err error) {
	parts := strings.Split(line, " ")
	var msgid string
	if code == 0 && len(parts) > 1 {
		msgid = parts[1]
	} else {
		msgid = parts[0]
	}
	if code == 238 {
		if ValidMessageID(msgid) {
			log.Println("sending", msgid, "to", self.name)
			// send the article to us
			self.take <- msgid
		}
	} else if code == 239 {
		// successful TAKETHIS
		log.Println(msgid, "sent via", self.name)
		// TODO: remember success
	} else if code == 431 {
		// CHECK said we would like this article later
		log.Println("defer sending", msgid, "to", self.name)
		go self.articleDefer(msgid)
	} else if code == 439 {
		// TAKETHIS failed
		log.Println(msgid, "was not sent to", self.name, "denied:", line)
		// TODO: remember denial
	} else if code == 438 {
		// they don't want the article
		// TODO: remeber rejection
	} else {
		// handle command
		parts := strings.Split(line, " ")
		if len(parts) == 2 {
			cmd := parts[0]
			if cmd == "MODE" {
				if parts[1] == "READER" {
					// reader mode
					self.mode = "READER"
					log.Println(self.name, "switched to reader mode")
					conn.PrintfLine("201 No posting Permitted")
				} else if parts[1] == "STREAM" {
					// wut? we're already in streaming mode
					log.Println(self.name, "already in streaming mode")
					conn.PrintfLine("203 Streaming enabled brah")
				} else {
					// invalid
					log.Println(self.name, "got invalid mode request", parts[1])
					conn.PrintfLine("501 invalid mode variant:", parts[1])
				}
			} else if cmd == "QUIT" {
				// quit command
				conn.PrintfLine("")
				// close our connection and return
				conn.Close()
				return
			} else if cmd == "CHECK" {
				// handle check command
				msgid := parts[1]
				// have we seen this article?
				if daemon.database.HasArticle(msgid) {
					// yeh don't want it
					conn.PrintfLine("438 %s", msgid)
				} else if daemon.database.ArticleBanned(msgid) {
					// it's banned we don't want it
					conn.PrintfLine("438 %s", msgid)
				} else {
					// yes we do want it and we don't have it
					conn.PrintfLine("238 %s", msgid)
				}
			} else if cmd == "TAKETHIS" {
				// handle takethis command
				var hdr textproto.MIMEHeader
				var reason string
				// read the article header
				hdr, err = conn.ReadMIMEHeader()
				if err == nil {
					// check the header
					reason, err = self.checkMIMEHeader(daemon, hdr)
					dr := conn.DotReader()
					if len(reason) > 0 {
						// discard, we do not want
						code = 439
						log.Println(self.name, "rejected", msgid, reason)
						_, err = io.Copy(ioutil.Discard, dr)
						err = daemon.database.BanArticle(msgid, reason)
					} else {
						// check if we don't have the rootpost
						reference := hdr.Get("References")
						newsgroup := hdr.Get("Newsgroups")
						if reference != "" && ValidMessageID(reference) && !daemon.store.HasArticle(reference) && !daemon.database.IsExpired(reference) {
							log.Println(self.name, "got reply to", reference, "but we don't have it")
							daemon.ask_for_article <- ArticleEntry{reference, newsgroup}
						}
						f := daemon.store.CreateTempFile(msgid)
						if f == nil {
							log.Println(self.name, "discarding", msgid, "we are already loading it")
							// discard
							io.Copy(ioutil.Discard, dr)
						} else {
							// write header
							err = writeMIMEHeader(f, hdr)
							// write body
							_, err = io.Copy(f, dr)
							if err == nil || err == io.EOF {
								f.Close()
								// we gud, tell daemon
								daemon.infeed_load <- msgid
							} else {
								log.Println(self.name, "error reading message", err)
							}
						}
						code = 239
						reason = "gotten"
					}
				} else {
					log.Println(self.name, "error reading mime header:", err)
					code = 439
					reason = "error reading mime header"
				}
				conn.PrintfLine("%d %s %s", code, msgid, reason)
			} else if cmd == "ARTICLE" {
				if ValidMessageID(msgid) {
					if daemon.store.HasArticle(msgid) {
						// we have it yeh
						f, err := os.Open(daemon.store.GetFilename(msgid))
						if err == nil {
							conn.PrintfLine("220 %s", msgid)
							dw := conn.DotWriter()
							_, err = io.Copy(dw, f)
							dw.Close()
							f.Close()
						} else {
							// wtf?!
							conn.PrintfLine("503 idkwtf happened: %s", err.Error())
						}
					} else {
						// we dont got it
						conn.PrintfLine("430 %s", msgid)
					}
				} else {
					// invalid id
					conn.PrintfLine("500 Syntax error")
				}
			}
		}
	}
	return
}
Exemplo n.º 7
0
Arquivo: nntp.go Projeto: 4cdn/srndv2
func (self *nntpConnection) handleLine(daemon NNTPDaemon, code int, line string, conn *textproto.Conn) (err error) {
	parts := strings.Split(line, " ")
	var msgid string
	if code == 0 && len(parts) > 1 {
		msgid = parts[1]
	} else {
		msgid = parts[0]
	}
	if code == 238 {
		if ValidMessageID(msgid) {
			self.stream <- nntpTAKETHIS(msgid)
		}
		return
	} else if code == 239 {
		// successful TAKETHIS
		log.Println(msgid, "sent via", self.name)
		return
		// TODO: remember success
	} else if code == 431 {
		// CHECK said we would like this article later
		log.Println("defer sending", msgid, "to", self.name)
		go self.articleDefer(msgid)
	} else if code == 439 {
		// TAKETHIS failed
		log.Println(msgid, "was not sent to", self.name, "denied:", line)
		// TODO: remember denial
	} else if code == 438 {
		// they don't want the article
		// TODO: remeber rejection
	} else {
		// handle command
		parts := strings.Split(line, " ")
		if len(parts) > 1 {
			cmd := parts[0]
			if cmd == "MODE" {
				if parts[1] == "READER" {
					// reader mode
					self.mode = "READER"
					log.Println(self.name, "switched to reader mode")
					conn.PrintfLine("201 No posting Permitted")
				} else if parts[1] == "STREAM" {
					// wut? we're already in streaming mode
					log.Println(self.name, "already in streaming mode")
					conn.PrintfLine("203 Streaming enabled brah")
				} else {
					// invalid
					log.Println(self.name, "got invalid mode request", parts[1])
					conn.PrintfLine("501 invalid mode variant:", parts[1])
				}
			} else if cmd == "QUIT" {
				// quit command
				conn.PrintfLine("")
				// close our connection and return
				conn.Close()
				return
			} else if cmd == "CHECK" {
				// handle check command
				msgid := parts[1]
				// have we seen this article?
				if daemon.database.HasArticle(msgid) {
					// yeh don't want it
					conn.PrintfLine("438 %s", msgid)
				} else if daemon.database.ArticleBanned(msgid) {
					// it's banned we don't want it
					conn.PrintfLine("438 %s", msgid)
				} else {
					// yes we do want it and we don't have it
					conn.PrintfLine("238 %s", msgid)
				}
			} else if cmd == "TAKETHIS" {
				// handle takethis command
				var hdr textproto.MIMEHeader
				var reason string
				// read the article header
				hdr, err = conn.ReadMIMEHeader()
				if err == nil {
					// check the header
					reason, err = self.checkMIMEHeader(daemon, hdr)
					dr := conn.DotReader()
					if len(reason) > 0 {
						// discard, we do not want
						code = 439
						log.Println(self.name, "rejected", msgid, reason)
						_, err = io.Copy(ioutil.Discard, dr)
						err = daemon.database.BanArticle(msgid, reason)
					} else {
						// check if we don't have the rootpost
						reference := hdr.Get("References")
						newsgroup := hdr.Get("Newsgroups")
						if reference != "" && ValidMessageID(reference) && !daemon.store.HasArticle(reference) && !daemon.database.IsExpired(reference) {
							log.Println(self.name, "got reply to", reference, "but we don't have it")
							daemon.ask_for_article <- ArticleEntry{reference, newsgroup}
						}
						f := daemon.store.CreateTempFile(msgid)
						if f == nil {
							log.Println(self.name, "discarding", msgid, "we are already loading it")
							// discard
							io.Copy(ioutil.Discard, dr)
						} else {
							// write header
							err = writeMIMEHeader(f, hdr)
							// write body
							_, err = io.Copy(f, dr)
							if err == nil || err == io.EOF {
								f.Close()
								// we gud, tell daemon
								daemon.infeed_load <- msgid
							} else {
								log.Println(self.name, "error reading message", err)
							}
						}
						code = 239
						reason = "gotten"
					}
				} else {
					log.Println(self.name, "error reading mime header:", err)
					code = 439
					reason = "error reading mime header"
				}
				conn.PrintfLine("%d %s %s", code, msgid, reason)
			} else if cmd == "ARTICLE" {
				if ValidMessageID(msgid) {
					if daemon.store.HasArticle(msgid) {
						// we have it yeh
						f, err := os.Open(daemon.store.GetFilename(msgid))
						if err == nil {
							conn.PrintfLine("220 %s", msgid)
							dw := conn.DotWriter()
							_, err = io.Copy(dw, f)
							dw.Close()
							f.Close()
						} else {
							// wtf?!
							conn.PrintfLine("503 idkwtf happened: %s", err.Error())
						}
					} else {
						// we dont got it
						conn.PrintfLine("430 %s", msgid)
					}
				} else {
					// invalid id
					conn.PrintfLine("500 Syntax error")
				}
			} else if cmd == "POST" {
				// handle POST command
				conn.PrintfLine("340 Post it nigguh; end with <CR-LF>.<CR-LF>")
				hdr, err := conn.ReadMIMEHeader()
				var success bool
				if err == nil {
					hdr["Message-ID"] = []string{genMessageID(daemon.instance_name)}
					reason, err := self.checkMIMEHeader(daemon, hdr)
					success = reason == "" && err == nil
					if success {
						dr := conn.DotReader()
						reference := hdr.Get("References")
						newsgroup := hdr.Get("Newsgroups")
						if reference != "" && ValidMessageID(reference) && !daemon.store.HasArticle(reference) && !daemon.database.IsExpired(reference) {
							log.Println(self.name, "got reply to", reference, "but we don't have it")
							daemon.ask_for_article <- ArticleEntry{reference, newsgroup}
						}
						f := daemon.store.CreateTempFile(msgid)
						if f == nil {
							log.Println(self.name, "discarding", msgid, "we are already loading it")
							// discard
							io.Copy(ioutil.Discard, dr)
						} else {
							// write header
							err = writeMIMEHeader(f, hdr)
							// write body
							_, err = io.Copy(f, dr)
							if err == nil || err == io.EOF {
								f.Close()
								// we gud, tell daemon
								daemon.infeed_load <- msgid
							} else {
								log.Println(self.name, "error reading message", err)
							}
						}
					}
				}
				if success && err == nil {
					// all gud
					conn.PrintfLine("240 We got it, thnkxbai")
				} else {
					// failed posting
					if err != nil {
						log.Println(self.name, "failed nntp POST", err)
					}
					conn.PrintfLine("441 Posting Failed")
				}
			} else if cmd == "IHAVE" {
				// handle IHAVE command
				msgid := parts[1]
				if daemon.database.HasArticleLocal(msgid) || daemon.database.HasArticle(msgid) || daemon.database.ArticleBanned(msgid) {
					// we don't want it
					conn.PrintfLine("435 Article Not Wanted")
				} else {
					// gib we want
					conn.PrintfLine("335 Send it plz")
					hdr, err := conn.ReadMIMEHeader()
					if err == nil {
						// check the header
						var reason string
						reason, err = self.checkMIMEHeader(daemon, hdr)
						dr := conn.DotReader()
						if len(reason) > 0 {
							// discard, we do not want
							log.Println(self.name, "rejected", msgid, reason)
							_, err = io.Copy(ioutil.Discard, dr)
							// ignore this
							_ = daemon.database.BanArticle(msgid, reason)
							conn.PrintfLine("437 Rejected do not send again bro")
						} else {
							// check if we don't have the rootpost
							reference := hdr.Get("References")
							newsgroup := hdr.Get("Newsgroups")
							if reference != "" && ValidMessageID(reference) && !daemon.store.HasArticle(reference) && !daemon.database.IsExpired(reference) {
								log.Println(self.name, "got reply to", reference, "but we don't have it")
								daemon.ask_for_article <- ArticleEntry{reference, newsgroup}
							}
							f := daemon.store.CreateTempFile(msgid)
							if f == nil {
								log.Println(self.name, "discarding", msgid, "we are already loading it")
								// discard
								io.Copy(ioutil.Discard, dr)
							} else {
								// write header
								err = writeMIMEHeader(f, hdr)
								// write body
								_, err = io.Copy(f, dr)
								if err == nil || err == io.EOF {
									f.Close()
									// we gud, tell daemon
									daemon.infeed_load <- msgid
								} else {
									log.Println(self.name, "error reading message", err)
								}
							}
							conn.PrintfLine("235 We got it")
						}
					} else {
						// error here
						conn.PrintfLine("436 Transfer failed: " + err.Error())
					}
				}
			} else if cmd == "NEWSGROUPS" {
				// handle NEWSGROUPS
				conn.PrintfLine("231 List of newsgroups follow")
				dw := conn.DotWriter()
				// get a list of every newsgroup
				groups := daemon.database.GetAllNewsgroups()
				// for each group
				for _, group := range groups {
					// get low/high water mark
					lo, hi, err := daemon.database.GetLastAndFirstForGroup(group)
					if err == nil {
						// XXX: we ignore errors here :\
						_, _ = io.WriteString(dw, fmt.Sprintf("%s %d %d y\n", group, lo, hi))
					} else {
						log.Println(self.name, "could not get low/high water mark for", group, err)
					}
				}
				// flush dotwriter
				dw.Close()

			} else if cmd == "XOVER" {
				// handle XOVER
				if self.group == "" {
					conn.PrintfLine("412 No newsgroup selected")
				} else {
					// handle xover command
					// right now it's every article in group
					models, err := daemon.database.GetPostsInGroup(self.group)
					if err == nil {
						conn.PrintfLine("224 Overview information follows")
						dw := conn.DotWriter()
						for idx, model := range models {
							io.WriteString(dw, fmt.Sprintf("%.6d\t%s\t\"%s\" <%s@%s>\t%s\t%s\t%s\r\n", idx+1, model.Subject(), model.Name(), model.Name(), model.Frontend(), model.Date(), model.MessageID(), model.Reference()))
						}
						dw.Close()
					} else {
						log.Println(self.name, "error when getting posts in", self.group, err)
						conn.PrintfLine("500 error, %s", err.Error())
					}
				}
			} else if cmd == "GROUP" {
				// handle GROUP command
				group := parts[1]
				// check for newsgroup
				if daemon.database.HasNewsgroup(group) {
					// we have the group
					self.group = group
					// count posts
					number := daemon.database.CountPostsInGroup(group, 0)
					// get hi/low water marks
					low, hi, err := daemon.database.GetLastAndFirstForGroup(group)
					if err == nil {
						// we gud
						conn.PrintfLine("211 %d %d %d %s", number, low, hi, group)
					} else {
						// wtf error
						log.Println(self.name, "error in GROUP command", err)
						// still have to reply, send it bogus low/hi
						conn.PrintfLine("211 %d 0 1 %s", number, group)
					}
				} else {
					// no such group
					conn.PrintfLine("411 No Such Newsgroup")
				}
			} else {
				log.Println(self.name, "invalid command recv'd", cmd)
				conn.PrintfLine("500 Invalid command: %s", cmd)
			}
		}
	}
	return
}