petit ménage
This commit is contained in:
@@ -1,9 +0,0 @@
|
||||
package main
|
||||
|
||||
type BlogEntry struct {
|
||||
Id string
|
||||
Title string
|
||||
Author string
|
||||
HTML string
|
||||
Text string
|
||||
}
|
@@ -1,5 +1,11 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type MailBoxConfiguration struct {
|
||||
Server string
|
||||
Port string
|
||||
@@ -14,3 +20,56 @@ type BlogConfiguration struct {
|
||||
MailBox MailBoxConfiguration
|
||||
WWWRoot string
|
||||
}
|
||||
|
||||
func (configuration *BlogConfiguration) Prompt() error {
|
||||
var err error
|
||||
configuration.Title, err = prompt("Blog Title", nil, "", configuration.Title, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
configuration.ShortName, err = prompt("Blog Short Name (only letters and numbers, no special signes)", nil, "blog", configuration.ShortName, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !regexp.MustCompile(`^[a-zA-Z0-9]+$`).MatchString(configuration.ShortName) {
|
||||
return fmt.Errorf("short same invalid")
|
||||
}
|
||||
|
||||
configuration.WWWRoot, err = prompt("Web Root directory", nil, fmt.Sprintf("/var/www/html/%s", configuration.ShortName), configuration.WWWRoot, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
configuration.MailBox.Server, err = prompt("IMAP Server Hostname or IP", nil, "", configuration.MailBox.Server, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
configuration.MailBox.Port, err = prompt("IMAP Server Port", nil, "993", configuration.MailBox.Port, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = strconv.ParseUint(configuration.MailBox.Port, 10, 16)
|
||||
if err != nil {
|
||||
return fmt.Errorf("imap server port invalid")
|
||||
}
|
||||
configuration.MailBox.User, err = prompt("IMAP User Login", nil, "", configuration.MailBox.User, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
configuration.MailBox.Password, err = prompt("IMAP User Password", nil, "", configuration.MailBox.Password, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
options := [...]string{"SSL/TLS", "StartTLS", "NoTLS"}
|
||||
configuration.MailBox.SSL, err = prompt("IMAP SSL/TLS", options[:], "SSL/TLS", configuration.MailBox.SSL, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
configuration.MailBox.InBox, err = prompt("IMAP INBOX", nil, "INBOX", configuration.MailBox.InBox, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
1
go.mod
1
go.mod
@@ -5,6 +5,7 @@ go 1.23.2
|
||||
require (
|
||||
github.com/emersion/go-imap/v2 v2.0.0-beta.5
|
||||
github.com/emersion/go-message v0.18.1
|
||||
golang.org/x/net v0.6.0
|
||||
)
|
||||
|
||||
require (
|
||||
|
1
go.sum
1
go.sum
@@ -12,6 +12,7 @@ golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.6.0 h1:L4ZwwTvKW9gr0ZMS1yrHD9GZhIuVjOBBnaKH+SPQK0Q=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
|
@@ -3,16 +3,22 @@ package main
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"io"
|
||||
"log"
|
||||
"mime"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
/*
|
||||
_ "golang.org/x/net/html"
|
||||
_ "golang.org/x/net/html/atom"
|
||||
*/
|
||||
"github.com/emersion/go-imap/v2"
|
||||
"github.com/emersion/go-imap/v2/imapclient"
|
||||
"github.com/emersion/go-message/charset"
|
||||
"github.com/emersion/go-message/mail"
|
||||
"golang.org/x/net/html"
|
||||
)
|
||||
|
||||
type MailBox struct {
|
||||
@@ -82,7 +88,7 @@ func (mb *MailBox) ListFolders() ([]string, error) {
|
||||
}
|
||||
return folders, nil
|
||||
}
|
||||
func (mb *MailBox) GetMessages() ([]BlogEntry, error) {
|
||||
func (mb *MailBox) GetMessages() ([]Post, error) {
|
||||
|
||||
inbox, err := mb.Client.Select(mb.InBox, nil).Wait()
|
||||
if err != nil {
|
||||
@@ -93,9 +99,9 @@ func (mb *MailBox) GetMessages() ([]BlogEntry, error) {
|
||||
if inbox.NumMessages <= 0 {
|
||||
return nil, fmt.Errorf("nomessages")
|
||||
}
|
||||
entries := make([]BlogEntry, 0)
|
||||
entries := make([]Post, 0)
|
||||
for i := uint32(1); i <= inbox.NumMessages; i++ {
|
||||
var entry BlogEntry
|
||||
var post Post
|
||||
seqSet := imap.SeqSetNum(i)
|
||||
bodySection := &imap.FetchItemBodySection{}
|
||||
fetchOptions := &imap.FetchOptions{
|
||||
@@ -106,14 +112,15 @@ func (mb *MailBox) GetMessages() ([]BlogEntry, error) {
|
||||
if err != nil {
|
||||
log.Fatal("Error fetching mails:", err)
|
||||
}
|
||||
entry.Title = strings.Trim(messages[0].Envelope.Subject, "\t ")
|
||||
if !strings.HasPrefix(strings.ToLower(entry.Title), "blog ") {
|
||||
post.Title = strings.Trim(messages[0].Envelope.Subject, "\t ")
|
||||
if !strings.HasPrefix(strings.ToLower(post.Title), "blog ") {
|
||||
continue
|
||||
}
|
||||
|
||||
entry.Id = messages[0].Envelope.MessageID
|
||||
entry.Title = entry.Title[5:]
|
||||
entry.Author = messages[0].Envelope.From[0].Name
|
||||
post.Id = messages[0].Envelope.MessageID
|
||||
post.Title = post.Title[5:] // remove first chars = blog+whitespace
|
||||
post.Author = messages[0].Envelope.From[0].Name
|
||||
post.Date = messages[0].Envelope.Date.String()
|
||||
|
||||
section := messages[0].FindBodySection(bodySection)
|
||||
ioReader := bytes.NewReader(section)
|
||||
@@ -148,9 +155,33 @@ func (mb *MailBox) GetMessages() ([]BlogEntry, error) {
|
||||
}
|
||||
switch mediaType {
|
||||
case "text/plain":
|
||||
entry.Text = string(body)
|
||||
post.Text = string(body)
|
||||
case "text/html":
|
||||
entry.HTML = string(body)
|
||||
post.HTML = ""
|
||||
nodes, err := html.Parse(strings.NewReader(string(body)))
|
||||
if err != nil {
|
||||
post.HTML = ""
|
||||
break
|
||||
}
|
||||
htmlNode, err := findHTMLNode(nodes)
|
||||
if err != nil {
|
||||
post.HTML = ""
|
||||
break
|
||||
}
|
||||
log.Println("Trying to generate html for", htmlNode.Data)
|
||||
var buf bytes.Buffer
|
||||
err = nil
|
||||
for child := htmlNode.FirstChild; child != nil; child = child.NextSibling {
|
||||
log.Println("html for", child.Data)
|
||||
if err = html.Render(&buf, child); err != nil {
|
||||
post.HTML = ""
|
||||
break
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
post.HTML = template.HTML(buf.String())
|
||||
}
|
||||
|
||||
default:
|
||||
log.Println("Content-Type:", part.Header.Get("Content-Type"))
|
||||
|
||||
@@ -160,7 +191,7 @@ func (mb *MailBox) GetMessages() ([]BlogEntry, error) {
|
||||
log.Printf("Unkown part type %+v", part)
|
||||
}
|
||||
}
|
||||
entries = append(entries, entry)
|
||||
posts = append(posts, post)
|
||||
}
|
||||
return entries, nil
|
||||
}
|
||||
@@ -168,3 +199,22 @@ func (mb *MailBox) GetMessages() ([]BlogEntry, error) {
|
||||
func (mb *MailBox) Close() {
|
||||
mb.Client.Close()
|
||||
}
|
||||
|
||||
func findHTMLNode(node *html.Node) (*html.Node, error) {
|
||||
if node.Type == html.ElementNode {
|
||||
log.Println(node.Data)
|
||||
}
|
||||
if node.Type == html.ElementNode && node.Data == "body" {
|
||||
log.Println("Found", node.Data)
|
||||
return node, nil
|
||||
}
|
||||
for e := node.FirstChild; e != nil; e = node.NextSibling {
|
||||
log.Println("Search in", e.Data)
|
||||
n, err := findHTMLNode(e)
|
||||
if err == nil {
|
||||
return n, nil
|
||||
}
|
||||
|
||||
}
|
||||
return nil, fmt.Errorf("notfound")
|
||||
}
|
107
mailblog.go
107
mailblog.go
@@ -1,18 +1,20 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"regexp"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func slash(w http.ResponseWriter, r *http.Request) {
|
||||
//go:embed html/index.tmpl
|
||||
var indexTemplate string
|
||||
|
||||
}
|
||||
//go:embed html/entry.tmpl
|
||||
var entryTemplate string
|
||||
|
||||
func main() {
|
||||
|
||||
@@ -38,56 +40,7 @@ func main() {
|
||||
if len(args) > 0 {
|
||||
switch args[0] {
|
||||
case "configure":
|
||||
|
||||
configuration.Title, err = prompt("Blog Title", nil, "", configuration.Title, false)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
configuration.ShortName, err = prompt("Blog Short Name (only letters and numbers, no special signes)", nil, "blog", configuration.ShortName, false)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if !regexp.MustCompile(`^[a-zA-Z0-9]+$`).MatchString(configuration.ShortName) {
|
||||
log.Fatal("Short Name invalid")
|
||||
}
|
||||
|
||||
configuration.WWWRoot, err = prompt("Web Root directory", nil, fmt.Sprintf("/var/www/html/%s", configuration.ShortName), configuration.WWWRoot, false)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
configuration.MailBox.Server, err = prompt("IMAP Server Hostname or IP", nil, "", configuration.MailBox.Server, false)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
configuration.MailBox.Port, err = prompt("IMAP Server Port", nil, "993", configuration.MailBox.Port, false)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
_, err = strconv.ParseUint(configuration.MailBox.Port, 10, 16)
|
||||
if err != nil {
|
||||
log.Fatal("IMAP Server Port invalid")
|
||||
}
|
||||
configuration.MailBox.User, err = prompt("IMAP User Login", nil, "", configuration.MailBox.User, false)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
configuration.MailBox.Password, err = prompt("IMAP User Password", nil, "", configuration.MailBox.Password, false)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
options := [...]string{"SSL/TLS", "StartTLS", "NoTLS"}
|
||||
configuration.MailBox.SSL, err = prompt("IMAP SSL/TLS", options[:], "SSL/TLS", configuration.MailBox.SSL, false)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
configuration.MailBox.InBox, err = prompt("IMAP INBOX", nil, "INBOX", configuration.MailBox.InBox, false)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
configuration.Prompt()
|
||||
file, err = os.Create(fmt.Sprintf("%s/.config/mailblog.json", home))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
@@ -108,16 +61,19 @@ func main() {
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer mb.Close()
|
||||
|
||||
folders, err := mb.ListFolders()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
log.Println(folders)
|
||||
msgs, err := mb.GetMessages()
|
||||
messages, err := mb.GetMessages()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
/*
|
||||
for _, m := range msgs {
|
||||
log.Println(m.Id)
|
||||
log.Println(m.Title)
|
||||
@@ -129,9 +85,46 @@ func main() {
|
||||
log.Println(m.Id)
|
||||
log.Println()
|
||||
}
|
||||
*/
|
||||
http.HandleFunc("GET /{$}",
|
||||
func(w http.ResponseWriter, r *http.Request) {
|
||||
tpl, err := template.New("index").Parse(indexTemplate)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
err = tpl.ExecuteTemplate(w, "index", messages)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
mb.Close()
|
||||
})
|
||||
http.HandleFunc("GET /post/{id}",
|
||||
func(w http.ResponseWriter, r *http.Request) {
|
||||
id := r.PathValue("id")
|
||||
log.Println("showing message:", id)
|
||||
for _, m := range messages {
|
||||
log.Println("Examining:", m.Id)
|
||||
if m.Id == id {
|
||||
tpl, err := template.New("entry").Parse(entryTemplate)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
err = tpl.ExecuteTemplate(w, "entry", m)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
w.WriteHeader(404)
|
||||
|
||||
})
|
||||
|
||||
http.HandleFunc("GET /favicon.ico",
|
||||
func(w http.ResponseWriter, r *http.Request) {
|
||||
log.Println("favicon.ico")
|
||||
w.WriteHeader(200)
|
||||
})
|
||||
|
||||
http.HandleFunc("/", slash)
|
||||
http.ListenAndServe("0.0.0.0:8080", nil)
|
||||
}
|
||||
|
Reference in New Issue
Block a user