diff --git a/contrib/backends/srndv2/src/srnd/database.go b/contrib/backends/srndv2/src/srnd/database.go
index 0cfb6de..0fa10f8 100644
--- a/contrib/backends/srndv2/src/srnd/database.go
+++ b/contrib/backends/srndv2/src/srnd/database.go
@@ -47,13 +47,12 @@ func (self PostEntry) Count() int64 {
return self[1]
}
+type PostEntryList []PostEntry
+
+
// stats about newsgroup postings
type NewsgroupStats struct {
- Posted []PostEntry
- Delted []PostEntry
- Hits []PostEntry
- Start time.Time
- End time.Time
+ PPD int64
Name string
}
@@ -70,6 +69,8 @@ type NewsgroupListEntry [3]string
type NewsgroupList []NewsgroupListEntry
+
+
type Database interface {
Close()
CreateTables()
@@ -81,7 +82,7 @@ type Database interface {
GetAllArticlesInGroup(group string, send chan ArticleEntry)
CountAllArticlesInGroup(group string) (int64, error)
GetAllArticles() []ArticleEntry
-
+
SetConnectionLifetime(seconds int)
SetMaxOpenConns(n int)
SetMaxIdleConns(n int)
@@ -124,6 +125,9 @@ type Database interface {
// if N <= 0 then count all we have now
CountPostsInGroup(group string, time_frame int64) int64
+ // get the stats for the overview page
+ GetNewsgroupStats() ([]NewsgroupStats, error)
+
// get all replies to a thread
// if last > 0 then get that many of the last replies
// start at reply number start
diff --git a/contrib/backends/srndv2/src/srnd/model.go b/contrib/backends/srndv2/src/srnd/model.go
index a177f85..d4967e0 100644
--- a/contrib/backends/srndv2/src/srnd/model.go
+++ b/contrib/backends/srndv2/src/srnd/model.go
@@ -224,6 +224,8 @@ type boardPageRow struct {
Hour int64
Day int64
All int64
+ Hi int64
+ Lo int64
}
type boardPageRows []boardPageRow
@@ -242,6 +244,7 @@ func (self boardPageRows) Swap(i, j int) {
self[i], self[j] = self[j], self[i]
}
+
type postsGraphRow struct {
day time.Time
Num int64
diff --git a/contrib/backends/srndv2/src/srnd/nntp.go b/contrib/backends/srndv2/src/srnd/nntp.go
index 61f2e55..0d9327d 100644
--- a/contrib/backends/srndv2/src/srnd/nntp.go
+++ b/contrib/backends/srndv2/src/srnd/nntp.go
@@ -776,10 +776,13 @@ func (self *nntpConnection) handleLine(daemon *NNTPDaemon, code int, line string
// wtf?!
conn.PrintfLine("503 idkwtf happened: %s", err.Error())
}
+ } else {
+ // we dont got it (by msgid)
+ conn.PrintfLine("430 %s", msgid)
}
} else {
- // we dont got it
- conn.PrintfLine("430 %s", msgid)
+ // we dont got it (by num)
+ conn.PrintfLine("423 %s", msgid)
}
} else if cmd == "IHAVE" {
if !self.authenticated {
@@ -1175,7 +1178,7 @@ func (self *nntpConnection) handleLine(daemon *NNTPDaemon, code int, line string
dw := conn.DotWriter()
for _, entry := range list {
if ValidNewsgroup(entry[0]) {
- io.WriteString(dw, fmt.Sprintf("%s %s %s y\r\n", entry[0], entry[1], entry[2]))
+ io.WriteString(dw, fmt.Sprintf("%s %s %s y\r\n", entry[0], entry[2], entry[1]))
}
}
dw.Close()
diff --git a/contrib/backends/srndv2/src/srnd/null_cache.go b/contrib/backends/srndv2/src/srnd/null_cache.go
index b5bbcec..6af4724 100644
--- a/contrib/backends/srndv2/src/srnd/null_cache.go
+++ b/contrib/backends/srndv2/src/srnd/null_cache.go
@@ -97,6 +97,12 @@ func (self *nullHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
return
}
+ // board list page
+ if strings.ToLower(path) == "/b/" {
+ template.genBoardList(self.prefix, self.name, w, self.database, i18n)
+ return
+ }
+
if strings.HasPrefix(path, "/b/") {
// board handler
parts := strings.Split(path[3:], "/")
diff --git a/contrib/backends/srndv2/src/srnd/postgres.go b/contrib/backends/srndv2/src/srnd/postgres.go
index e03583e..141b535 100644
--- a/contrib/backends/srndv2/src/srnd/postgres.go
+++ b/contrib/backends/srndv2/src/srnd/postgres.go
@@ -152,9 +152,11 @@ const GetCitesByPostHashLike = "GetCitesByPostHashLike"
const GetYearlyPostHistory = "GetYearlyPostHistory"
const GetNewsgroupList = "GetNewsgroupList"
const CountUkko = "CountUkko"
+const GetNewsgroupStats = "GetNewsgroupStats"
func (self *PostgresDatabase) prepareStatements() {
self.stmt = map[string]string{
+ GetNewsgroupStats: "SELECT COUNT(message_id), newsgroup FROM articleposts WHERE time_posted > (EXTRACT(epoch FROM NOW()) - (24*3600)) GROUP BY newsgroup",
NewsgroupBanned: "SELECT 1 FROM BannedGroups WHERE newsgroup = $1",
ArticleBanned: "SELECT 1 FROM BannedArticles WHERE message_id = $1",
GetAllNewsgroups: "SELECT name FROM Newsgroups WHERE name NOT IN ( SELECT newsgroup FROM BannedGroups )",
@@ -2051,6 +2053,21 @@ func (self *PostgresDatabase) GetUkkoPageCount(perpage int) (count int64, err er
return
}
+func (self *PostgresDatabase) GetNewsgroupStats() (stats []NewsgroupStats, err error) {
+ var rows *sql.Rows
+ rows, err = self.conn.Query(self.stmt[GetNewsgroupStats])
+ if err == nil {
+ for rows.Next() {
+ var s NewsgroupStats
+ rows.Scan(&s.PPD, &s.Name)
+ stats = append(stats, s)
+ }
+ rows.Close()
+ }
+ return
+}
+
+
func (self *PostgresDatabase) FindHeaders(group, headername string, lo, hi int64) (hdr ArticleHeaders, err error) {
hdr = make(ArticleHeaders)
q := "SELECT header_value FROM nntpheaders WHERE header_name = $1 AND header_article_message_id IN ( SELECT message_id FROM articleposts WHERE newsgroup = $2 )"
diff --git a/contrib/backends/srndv2/src/srnd/templates_impl.go b/contrib/backends/srndv2/src/srnd/templates_impl.go
index ff9153f..7541933 100644
--- a/contrib/backends/srndv2/src/srnd/templates_impl.go
+++ b/contrib/backends/srndv2/src/srnd/templates_impl.go
@@ -475,36 +475,29 @@ func (self *templateEngine) genGraphs(prefix string, wr io.Writer, db Database,
func (self *templateEngine) genBoardList(prefix, name string, wr io.Writer, db Database, i18n *I18N) {
// the graph for the front page
- var frontpage_graph boardPageRows
+ var graph boardPageRows
- // for each group
- groups := db.GetAllNewsgroups()
- for _, group := range groups {
- // exclude banned
- banned, _ := db.NewsgroupBanned(group)
- if banned {
- continue
- }
- // posts this hour
- hour := db.CountPostsInGroup(group, 3600)
- // posts today
- day := db.CountPostsInGroup(group, 86400)
- // posts total
- all := db.CountPostsInGroup(group, 0)
- frontpage_graph = append(frontpage_graph, boardPageRow{
- All: all,
- Day: day,
- Hour: hour,
- Board: group,
+ stats, err := db.GetNewsgroupStats()
+ if err != nil {
+ log.Println("error getting board list", err)
+ io.WriteString(wr, err.Error())
+ return
+ }
+
+ for idx := range stats {
+ graph = append(graph, boardPageRow{
+ Board: stats[idx].Name,
+ Day: stats[idx].PPD,
})
}
+
param := map[string]interface{}{
"prefix": prefix,
"frontend": name,
}
- sort.Sort(frontpage_graph)
- param["graph"] = frontpage_graph
- _, err := io.WriteString(wr, self.renderTemplate("boardlist", param, i18n))
+ sort.Sort(graph)
+ param["graph"] = graph
+ _, err = io.WriteString(wr, self.renderTemplate("boardlist", param, i18n))
if err != nil {
log.Println("error writing board list page", err)
}
diff --git a/contrib/backends/srndv2/src/srnd/util.go b/contrib/backends/srndv2/src/srnd/util.go
index 21023f9..efa9428 100644
--- a/contrib/backends/srndv2/src/srnd/util.go
+++ b/contrib/backends/srndv2/src/srnd/util.go
@@ -60,10 +60,34 @@ func EnsureDir(dirname string) {
}
}
-var exp_valid_message_id = regexp.MustCompilePOSIX(`^<[a-zA-Z0-9$.]{2,128}@[a-zA-Z0-9\-.]{2,63}>$`)
+// printableASCII tells whether string is made of US-ASCII printable characters
+// except of specified one.
+func printableASCII(s string, e byte) bool {
+ for i := 0; i < len(s); i++ {
+ c := s[i]
+ // NOTE: doesn't include space, which is neither printable nor control
+ if c <= 32 || c >= 127 || c == e {
+ return false
+ }
+ }
+ return true
+}
func ValidMessageID(id string) bool {
- return exp_valid_message_id.MatchString(id)
+ /*
+ {RFC 3977}
+ o A message-id MUST begin with "<", end with ">", and MUST NOT
+ contain the latter except at the end.
+ o A message-id MUST be between 3 and 250 octets in length.
+ o A message-id MUST NOT contain octets other than printable US-ASCII
+ characters.
+
+ additionally, we check path characters, they may be dangerous
+ */
+ return len(id) >= 3 && len(id) <= 250 &&
+ id[0] == '<' && id[len(id)-1] == '>' &&
+ printableASCII(id[1:len(id)-1], '>') &&
+ strings.IndexAny(id[1:len(id)-1], "/\\") < 0
}
// message id hash
@@ -482,7 +506,7 @@ func IPNet2MinMax(inet *net.IPNet) (min, max net.IP) {
maskb := []byte(inet.Mask)
maxb := make([]byte, len(netb))
- for i, _ := range maxb {
+ for i := range maxb {
maxb[i] = netb[i] | (^maskb[i])
}
min = net.IP(netb)
diff --git a/contrib/templates/placebo/boardlist.mustache b/contrib/templates/placebo/boardlist.mustache
index 5767176..6e22135 100644
--- a/contrib/templates/placebo/boardlist.mustache
+++ b/contrib/templates/placebo/boardlist.mustache
@@ -22,7 +22,7 @@
-
+
- | posts today | post rate | board |
+ | posts today | board |
{{#graph}}
- | {{Day}} | {{Hour}} PPH | {{Board}} |
+ | {{Day}} | {{Board}} |
{{/graph}}
|
diff --git a/contrib/templates/placebo/frontpage.mustache b/contrib/templates/placebo/frontpage.mustache
index 7036869..7a7be9f 100644
--- a/contrib/templates/placebo/frontpage.mustache
+++ b/contrib/templates/placebo/frontpage.mustache
@@ -26,9 +26,11 @@
- 
Enter
- Board List
+
+ Board List
+ Firehose
FAQ
+