petit ménage
This commit is contained in:
220
imap.go
Normal file
220
imap.go
Normal file
@@ -0,0 +1,220 @@
|
||||
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 {
|
||||
Server string
|
||||
Port uint16
|
||||
User string
|
||||
Password string
|
||||
SSL string
|
||||
InBox string
|
||||
Client *imapclient.Client
|
||||
}
|
||||
|
||||
func (mb *MailBox) Configure(conf *MailBoxConfiguration) error {
|
||||
|
||||
mb.Server = conf.Server
|
||||
port, err := strconv.ParseUint(conf.Port, 10, 16)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
mb.Port = uint16(port)
|
||||
mb.User = conf.User
|
||||
mb.Password = conf.Password
|
||||
mb.SSL = conf.SSL
|
||||
mb.InBox = conf.InBox
|
||||
return nil
|
||||
}
|
||||
func (mb *MailBox) ListMessages() (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func (mb *MailBox) Connect() error {
|
||||
options := &imapclient.Options{
|
||||
WordDecoder: &mime.WordDecoder{CharsetReader: charset.Reader},
|
||||
}
|
||||
var err error
|
||||
imapServer := fmt.Sprintf("%s:%d", mb.Server, mb.Port)
|
||||
switch mb.SSL {
|
||||
case "SSL/TLS":
|
||||
mb.Client, err = imapclient.DialTLS(imapServer, options)
|
||||
case "StartTLS":
|
||||
mb.Client, err = imapclient.DialStartTLS(imapServer, options)
|
||||
case "NoTLS":
|
||||
mb.Client, err = imapclient.DialInsecure(imapServer, options)
|
||||
default:
|
||||
return fmt.Errorf("bad tls configuration")
|
||||
}
|
||||
if err != nil {
|
||||
log.Println("Error connnecting to", imapServer, ":", err)
|
||||
return err
|
||||
}
|
||||
log.Println("Connected")
|
||||
err = mb.Client.Login(mb.User, mb.Password).Wait()
|
||||
if err != nil {
|
||||
log.Fatal("failed to login:", err)
|
||||
}
|
||||
log.Println("Logged in")
|
||||
return nil
|
||||
}
|
||||
func (mb *MailBox) ListFolders() ([]string, error) {
|
||||
folders := make([]string, 0)
|
||||
mailBoxes, err := mb.Client.List("", "%", nil).Collect()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, mbox := range mailBoxes {
|
||||
folders = append(folders, mbox.Mailbox)
|
||||
}
|
||||
return folders, nil
|
||||
}
|
||||
func (mb *MailBox) GetMessages() ([]Post, error) {
|
||||
|
||||
inbox, err := mb.Client.Select(mb.InBox, nil).Wait()
|
||||
if err != nil {
|
||||
log.Fatal("Error selecting mailbox:", mb.InBox, err)
|
||||
}
|
||||
log.Println("Inbox has", inbox.NumMessages, "messages")
|
||||
|
||||
if inbox.NumMessages <= 0 {
|
||||
return nil, fmt.Errorf("nomessages")
|
||||
}
|
||||
entries := make([]Post, 0)
|
||||
for i := uint32(1); i <= inbox.NumMessages; i++ {
|
||||
var post Post
|
||||
seqSet := imap.SeqSetNum(i)
|
||||
bodySection := &imap.FetchItemBodySection{}
|
||||
fetchOptions := &imap.FetchOptions{
|
||||
Envelope: true,
|
||||
BodySection: []*imap.FetchItemBodySection{bodySection},
|
||||
}
|
||||
messages, err := mb.Client.Fetch(seqSet, fetchOptions).Collect()
|
||||
if err != nil {
|
||||
log.Fatal("Error fetching mails:", err)
|
||||
}
|
||||
post.Title = strings.Trim(messages[0].Envelope.Subject, "\t ")
|
||||
if !strings.HasPrefix(strings.ToLower(post.Title), "blog ") {
|
||||
continue
|
||||
}
|
||||
|
||||
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)
|
||||
mailReader, err := mail.CreateReader(ioReader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for {
|
||||
part, err := mailReader.NextPart()
|
||||
if err == io.EOF {
|
||||
break
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch part.Header.(type) {
|
||||
case *mail.AttachmentHeader:
|
||||
/*
|
||||
filename, _ := header.Filename()
|
||||
|
||||
log.Println("------------FILE-----------")
|
||||
log.Println("Attachment:", filename)
|
||||
*/
|
||||
case *mail.InlineHeader:
|
||||
|
||||
body, _ := io.ReadAll(part.Body)
|
||||
contentTypeFull := strings.TrimPrefix(
|
||||
strings.ToLower(part.Header.Get("Content-Type")), "content-type")
|
||||
mediaType, _, err := mime.ParseMediaType(strings.TrimLeft(contentTypeFull, ": "))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch mediaType {
|
||||
case "text/plain":
|
||||
post.Text = string(body)
|
||||
case "text/html":
|
||||
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"))
|
||||
|
||||
}
|
||||
|
||||
default:
|
||||
log.Printf("Unkown part type %+v", part)
|
||||
}
|
||||
}
|
||||
posts = append(posts, post)
|
||||
}
|
||||
return entries, nil
|
||||
}
|
||||
|
||||
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")
|
||||
}
|
Reference in New Issue
Block a user