Beispiel #1
0
//Make makes and returns record from Recstr
func Make(line string) (*Record, error) {
	line = strings.TrimRight(line, "\r\n")
	buf := strings.Split(line, "<>")
	if len(buf) <= 2 || buf[0] == "" || buf[1] == "" || buf[2] == "" {
		err := errors.New("illegal format")
		return nil, err
	}
	idstr := buf[0] + "_" + buf[1]
	dec := util.FileDecode(buf[2])
	if dec == "" || !strings.HasPrefix(buf[2], "thread_") {
		err := errors.New("illegal format " + buf[2])
		//		log.Println(err)
		return nil, err
	}
	buf[2] = util.FileEncode("thread", dec)
	vr, err := NewIDstr(buf[2], idstr)
	if err != nil {
		return nil, err
	}
	if err := vr.Parse(line); err != nil {
		log.Println(err)
		return nil, err
	}
	return vr, nil
}
//appendRSS appends cache ca to rss with contents,url to records,stamp,attached file.
func (g *gatewayCGI) appendRSS(rsss *cgi.RSS, ca *thread.Cache) {
	now := time.Now().Unix()
	if ca.Stamp()+cfg.RSSRange < now {
		return
	}
	title := util.Escape(util.FileDecode(ca.Datfile))
	path := cfg.ThreadURL + "/" + util.StrEncode(title)
	recs := ca.LoadRecords(record.Alive)
	for _, r := range recs {
		if r.Stamp+cfg.RSSRange < now {
			continue
		}
		if err := r.Load(); err != nil {
			log.Println(err)
			continue
		}
		desc := cgi.RSSTextFormat(r.GetBodyValue("body", ""))
		content := g.rssHTMLFormat(r.GetBodyValue("body", ""), cfg.ThreadURL, title)
		if attach := r.GetBodyValue("attach", ""); attach != "" {
			suffix := r.GetBodyValue("suffix", "")
			if reg := regexp.MustCompile("^[0-9A-Za-z]+$"); !reg.MatchString(suffix) {
				suffix = cfg.SuffixTXT
			}
			content += fmt.Sprintf("\n    <p><a href=\"http://%s%s%s%s/%s/%d.%s\">%d.%s</a></p>",
				g.Host(), cfg.ThreadURL, "/", ca.Datfile, r.ID, r.Stamp, suffix, r.Stamp, suffix)
		}
		permpath := fmt.Sprintf("%s/%s", path[1:], r.ID[:8])
		rsss.Append(permpath, title, cgi.RSSTextFormat(r.GetBodyValue("name", "")), desc, content, user.GetStrings(ca.Datfile), r.Stamp, false)
	}
}
Beispiel #3
0
//MakeDat makes dat lines of 2ch from cache.
func MakeDat(ca *thread.Cache, board, host string) []string {
	recs := ca.LoadRecords(record.Alive)
	dat := make([]string, len(recs))
	table := mch.NewResTable(ca)

	i := 0
	for _, datfile := range recs.Keys() {
		rec := recs[datfile]
		err := rec.Load()
		if err != nil {
			log.Println(err)
			continue
		}
		name := rec.GetBodyValue("name", "")
		if name == "" {
			name = "名無しさん"
		}
		if rec.GetBodyValue("pubkey", "") != "" {
			name += "◆" + rec.GetBodyValue("pubkey", "")[:10]
		}
		comment := fmt.Sprintf("%s<>%s<>%s<>%s<>",
			name, rec.GetBodyValue("main", ""), util.Datestr2ch(rec.Stamp), MakeBody(rec, host, board, table))
		if i == 0 {
			comment += util.FileDecode(ca.Datfile)
		}
		dat[i] = comment
		i++
	}

	return dat
}
//makeSubject makes subject.txt(list of records title) from thread.Caches with tag=board.
func (m *mchCGI) makeSubject(board string) ([]string, int64) {
	loadFromNet := m.CheckGetCache()
	var subjects []string
	cl := m.makeSubjectCachelist(board)
	var lastStamp int64
	for _, c := range cl {
		if !loadFromNet && c.Len() == 0 {
			continue
		}
		if lastStamp < c.Stamp() {
			lastStamp = c.Stamp()
		}
		key, err := keylib.GetDatkey(c.Datfile)
		if err != nil {
			log.Println(err)
			continue
		}
		titleStr := util.FileDecode(c.Datfile)
		if titleStr == "" {
			continue
		}
		titleStr = strings.Trim(titleStr, "\r\n")
		subjects = append(subjects, fmt.Sprintf("%d.dat<>%s (%d)",
			key, titleStr, c.Len()))
	}
	return subjects, lastStamp
}
//subjectApp makes list of records title from thread.Caches whose tag is same as one stripped from url.
func (m *mchCGI) subjectApp(board string) {
	var boardEncoded, boardName string
	if board != "" {
		boardEncoded = util.StrDecode(board)
	}
	if boardEncoded != "" {
		boardName = util.FileDecode("dummy_" + boardEncoded)
	}
	subject, lastStamp := m.makeSubject(boardName)
	m.WR.Header().Set("Content-Type", "text/plain; charset=Shift_JIS")
	m.serveContent("a.txt", time.Unix(lastStamp, 0), strings.Join(subject, "\n")+"\n")
}
//postCommentApp checks posted data and replaces >> links to html links,
//and  saves it as record.
func (m *mchCGI) postCommentApp() {
	if m.Req.Method != http.MethodPost {
		m.WR.Header().Set("Content-Type", "text/plain")
		m.WR.WriteHeader(404)
		fmt.Fprintf(m.WR, "404 Not Found")
		return
	}
	info := m.getCommentData()
	info["host"] = m.Req.Host
	key := m.checkInfo(info)
	if key == "" {
		return
	}

	referer := m.getCP932("Referer")
	reg := regexp.MustCompile("/2ch_([^/]+)/")
	var tag string
	if ma := reg.FindStringSubmatch(referer); ma != nil && m.HasAuth() {
		tag = util.FileDecode("dummy_" + ma[1])
	}
	table := mch.NewResTable(thread.NewCache(key))
	reg = regexp.MustCompile(">>([1-9][0-9]*)")
	body := reg.ReplaceAllStringFunc(info["body"], func(str string) string {
		noStr := reg.FindStringSubmatch(str)[1]
		no, err := strconv.Atoi(noStr)
		if err != nil {
			log.Fatal(err)
		}
		return ">>" + table.Num2id[no]
	})

	name := info["name"]
	var passwd string
	if strings.ContainsRune(name, '#') {
		ary := strings.Split(name, "#")
		name = ary[0]
		passwd = ary[1]
	}
	if passwd != "" && !m.IsAdmin() {
		m.errorResp("自ノード以外で署名機能は使えません", info)
	}
	err := m.postComment(key, name, info["mail"], body, passwd, tag)
	if err == errSpamM {
		m.errorResp("スパムとみなされました", info)
	}
	m.WR.Header().Set("Content-Type", "text/html; charset=Shift_JIS")
	fmt.Fprintln(m.WR,
		util.ToSJIS(`<html lang="ja"><head><meta http-equiv="Content-Type" content="text/html"><title>書きこみました。</title></head><body>書きこみが終わりました。<br><br></body></html>`))
}
Beispiel #7
0
//checkCache checks cache ca has specified tag and datfile doesn't contains filterd string.
func checkCache(ca *thread.Cache, target, filter, tag string) (string, bool) {
	x := util.FileDecode(ca.Datfile)
	if x == "" {
		return "", false
	}
	if filter != "" && !strings.Contains(strings.ToLower(x), filter) {
		return "", false
	}
	if tag != "" {
		switch {
		case user.Has(ca.Datfile, strings.ToLower(tag)):
		case target == "recent" && suggest.HasTagstr(ca.Datfile, strings.ToLower(tag)):
		default:
			return "", false
		}
	}
	return x, true
}
//setCookie set cookie access=now time,tmpaccess=access var.
func (t *threadCGI) setCookie(ca *thread.Cache, access string) []*http.Cookie {
	const (
		saveCookie = 7 * 24 * time.Hour // Seconds
	)

	c := http.Cookie{}
	c.Expires = time.Now().Add(saveCookie)
	c.Path = cfg.ThreadURL + "/" + util.StrEncode(util.FileDecode(ca.Datfile))
	c.Name = "access"
	c.Value = strconv.FormatInt(time.Now().Unix(), 10)
	if access == "" {
		return []*http.Cookie{&c}
	}
	cc := http.Cookie{}
	cc.Name = "tmpaccess"
	cc.Value = access
	return []*http.Cookie{&c, &cc}
}
//printThreadIndex adds records in multiform and redirect to its thread page.
func (t *threadCGI) printThreadIndex() {
	err := t.Req.ParseMultipartForm(int64(cfg.RecordLimit) << 10)
	if err != nil {
		t.Print404(nil, "")
		return
	}
	if t.Req.FormValue("cmd") != "post" || !strings.HasPrefix(t.Req.FormValue("file"), "thread_") {
		t.Print404(nil, "")
		return
	}
	id := t.doPost()
	if id == "" {
		t.Print404(nil, "")
		return
	}
	datfile := t.Req.FormValue("file")
	title := util.StrEncode(util.FileDecode(datfile))
	t.Print302(cfg.ThreadURL + "/" + title + "#r" + id)
}
//renderCSV renders CSV including key string of caches in disk.
//key is specified in url query.
func (g *gatewayCGI) renderCSV(cl thread.Caches) {
	g.WR.Header().Set("Content-Type", "text/comma-separated-values;charset=UTF-8")
	p := strings.Split(g.Path(), "/")
	if len(p) < 3 {
		g.Print404(nil, "")
		return
	}
	cols := strings.Split(p[2], ",")
	cwr := csv.NewWriter(g.WR)
	for _, ca := range cl {
		title := util.FileDecode(ca.Datfile)
		p := cfg.ThreadURL + "/" + util.StrEncode(title)
		row := make([]string, len(cols))
		for i, c := range cols {
			row[i] = g.makeOneRow(c, ca, p, title)
		}
		err := cwr.Write(row)
		if err != nil {
			log.Println(err)
		}
	}
	cwr.Flush()
}
//printRecentRSS renders rss of caches which are written recently(are updated remotely).
//including title,tags,last-modified.
func printRecentRSS(w http.ResponseWriter, r *http.Request) {
	g, err := new(w, r)
	if err != nil {
		log.Println(err)
		return
	}
	rsss := cgi.NewRSS("UTF-8", "", fmt.Sprintf("%s - %s", g.M["recent"], g.M["logo"]),
		"http://"+g.Host(), "",
		"http://"+g.Host()+cfg.GatewayURL+"/"+"recent_rss", g.M["description"], xslURL)
	cl := thread.MakeRecentCachelist()
	for _, ca := range cl {
		title := util.Escape(util.FileDecode(ca.Datfile))
		tags := suggest.Get(ca.Datfile, nil)
		tags = append(tags, user.GetByThread(ca.Datfile)...)
		rsss.Append(cfg.ThreadURL[1:]+"/"+util.StrEncode(title),
			title, "", "", html.EscapeString(title), tags.GetTagstrSlice(),
			ca.RecentStamp(), false)
	}
	g.WR.Header().Set("Content-Type", "text/xml; charset=UTF-8")
	if rsss.Len() != 0 {
		g.WR.Header().Set("Last-Modified", g.RFC822Time(rsss.Feeds[0].Date))
	}
	rsss.MakeRSS1(g.WR)
}
Beispiel #12
0
//Gettitle returns title part if *_*.
//returns ca.datfile if not.
//used in templates
func (c *Cache) Gettitle() string {
	if strings.HasPrefix(c.Datfile, "thread_") {
		return util.FileDecode(c.Datfile)
	}
	return c.Datfile
}