commit fadb646042f16c4ec2da2e9280a37d4ea78f3d82
parent 29b5beffba37eda20b7ec27d77dd2a5bd699ab31
Author: Peter Kosyh <p.kosyh@gmail.com>
Date: Tue, 8 Sep 2020 10:10:50 +0300
attachments
Diffstat:
4 files changed, 100 insertions(+), 18 deletions(-)
diff --git a/ii-node/tpl/preview.tpl b/ii-node/tpl/preview.tpl
@@ -8,9 +8,7 @@
<span class="info">{{.From}}({{.Addr}}) — {{.To}}<br>{{.Date | fdate}}</span><br>
<div class="text">
<br>
-{{with .Text}}
-{{. | msg_format}}
-{{end}}
+{{. | msg_text}}
<br>
</div>
</div>
@@ -29,6 +27,7 @@
<input type="text" name="to" class="to" placeholder="{{.To}}" value="{{.To}}"><br>
<input type="text" name="subj" class="subj" placeholder="{{.Subj}}" value="{{.Subj}}"><br>
<input type="hidden" name="repto" value="{{ . | repto}}">
+<input type="hidden" name="id" value="{{ .MsgId }}">
<textarea type="text" name="msg" class="message" cols=60 row=16 placeholder="Hi, All!">{{.Text}}</textarea>
</td></tr>
diff --git a/ii-node/tpl/query.tpl b/ii-node/tpl/query.tpl
@@ -12,12 +12,11 @@
<span class="info">{{.From}}({{.Addr}}) — {{.To}}<br>{{.Date | fdate}}</span><br>
<div class="text">
<br>
-{{with .Text}}
-{{. | msg_format}}
-{{end}}
+{{. | msg_text}}
<br>
{{if $.User.Name}}
-<span class="reply"><a href="/{{.MsgId}}/reply">Reply</a></span>
+<span class="reply"><a href="/{{.MsgId}}/reply/new">Reply</a> :: </span>
+<span class="reply"><a href="/{{.MsgId}}/reply">Quote</a></span>
{{end}}
{{ if msg_access . $.User }}
:: <span class="reply"><a href="/{{.MsgId}}/edit">Edit</a></span>
diff --git a/ii-node/tpl/topic.tpl b/ii-node/tpl/topic.tpl
@@ -15,12 +15,11 @@
<span class="info"><a href="/from/{{.From}}">{{.From}}</a>({{.Addr}}) — {{.To}}<br>{{.Date | fdate}}</span><br>
<div class="text">
<br>
-{{with .Text}}
-{{. | msg_format}}
-{{end}}
+{{. | msg_text}}
<br>
{{if $.User.Name}}
-<span class="reply"><a href="/{{.MsgId}}/reply">Reply</a></span>
+<span class="reply"><a href="/{{.MsgId}}/reply/new">Reply</a> :: </span>
+<span class="reply"><a href="/{{.MsgId}}/reply">Quote</a></span>
{{end}}
{{ if msg_access . $.User }}
:: <span class="reply"><a href="/{{.MsgId}}/edit">Edit</a></span>
diff --git a/ii-node/web.go b/ii-node/web.go
@@ -139,6 +139,74 @@ func parse_ava(txt string) *image.RGBA {
return img
}
+var magicTable = map[string]string {
+ "\xff\xd8\xff": "image/jpeg",
+ "\x89PNG\r\n\x1a\n": "image/png",
+ "GIF87a": "image/gif",
+ "GIF89a": "image/gif",
+}
+
+func check_image(incipit []byte) string {
+ incipitStr := string(incipit)
+ for magic, mime := range magicTable {
+ if strings.HasPrefix(incipitStr, magic) {
+ return mime
+ }
+ }
+ return ""
+}
+
+func www_base64(ctx *WebContext, w http.ResponseWriter, r *http.Request) error {
+ id := ctx.BasePath
+ m := ctx.www.db.Get(id)
+ if m == nil {
+ return errors.New("No such message")
+ }
+ lines := strings.Split(msg_clean(m.Text), "\n")
+ start := false
+ b64 := ""
+ fname := ""
+ for _, v := range lines {
+ if !start && !strings.HasPrefix(v, "@base64:") {
+ continue
+ }
+ if start {
+ v = strings.Replace(v, " ", "", -1)
+ if !base64Regex.MatchString(v) {
+ break
+ }
+ b64 += v
+ continue
+ }
+ v = strings.TrimPrefix(v, "@base64:")
+ v = strings.Trim(v, " ")
+ fname = v
+ if fname == "" {
+ fname = "file"
+ }
+ start = true
+ }
+ if b64 == "" {
+ return nil
+ }
+ b, err := base64.RawStdEncoding.DecodeString(b64)
+ if err != nil {
+ if b, err = base64.StdEncoding.DecodeString(b64); err != nil {
+ if b, err = base64.URLEncoding.DecodeString(b64); err != nil {
+ return err
+ }
+ }
+ }
+ // w.Header().Set("Content-Type", "image/jpeg")
+ if check_image(b) != "" {
+ w.Header().Set("Content-Disposition", "inline")
+ } else {
+ w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", fname))
+ }
+ w.Header().Set("Content-Length", fmt.Sprintf("%d", len(b)))
+ _, err = w.Write(b)
+ return err
+}
func www_avatar(ctx *WebContext, w http.ResponseWriter, r *http.Request, user string) error {
if r.Method == "POST" { /* upload avatar */
if ctx.User.Name == "" || ctx.User.Name != user {
@@ -152,7 +220,7 @@ func www_avatar(ctx *WebContext, w http.ResponseWriter, r *http.Request, user st
ava := r.FormValue("avatar")
if len(ava) > 2048 {
ii.Error.Printf("Avatar is too big.")
- return errors.New("Avatar is too big")
+ return errors.New("Avatar is too big (>2048 bytes)")
}
if ava == "" {
ii.Trace.Printf("Delete avatar for %s", ctx.User.Name)
@@ -289,13 +357,14 @@ func www_query(ctx *WebContext, w http.ResponseWriter, r *http.Request, q ii.Que
<guid>%s</guid>
<link>%s/%s#%s</link>
<pubDate>%s</pubDate>
- <description>%s</description>
+ <description>%s\n\n%s</description>
<author>%s</author>
</item>
`,
str_esc(m.Subj), m.MsgId, ctx.www.Host, m.MsgId, m.MsgId,
time.Unix(m.Date, 0).Format("2006-01-02 15:04:05"),
- str_esc(msg_format(fmt.Sprintf("%s -> %s\n\n%s", m.From, m.To, m.Text))),
+ str_esc(fmt.Sprintf("%s -> %s\n\n", m.From, m.To)),
+ str_esc(msg_text(m)),
str_esc(m.From))
}
fmt.Fprintf(w,
@@ -564,6 +633,7 @@ var quoteRegex = regexp.MustCompile("^[^ >]*>")
var urlRegex = regexp.MustCompile(`(http|ftp|https)://[^ <>"]+`)
var url2Regex = regexp.MustCompile(`{{{href=[0-9]+}}}`)
var urlIIRegex = regexp.MustCompile(`ii://[a-zA-Z0-9]{20}`)
+var base64Regex = regexp.MustCompile(`^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)?$`)
func msg_clean(txt string) string {
txt = strings.Replace(txt, "\r", "", -1)
@@ -629,7 +699,11 @@ func msg_esc(l string) string {
return l
}
-func msg_format(txt string) string {
+func msg_text(m *ii.Msg) string {
+ if m == nil {
+ return ""
+ }
+ txt := m.Text
txt = msg_clean(txt)
f := ""
pre := false
@@ -675,10 +749,18 @@ func msg_format(txt string) string {
strings.HasPrefix(l, "//") || strings.HasPrefix(l, "#") ||
strings.HasPrefix(l, "+++ ") {
l = fmt.Sprintf("<span class=\"comment\">%s</span>", str_esc(l))
- } else if strings.HasPrefix(l, "spoiler:") {
+ } else if strings.HasPrefix(l, "@spoiler:") {
l = fmt.Sprintf("<span class=\"spoiler\">%s</span>", str_esc(ReverseStr(l)))
} else if quoteRegex.MatchString(l) {
l = fmt.Sprintf("<span class=\"quote\">%s</span>", str_esc(l))
+ } else if strings.HasPrefix(l, "@base64:") {
+ fname := strings.TrimPrefix(l, "@base64:")
+ fname = strings.Trim(fname, " ")
+ if fname == "" {
+ fname = "file"
+ }
+ f += fmt.Sprintf("<a class=\"attach\" href=\"%s/base64\">%s</a><br>\n", m.MsgId, str_esc(fname))
+ return f
} else {
l = msg_esc(l)
}
@@ -704,8 +786,8 @@ func WebInit(www *WWW) {
}
return template.HTML(time.Unix(date, 0).Format("2006-01-02 15:04:05"))
},
- "msg_format": func(s string) template.HTML {
- return template.HTML(msg_format(s))
+ "msg_text": func(m *ii.Msg) template.HTML {
+ return template.HTML(msg_text(m))
},
"repto": func(m ii.Msg) string {
r, _ := m.Tag("repto")
@@ -800,6 +882,9 @@ func _handleWWW(ctx *WebContext, w http.ResponseWriter, r *http.Request) error {
} else if args[1] == "blacklist" {
ctx.BasePath = args[0]
return www_blacklist(ctx, w, r)
+ } else if args[1] == "base64" {
+ ctx.BasePath = args[0]
+ return www_base64(ctx, w, r)
}
fmt.Sscanf(args[1], "%d", &page)
}