tgmail/server/server.go

194 lines
4.0 KiB
Go

package server
import (
"bytes"
"encoding/json"
"git.ddd.rip/ptrcnull/telegram"
"io"
"io/ioutil"
"log"
"mime"
"mime/multipart"
"mime/quotedprintable"
"net"
"net/http"
"net/mail"
"strings"
)
const response = "uwu"
var Tg telegram.Client
const chatId = "456311800"
func Handle(conn net.Conn) {
c := wrapper{Conn: conn}
log.Println("Connection received from", c.RemoteAddr().String())
c.cmd(220, response+" ESMTP")
for {
msg, err := c.recv()
if err != nil {
log.Println(err)
c.Close()
return
}
cmd := strings.ToUpper(strings.Split(msg, " ")[0])
if cmd == "EHLO" {
c.cmd(250,
response,
"8BITMIME",
"SMTPUTF8",
"SIZE 104857600")
continue
}
if cmd == "DATA" {
c.cmd(354, response)
data, err := readContent(c)
if err != nil {
log.Println(err)
c.Close()
return
}
go handleMessage(data)
continue
}
if cmd == "QUIT" {
c.cmd(221, response)
c.Close()
break
}
c.cmd(250, response)
}
c.Close()
}
func readContent(c wrapper) (string, error) {
data := ""
for {
msg, err := c.recv()
if err != nil {
return "", err
}
if msg == "." {
break
}
data += msg + "\r\n"
}
c.cmd(250, response)
return data, nil
}
type Header interface {
Get(key string) string
}
func readTextBody(header Header, body io.Reader) (string, error) {
log.Println("reading text body")
var bodyBytes []byte
var err error
if header.Get("Content-Transfer-Encoding") == "quoted-printable" {
bodyBytes, err = ioutil.ReadAll(quotedprintable.NewReader(body))
} else {
bodyBytes, err = ioutil.ReadAll(body)
}
log.Println("ended reading text body")
return string(bodyBytes), err
}
func readMultipartBody(msg *mail.Message, boundary string) (string, error) {
r := multipart.NewReader(msg.Body, boundary)
body := ""
for {
part, err := r.NextPart()
if err == io.EOF {
break
}
if err != nil {
log.Println("error parsing multipart:", err)
break
}
mimetype, _, err := mime.ParseMediaType(part.Header.Get("Content-Type"))
if err != nil {
log.Println("error parsing multipart mimetype:", err)
continue
}
if mimetype == "text/plain" {
body, err = readTextBody(part.Header, part)
if err != nil {
log.Println("error reading text body from multipart:", err)
}
} else if mimetype == "text/html" && body == "" {
body, err = readTextBody(part.Header, part)
if err != nil {
log.Println("error reading html body from multipart:", err)
}
}
}
return body, nil
}
func handleMessage(data string) {
msg, err := mail.ReadMessage(bytes.NewReader([]byte(data)))
if err != nil {
log.Println(err)
return
}
res := "New mail!"
res += "\nFrom: " + msg.Header.Get("From")
res += "\nTo: " + msg.Header.Get("To")
mimetype, mimeparams, err := mime.ParseMediaType(msg.Header.Get("Content-Type"))
if err != nil {
log.Println(err)
return
}
log.Println("handling email with content-type", mimetype)
var body string
if strings.HasPrefix(mimetype, "text/") {
body, err = readTextBody(msg.Header, msg.Body)
} else if strings.HasPrefix(mimetype, "multipart/") {
body, err = readMultipartBody(msg, mimeparams["boundary"])
} else {
body = "check console for more info"
}
if err != nil {
log.Println("reading body failed:", err)
return
}
if len(body) > 1000 {
// curl 'https://bin.ddd.rip/documents' --compressed -H 'Content-Type: application/json; charset=utf-8' -H 'X-Requested-With: XMLHttpRequest' -H 'Origin: https://bin.ddd.rip' -H 'DNT: 1' -H 'Connection: keep-alive' -H 'Referer: https://bin.ddd.rip/' -H 'TE: Trailers' --data-raw dupa
log.Println("mail too long, uploading to hastebin")
res, err := http.Post("https://bin.ddd.rip/documents", "text/plain", bytes.NewReader([]byte(body)))
if err != nil {
body = "error uploading email: " + err.Error()
} else {
var response map[string]string
json.NewDecoder(res.Body).Decode(&response)
body = "https://bin.ddd.rip/" + response["key"]
}
}
res += "\n\n" + body
log.Println("sending telegram message")
_, err = Tg.SendMessage(chatId, res)
if err != nil {
log.Println(err)
}
}