准备开发单页列表

pull/23/head
630892807@qq.com 4 years ago
parent e804febfdc
commit 2864692c7d

@ -1,341 +0,0 @@
package controller
import (
"encoding/json"
"github.com/gin-gonic/gin"
"github.com/gorilla/websocket"
"github.com/taoshihan1991/imaptool/models"
"github.com/taoshihan1991/imaptool/ws"
"log"
"sort"
"time"
)
type vistor struct {
conn *websocket.Conn
name string
id string
avator string
to_id string
}
type Message struct {
conn *websocket.Conn
c *gin.Context
content []byte
messageType int
}
var clientList = make(map[string]*vistor)
var kefuList = make(map[string][]*websocket.Conn)
var message = make(chan *Message)
type TypeMessage struct {
Type interface{} `json:"type"`
Data interface{} `json:"data"`
}
type ClientMessage struct {
Name string `json:"name"`
Avator string `json:"avator"`
Id string `json:"id"`
VisitorId string `json:"visitor_id"`
Group string `json:"group"`
Time string `json:"time"`
ToId string `json:"to_id"`
Content string `json:"content"`
City string `json:"city"`
ClientIp string `json:"client_ip"`
Refer string `json:"refer"`
}
//定时检测客户端是否在线
func init() {
upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
}
//go UpdateVisitorStatusCron()
//go singleBroadcaster()
//go sendPingOnlineUsers()
//sendPingToClient()
}
func NewChatServer(c *gin.Context) {
conn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
if err != nil {
log.Print("upgrade:", err)
return
}
for {
//接受消息
var receive []byte
var recevString string
messageType, receive, err := conn.ReadMessage()
if err != nil {
for uid, visitor := range clientList {
if visitor.conn == conn {
log.Println("删除用户", uid)
delete(clientList, uid)
models.UpdateVisitorStatus(uid, 0)
userInfo := make(map[string]string)
userInfo["uid"] = uid
userInfo["name"] = visitor.name
msg := TypeMessage{
Type: "userOffline",
Data: userInfo,
}
str, _ := json.Marshal(msg)
kefuConns := kefuList[visitor.to_id]
if kefuConns != nil {
for _, kefuConn := range kefuConns {
kefuConn.WriteMessage(websocket.TextMessage, str)
}
}
//新版
mKefuConns := ws.KefuList[visitor.to_id]
if mKefuConns != nil {
for _, kefu := range mKefuConns {
kefu.Conn.WriteMessage(websocket.TextMessage, str)
}
}
sendPingOnlineUsers()
}
}
log.Println(err)
return
}
recevString = string(receive)
log.Println("客户端:", recevString)
message <- &Message{
conn: conn,
content: receive,
c: c,
messageType: messageType,
}
}
}
//发送给客户客服上线
func SendKefuOnline(clientMsg ClientMessage, conn *websocket.Conn) {
sendMsg := TypeMessage{
Type: "kfOnline",
Data: ClientMessage{
Name: clientMsg.Name,
Avator: clientMsg.Avator,
Id: clientMsg.Id,
Group: clientMsg.Group,
Time: time.Now().Format("2006-01-02 15:04:05"),
Content: "客服上线",
},
}
jsonStrByte, _ := json.Marshal(sendMsg)
conn.WriteMessage(websocket.TextMessage, jsonStrByte)
}
//发送通知
func SendNotice(msg string, conn *websocket.Conn) {
sendMsg := TypeMessage{
Type: "notice",
Data: msg,
}
jsonStrByte, _ := json.Marshal(sendMsg)
conn.WriteMessage(websocket.TextMessage, jsonStrByte)
}
//定时给客户端发送消息判断客户端是否在线
func sendPingToClient() {
msg := TypeMessage{
Type: "ping",
}
go func() {
for {
str, _ := json.Marshal(msg)
for uid, user := range clientList {
err := user.conn.WriteMessage(websocket.TextMessage, str)
if err != nil {
delete(clientList, uid)
models.UpdateVisitorStatus(uid, 0)
}
}
for kefuId, kfConns := range kefuList {
var newkfConns = make([]*websocket.Conn, 0)
for _, kefuConn := range kfConns {
if kefuConn == nil {
continue
}
err := kefuConn.WriteMessage(websocket.TextMessage, str)
if err == nil {
newkfConns = append(newkfConns, kefuConn)
}
}
if newkfConns == nil {
delete(kefuList, kefuId)
} else {
kefuList[kefuId] = newkfConns
}
}
time.Sleep(15 * time.Second)
}
}()
}
//定时给更新数据库状态
func UpdateVisitorStatusCron() {
for {
visitors := models.FindVisitorsOnline()
for _, visitor := range visitors {
if visitor.VisitorId == "" {
continue
}
_, ok := clientList[visitor.VisitorId]
if !ok {
models.UpdateVisitorStatus(visitor.VisitorId, 0)
}
}
time.Sleep(60 * time.Second)
}
}
//定时推送当前在线用户
func sendPingOnlineUsers() {
var visitorIds []string
for visitorId, _ := range clientList {
visitorIds = append(visitorIds, visitorId)
}
sort.Strings(visitorIds)
for kefuId, kfConns := range kefuList {
result := make([]map[string]string, 0)
for _, visitorId := range visitorIds {
user := clientList[visitorId]
userInfo := make(map[string]string)
userInfo["uid"] = user.id
userInfo["username"] = user.name
userInfo["avator"] = user.avator
if user.to_id == kefuId {
result = append(result, userInfo)
}
}
msg := TypeMessage{
Type: "allUsers",
Data: result,
}
str, _ := json.Marshal(msg)
var newkfConns = make([]*websocket.Conn, 0)
for _, kefuConn := range kfConns {
err := kefuConn.WriteMessage(websocket.TextMessage, str)
if err == nil {
newkfConns = append(newkfConns, kefuConn)
}
}
if len(newkfConns) == 0 {
delete(kefuList, kefuId)
} else {
kefuList[kefuId] = newkfConns
}
}
}
//后端广播发送消息
//func singleBroadcaster() {
// for {
// message := <-message
// //log.Println("debug:",message)
//
// var typeMsg TypeMessage
// var clientMsg ClientMessage
// json.Unmarshal(message.content, &typeMsg)
// conn := message.conn
// if typeMsg.Type == nil || typeMsg.Data == nil {
// continue
// }
// msgType := typeMsg.Type.(string)
// msgData, _ := json.Marshal(typeMsg.Data)
// switch msgType {
// //用户上线
// case "userInit":
// json.Unmarshal(msgData, &clientMsg)
// vistorInfo := models.FindVisitorByVistorId(clientMsg.VisitorId)
// if vistorInfo.VisitorId == "" {
// SendNotice("访客数据不存在", conn)
// continue
// }
// //用户id对应的连接
// user := &vistor{
// conn: conn,
// name: clientMsg.Name,
// avator: clientMsg.Avator,
// id: clientMsg.VisitorId,
// to_id: clientMsg.ToId,
// }
// clientList[clientMsg.VisitorId] = user
// //插入数据表
// models.UpdateVisitor(clientMsg.VisitorId, 1, clientMsg.ClientIp, message.c.ClientIP(), clientMsg.Refer, "")
// //models.CreateVisitor(clientMsg.Name,clientMsg.Avator,message.c.ClientIP(),clientMsg.ToId,clientMsg.VisitorId,clientMsg.Refer,clientMsg.City,clientMsg.ClientIp)
// userInfo := make(map[string]string)
// userInfo["uid"] = user.id
// userInfo["username"] = user.name
// userInfo["avator"] = user.avator
// msg := TypeMessage{
// Type: "userOnline",
// Data: userInfo,
// }
// str, _ := json.Marshal(msg)
//
// //新版
// mKefuConns := ws.KefuList[user.to_id]
// if mKefuConns != nil {
// for _, kefu := range mKefuConns {
// kefu.Conn.WriteMessage(websocket.TextMessage, str)
// }
// }
//
// //兼容旧版
// kefuConns := kefuList[user.to_id]
// if kefuConns != nil {
// for k, kefuConn := range kefuConns {
// log.Println(k, "xxxxxxxx")
// kefuConn.WriteMessage(websocket.TextMessage, str)
// }
// }
//
// //客户上线发微信通知
// go SendServerJiang(userInfo["username"])
// sendPingOnlineUsers()
// //客服上线
// case "kfOnline":
// json.Unmarshal(msgData, &clientMsg)
// //客服id对应的连接
// var newKefuConns = []*websocket.Conn{conn}
// kefuConns := kefuList[clientMsg.Id]
// if kefuConns != nil {
// newKefuConns = append(newKefuConns, kefuConns...)
// }
// log.Println(newKefuConns)
// kefuList[clientMsg.Id] = newKefuConns
// //发送给客户
// if len(clientList) == 0 {
// continue
// }
// sendPingOnlineUsers()
// //客服接手
// case "kfConnect":
// json.Unmarshal(msgData, &clientMsg)
// visitor, ok := clientList[clientMsg.ToId]
// if visitor == nil || !ok {
// continue
// }
// SendKefuOnline(clientMsg, visitor.conn)
// //心跳
// case "ping":
// msg := TypeMessage{
// Type: "pong",
// }
// str, _ := json.Marshal(msg)
// conn.WriteMessage(websocket.TextMessage, str)
// }
//
// }
//}

@ -1,262 +0,0 @@
package controller
import (
"encoding/json"
"github.com/gin-gonic/gin"
"github.com/taoshihan1991/imaptool/config"
"github.com/taoshihan1991/imaptool/tmpl"
"github.com/taoshihan1991/imaptool/tools"
"io/ioutil"
"net/http"
"strconv"
"sync"
)
const PageSize = 20
func GetFolders(c *gin.Context) {
fid := c.Query("fid")
currentPage, _ := strconv.Atoi(c.Query("page"))
if fid == "" {
fid = "INBOX"
}
if currentPage == 0 {
currentPage = 1
}
mailServer := config.CreateMailServer()
var wg sync.WaitGroup
wg.Add(2)
result := make(map[string]interface{})
go func() {
defer wg.Done()
folders := tools.GetFolders(mailServer.Server, mailServer.Email, mailServer.Password, fid)
result["folders"] = folders
result["total"] = folders[fid]
}()
go func() {
defer wg.Done()
mails := tools.GetFolderMail(mailServer.Server, mailServer.Email, mailServer.Password, fid, currentPage, PageSize)
result["mails"] = mails
}()
wg.Wait()
result["pagesize"] = PageSize
result["fid"] = fid
c.JSON(200, gin.H{
"code": 200,
"msg": "ok",
"result": result,
})
}
func GetFolderList(c *gin.Context) {
fid := c.Query("fid")
if fid == "" {
fid = "INBOX"
}
mailServer := config.CreateMailServer()
result := make(map[string]interface{})
folders := tools.GetFolders(mailServer.Server, mailServer.Email, mailServer.Password, fid)
result["folders"] = folders
result["total"] = folders[fid]
result["fid"] = fid
c.JSON(200, gin.H{
"code": 200,
"msg": "ok",
"result": result,
})
}
//输出列表
func ActionFolder(w http.ResponseWriter, r *http.Request) {
fid := tools.GetUrlArg(r, "fid")
currentPage, _ := strconv.Atoi(tools.GetUrlArg(r, "page"))
if fid == "" {
fid = "INBOX"
}
if currentPage == 0 {
currentPage = 1
}
render := tmpl.NewFolderHtml(w)
render.CurrentPage = currentPage
render.Fid = fid
render.Display("list", render)
}
//写信界面
func ActionWrite(w http.ResponseWriter, r *http.Request) {
render := tmpl.NewRender(w)
render.SetLeft("mail_left")
render.Display("write", nil)
}
//读信界面
func ActionDetail(w http.ResponseWriter, r *http.Request) {
fid := tools.GetUrlArg(r, "fid")
id, _ := strconv.Atoi(tools.GetUrlArg(r, "id"))
render := tmpl.NewDetailHtml(w)
render.SetLeft("mail_left")
render.Fid = fid
render.Id = uint32(id)
render.Display("mail_detail", render)
}
//获取邮件夹接口
func FolderDir(w http.ResponseWriter, r *http.Request) {
fid := tools.GetUrlArg(r, "fid")
if fid == "" {
fid = "INBOX"
}
mailServer := tools.GetMailServerFromCookie(r)
w.Header().Set("content-type", "text/json;charset=utf-8;")
if mailServer == nil {
msg, _ := json.Marshal(tools.JsonResult{Code: 400, Msg: "验证失败"})
w.Write(msg)
return
}
result := make(map[string]interface{})
folders := tools.GetFolders(mailServer.Server, mailServer.Email, mailServer.Password, fid)
result["folders"] = folders
result["total"] = folders[fid]
result["fid"] = fid
msg, _ := json.Marshal(tools.JsonListResult{
JsonResult: tools.JsonResult{Code: 200, Msg: "获取成功"},
Result: result,
})
w.Write(msg)
}
//邮件夹接口
func FoldersList(w http.ResponseWriter, r *http.Request) {
fid := tools.GetUrlArg(r, "fid")
currentPage, _ := strconv.Atoi(tools.GetUrlArg(r, "page"))
if fid == "" {
fid = "INBOX"
}
if currentPage == 0 {
currentPage = 1
}
mailServer := tools.GetMailServerFromCookie(r)
w.Header().Set("content-type", "text/json;charset=utf-8;")
if mailServer == nil {
msg, _ := json.Marshal(tools.JsonResult{Code: 400, Msg: "验证失败"})
w.Write(msg)
return
}
var wg sync.WaitGroup
wg.Add(2)
result := make(map[string]interface{})
go func() {
defer wg.Done()
folders := tools.GetFolders(mailServer.Server, mailServer.Email, mailServer.Password, fid)
result["folders"] = folders
result["total"] = folders[fid]
}()
go func() {
defer wg.Done()
mails := tools.GetFolderMail(mailServer.Server, mailServer.Email, mailServer.Password, fid, currentPage, PageSize)
result["mails"] = mails
}()
wg.Wait()
result["pagesize"] = PageSize
result["fid"] = fid
msg, _ := json.Marshal(tools.JsonListResult{
JsonResult: tools.JsonResult{Code: 200, Msg: "获取成功"},
Result: result,
})
w.Write(msg)
}
//邮件接口
func FolderMail(w http.ResponseWriter, r *http.Request) {
fid := tools.GetUrlArg(r, "fid")
id, _ := strconv.Atoi(tools.GetUrlArg(r, "id"))
mailServer := tools.GetMailServerFromCookie(r)
w.Header().Set("content-type", "text/json;charset=utf-8;")
if mailServer == nil {
msg, _ := json.Marshal(tools.JsonResult{Code: 400, Msg: "验证失败"})
w.Write(msg)
return
}
var wg sync.WaitGroup
result := make(map[string]interface{})
wg.Add(2)
go func() {
defer wg.Done()
folders := tools.GetFolders(mailServer.Server, mailServer.Email, mailServer.Password, fid)
result["folders"] = folders
result["total"] = folders[fid]
}()
go func() {
defer wg.Done()
mail := tools.GetMessage(mailServer.Server, mailServer.Email, mailServer.Password, fid, uint32(id))
result["from"] = mail.From
result["to"] = mail.To
result["subject"] = mail.Subject
result["date"] = mail.Date
result["html"] = mail.Body
}()
wg.Wait()
result["fid"] = fid
msg, _ := json.Marshal(tools.JsonListResult{
JsonResult: tools.JsonResult{Code: 200, Msg: "获取成功"},
Result: result,
})
w.Write(msg)
}
//发送邮件接口
func FolderSend(w http.ResponseWriter, r *http.Request) {
w.Header().Set("content-type", "text/json;charset=utf-8;")
mailServer := tools.GetMailServerFromCookie(r)
if mailServer == nil {
msg, _ := json.Marshal(tools.JsonResult{Code: 400, Msg: "验证失败"})
w.Write(msg)
return
}
bodyBytes, err := ioutil.ReadAll(r.Body)
if err != nil {
msg, _ := json.Marshal(tools.JsonResult{Code: 400, Msg: "操作失败," + err.Error()})
w.Write(msg)
return
}
var sendData tools.SmtpBody
err = json.Unmarshal(bodyBytes, &sendData)
if err != nil {
msg, _ := json.Marshal(tools.JsonResult{Code: 400, Msg: "操作失败," + err.Error()})
w.Write(msg)
return
}
smtpServer := sendData.Smtp
smtpFrom := mailServer.Email
smtpTo := sendData.To
smtpBody := sendData.Body
smtpPass := mailServer.Password
smtpSubject := sendData.Subject
err = tools.SendSmtp(smtpServer, smtpFrom, smtpPass, smtpTo, smtpSubject, smtpBody)
if err != nil {
msg, _ := json.Marshal(tools.JsonResult{Code: 400, Msg: err.Error()})
w.Write(msg)
return
}
msg, _ := json.Marshal(tools.JsonResult{Code: 200, Msg: "发送成功!"})
w.Write(msg)
}

@ -95,7 +95,7 @@ func SendMessageV2(c *gin.Context) {
// })
// return
//}
msg := TypeMessage{
msg := ws.TypeMessage{
Type: "message",
Data: ws.ClientMessage{
Avator: vistorInfo.Avator,
@ -133,13 +133,13 @@ func SendVisitorNotice(c *gin.Context) {
})
return
}
msg := TypeMessage{
msg := ws.TypeMessage{
Type: "notice",
Data: notice,
}
str, _ := json.Marshal(msg)
for _, visitor := range clientList {
visitor.conn.WriteMessage(websocket.TextMessage, str)
for _, visitor := range ws.ClientList {
visitor.Conn.WriteMessage(websocket.TextMessage, str)
}
c.JSON(200, gin.H{
"code": 200,
@ -158,7 +158,7 @@ func SendCloseMessageV2(c *gin.Context) {
oldUser, ok := ws.ClientList[visitorId]
if oldUser != nil || ok {
msg := TypeMessage{
msg := ws.TypeMessage{
Type: "force_close",
Data: visitorId,
}

@ -1,15 +1,10 @@
package controller
import (
"encoding/json"
"fmt"
"github.com/gin-gonic/gin"
"github.com/gorilla/websocket"
"github.com/taoshihan1991/imaptool/models"
"github.com/taoshihan1991/imaptool/tools"
"github.com/taoshihan1991/imaptool/ws"
"log"
"net/http"
"time"
)
@ -85,49 +80,3 @@ func DelNotice(c *gin.Context) {
"result": "",
})
}
var upgrader = websocket.Upgrader{}
var oldFolders map[string]int
//推送新邮件到达
func PushMailServer(w http.ResponseWriter, r *http.Request) {
c, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Print("upgrade:", err)
return
}
defer c.Close()
for {
mt, message, err := c.ReadMessage()
if err != nil {
log.Println("read:", err)
break
}
log.Printf("recv: %s", message)
mailServer := tools.GetMailServerFromCookie(r)
var msg []byte
if mailServer == nil {
msg, _ = json.Marshal(tools.JsonResult{Code: 400, Msg: "验证失败"})
err = c.WriteMessage(mt, msg)
if err != nil {
log.Println("write:", err)
break
}
} else {
folders := tools.GetMailNum(mailServer.Server, mailServer.Email, mailServer.Password)
for name, num := range folders {
if oldFolders[name] != num {
result := make(map[string]interface{})
result["folder_name"] = name
result["new_num"] = num - oldFolders[name]
msg, _ := json.Marshal(tools.JsonListResult{
JsonResult: tools.JsonResult{Code: 200, Msg: "获取成功"},
Result: result,
})
c.WriteMessage(mt, msg)
}
}
oldFolders = folders
}
}
}

@ -34,7 +34,7 @@ func SendVisitorLoginNotice(kefuName, visitorName, avator, content, visitorId st
userInfo["username"] = visitorName
userInfo["avator"] = avator
userInfo["content"] = content
msg := TypeMessage{
msg := ws.TypeMessage{
Type: "notice",
Data: userInfo,
}

@ -2,13 +2,9 @@ module github.com/taoshihan1991/imaptool
go 1.14
require github.com/emersion/go-imap v1.0.4
require (
github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394
github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f
github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/emersion/go-message v0.11.2
github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21
github.com/emersion/go-smtp v0.13.0
github.com/gin-contrib/pprof v1.3.0

@ -2,8 +2,6 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03
github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394 h1:OYA+5W64v3OgClL+IrOD63t4i/RW7RqrAVl9LTZ9UqQ=
github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394/go.mod h1:Q8n74mJTIgjX4RBBcHnJ05h//6/k6foqmgE45jTQtxg=
github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff/go.mod h1:+RTT1BOk5P97fT2CiHkbFQwkK3mjsFAP6zCYV2aXtjw=
github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA=
github.com/bradleypeabody/gorilla-sessions-memcache v0.0.0-20181103040241-659414f458e1/go.mod h1:dkChI7Tbtx7H1Tj7TqGSZMOeGpMP5gLHtjroHd4agiI=
@ -20,19 +18,10 @@ github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd h1:83Wprp6RO
github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/emersion/go-imap v1.0.4 h1:uiCAIHM6Z5Jwkma1zdNDWWXxSCqb+/xHBkHflD7XBro=
github.com/emersion/go-imap v1.0.4/go.mod h1:yKASt+C3ZiDAiCSssxg9caIckWF/JG7ZQTO7GAmvicU=
github.com/emersion/go-message v0.11.1/go.mod h1:C4jnca5HOTo4bGN9YdqNQM9sITuT3Y0K6bSUw9RklvY=
github.com/emersion/go-message v0.11.2 h1:oxO9SQ+3wgBAQRdk07eqfkCJ26Tl8ZHF7CcpGVoE00o=
github.com/emersion/go-message v0.11.2/go.mod h1:C4jnca5HOTo4bGN9YdqNQM9sITuT3Y0K6bSUw9RklvY=
github.com/emersion/go-sasl v0.0.0-20191210011802-430746ea8b9b h1:uhWtEWBHgop1rqEk2klKaxPAkVDCXexai6hSuRQ7Nvs=
github.com/emersion/go-sasl v0.0.0-20191210011802-430746ea8b9b/go.mod h1:G/dpzLu16WtQpBfQ/z3LYiYJn3ZhKSGWn83fyoyQe/k=
github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21 h1:OJyUGMJTzHTd1XQp98QTaHernxMYzRaOasRir9hUlFQ=
github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21/go.mod h1:iL2twTeMvZnrg54ZoPDNfJaJaqy0xIQFuBdrLsmspwQ=
github.com/emersion/go-smtp v0.13.0 h1:aC3Kc21TdfvXnuJXCQXuhnDXUldhc12qME/S7Y3Y94g=
github.com/emersion/go-smtp v0.13.0/go.mod h1:qm27SGYgoIPRot6ubfQ/GpiPy/g3PaZAVRxiO/sDUgQ=
github.com/emersion/go-textwrapper v0.0.0-20160606182133-d0e65e56babe h1:40SWqY0zE3qCi6ZrtTf5OUdNm5lDnGnjRSq9GgmeTrg=
github.com/emersion/go-textwrapper v0.0.0-20160606182133-d0e65e56babe/go.mod h1:aqO8z8wPrjkscevZJFVE1wXJrLpC5LtJG7fqLOsPb2U=
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y=
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
@ -116,8 +105,6 @@ github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgx
github.com/lib/pq v1.1.1 h1:sJZmqHoEaY7f+NPP8pgLB/WxulyR3fewgCM2qaSlBb4=
github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/martinlindhe/base36 v1.0.0 h1:eYsumTah144C0A8P1T/AVSUk5ZoLnhfYFM3OGQxB52A=
github.com/martinlindhe/base36 v1.0.0/go.mod h1:+AtEs8xrBpCeYgSLoY/aJ6Wf37jtBuR0s35750M27+8=
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=

@ -26,7 +26,6 @@ func InitApiRouter(engine *gin.Engine) {
engine.GET("/userinfo", middleware.JwtApiMiddleware, controller.GetKefuInfoAll)
engine.POST("/register", middleware.Ipblack, controller.PostKefuRegister)
//前后聊天
engine.GET("/chat_server", middleware.Ipblack, controller.NewChatServer)
engine.GET("/ws_kefu", middleware.JwtApiMiddleware, ws.NewKefuServer)
engine.GET("/ws_visitor", middleware.Ipblack, ws.NewVisitorServer)
go ws.WsServerBackend()
@ -56,8 +55,6 @@ func InitApiRouter(engine *gin.Engine) {
//角色列表
engine.GET("/roles", middleware.JwtApiMiddleware, middleware.RbacAuth, controller.GetRoleList)
engine.POST("/role", middleware.JwtApiMiddleware, middleware.RbacAuth, controller.PostRole)
//邮件夹列表
engine.GET("/folders", controller.GetFolders)
engine.GET("/mysql", middleware.JwtApiMiddleware, middleware.RbacAuth, controller.MysqlGetConf)
engine.POST("/mysql", middleware.JwtApiMiddleware, middleware.RbacAuth, controller.MysqlSetConf)

@ -8,6 +8,7 @@ import (
func InitViewRouter(engine *gin.Engine) {
engine.GET("/index_:lang", middleware.SetLanguage, tmpl.PageIndex)
engine.GET("/detail_:page", middleware.SetLanguage, tmpl.PageDetail)
engine.GET("/login", tmpl.PageLogin)
engine.GET("/chat_page", middleware.SetLanguage, tmpl.PageChat)
engine.GET("/chatIndex", middleware.SetLanguage, tmpl.PageChat)
@ -17,6 +18,7 @@ func InitViewRouter(engine *gin.Engine) {
engine.GET("/setting", tmpl.PageSetting)
engine.GET("/setting_statistics", tmpl.PageSettingStatis)
engine.GET("/setting_indexpage", tmpl.PageSettingIndexPage)
engine.GET("/setting_indexpages", tmpl.PageSettingIndexPages)
engine.GET("/setting_mysql", tmpl.PageSettingMysql)
engine.GET("/setting_welcome", tmpl.PageSettingWelcome)
engine.GET("/setting_deploy", tmpl.PageSettingDeploy)

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="renderer" content="webkit">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<title>{{.Title}}</title>
<meta name="keywords" content="{{.Keywords}}" />
<meta name="description" content="{{.Desc}}" />
{{.CssJs}}
</head>
<body>
{{.Content}}
</body>
</html>

@ -0,0 +1,9 @@
{{template "header" }}
<div id="app" style="width:100%">
<template>
正在开发...
</template>
</div>
</body>
{{template "setting_bottom" .}}

@ -34,11 +34,8 @@
<span>系统设置</span>
</template>
<el-menu-item-group>
<el-menu-item style="display:none" index="2-1">设置smtp</el-menu-item>
<el-menu-item style="display:none" index="2-2">设置imap</el-menu-item>
<el-menu-item style="display:none" index="2-3" v-on:click="openUrl('/setting')">设置登陆账号</el-menu-item>
<el-menu-item style="display:none" index="2-4" v-on:click="openUrl('/setting_mysql')">设置mysql</el-menu-item>
<el-menu-item index="4-7" v-on:click="openUrl('/setting_indexpage')">编辑首页</el-menu-item>
<el-menu-item index="4-7" v-on:click="openUrl('/setting_indexpages')">单页列表</el-menu-item>
<el-menu-item index="4-6" v-on:click="openUrl('/setting_config')">配置参数</el-menu-item>
<el-menu-item index="4-5" v-on:click="openUrl('/setting_ipblack')">IP黑名单</el-menu-item>
<el-menu-item index="2-5" v-on:click="openUrl('/setting_deploy')">网页部署</el-menu-item>

@ -1,16 +1,37 @@
package tmpl
import "net/http"
import (
"github.com/gin-gonic/gin"
"github.com/taoshihan1991/imaptool/models"
"html"
"html/template"
"net/http"
)
type DetailHtml struct {
*CommonHtml
Fid string
Id uint32
}
func NewDetailHtml(w http.ResponseWriter) *DetailHtml {
obj := new(DetailHtml)
parent := NewRender(w)
obj.CommonHtml = parent
return obj
func PageDetail(c *gin.Context) {
if c.Request.RequestURI == "/favicon.ico" {
return
}
page := c.Param("page")
lang, _ := c.Get("lang")
about := models.FindAboutByPageLanguage(page, lang.(string))
cssJs := html.UnescapeString(about.CssJs)
title := about.TitleCn
keywords := about.KeywordsCn
desc := html.UnescapeString(about.DescCn)
content := html.UnescapeString(about.HtmlCn)
if lang == "en" {
title = about.TitleEn
keywords = about.KeywordsEn
desc = html.UnescapeString(about.DescEn)
content = html.UnescapeString(about.HtmlEn)
}
c.HTML(http.StatusOK, "detail.html", gin.H{
"Lang": lang,
"Title": title,
"Keywords": keywords,
"Desc": desc,
"Content": template.HTML(content),
"CssJs": template.HTML(cssJs),
})
}

@ -95,3 +95,11 @@ func PageSettingIndexPage(c *gin.Context) {
"action": "setting_pageindex",
})
}
//配置项编辑首页
func PageSettingIndexPages(c *gin.Context) {
c.HTML(http.StatusOK, "setting_indexpages.html", gin.H{
"tab_index": "4-7",
"action": "setting_indexpages",
})
}

@ -1,363 +0,0 @@
package tools
import (
"bytes"
"fmt"
"github.com/axgle/mahonia"
"github.com/emersion/go-imap"
"github.com/emersion/go-imap/client"
"github.com/emersion/go-message/mail"
"io"
"io/ioutil"
"log"
"mime"
"strconv"
"strings"
)
//验证邮箱密码
func CheckEmailPassword(server string, email string, password string) bool {
if !strings.Contains(server, ":") {
return false
}
var c *client.Client
serverSlice := strings.Split(server, ":")
port, _ := strconv.Atoi(serverSlice[1])
if port != 993 && port != 143 {
return false
}
// 不要忘了退出
//defer c.Logout()
// 登陆
c = connect(server, email, password)
if c == nil {
return false
}
return true
}
//获取连接
func connect(server string, email string, password string) *client.Client {
var c *client.Client
var err error
serverSlice := strings.Split(server, ":")
uri := serverSlice[0]
port, _ := strconv.Atoi(serverSlice[1])
if port != 993 && port != 143 {
return nil
}
if port == 993 {
c, err = client.DialTLS(fmt.Sprintf("%s:%d", uri, port), nil)
} else {
c, err = client.Dial(fmt.Sprintf("%s:%d", uri, port))
}
if err != nil {
return nil
}
// 登陆
if err := c.Login(email, password); err != nil {
return nil
}
return c
}
//获取邮件总数
func GetMailNum(server string, email string, password string) map[string]int {
var c *client.Client
//defer c.Logout()
c = connect(server, email, password)
if c == nil {
return nil
}
// 列邮箱
mailboxes := make(chan *imap.MailboxInfo, 10)
done := make(chan error, 1)
go func() {
done <- c.List("", "*", mailboxes)
}()
//// 存储邮件夹
var folders = make(map[string]int)
for m := range mailboxes {
folders[m.Name] = 0
}
for m, _ := range folders {
mbox, _ := c.Select(m, true)
if mbox != nil {
folders[m] = int(mbox.Messages)
}
}
return folders
}
//获取邮件夹
func GetFolders(server string, email string, password string, folder string) map[string]int {
var c *client.Client
//defer c.Logout()
c = connect(server, email, password)
if c == nil {
return nil
}
// 列邮箱
mailboxes := make(chan *imap.MailboxInfo, 10)
done := make(chan error, 1)
go func() {
done <- c.List("", "*", mailboxes)
}()
// 存储邮件夹
var folders = make(map[string]int)
for m := range mailboxes {
folders[m.Name] = 0
}
for m, _ := range folders {
if m == folder {
mbox, _ := c.Select(m, true)
if mbox != nil {
folders[m] = int(mbox.Messages)
}
break
}
}
//log.Println(folders)
return folders
}
//获取邮件夹邮件
func GetFolderMail(server string, email string, password string, folder string, currentPage int, pagesize int) []*MailItem {
var c *client.Client
//defer c.Logout()
c = connect(server, email, password)
if c == nil {
return nil
}
mbox, _ := c.Select(folder, true)
to := mbox.Messages - uint32((currentPage-1)*pagesize)
from := to - uint32(pagesize)
if to <= uint32(pagesize) {
from = 1
}
seqset := new(imap.SeqSet)
seqset.AddRange(from, to)
messages := make(chan *imap.Message, pagesize)
done := make(chan error, 1)
fetchItem := imap.FetchItem(imap.FetchEnvelope)
items := make([]imap.FetchItem, 0)
items = append(items, fetchItem)
go func() {
done <- c.Fetch(seqset, items, messages)
}()
var mailPagelist = new(MailPageList)
dec := GetDecoder()
for msg := range messages {
log.Println(msg.Envelope.Date)
ret, err := dec.Decode(msg.Envelope.Subject)
if err != nil {
ret, _ = dec.DecodeHeader(msg.Envelope.Subject)
}
var mailitem = new(MailItem)
mailitem.Subject = ret
mailitem.Id = msg.SeqNum
mailitem.Fid = folder
mailitem.Date = msg.Envelope.Date.String()
from := ""
for _, s := range msg.Envelope.Sender {
from += s.Address()
}
mailitem.From = from
mailPagelist.MailItems = append(mailPagelist.MailItems, mailitem)
}
return mailPagelist.MailItems
}
func GetMessage(server string, email string, password string, folder string, id uint32) *MailItem {
var c *client.Client
//defer c.Logout()
c = connect(server, email, password)
if c == nil {
//return nil
}
// Select INBOX
mbox, err := c.Select(folder, false)
if err != nil {
log.Fatal(err)
}
// Get the last message
if mbox.Messages == 0 {
log.Fatal("No message in mailbox")
}
seqSet := new(imap.SeqSet)
seqSet.AddNum(id)
// Get the whole message body
section := &imap.BodySectionName{}
items := []imap.FetchItem{section.FetchItem()}
messages := make(chan *imap.Message, 1)
go func() {
if err := c.Fetch(seqSet, items, messages); err != nil {
log.Fatal(err)
}
}()
msg := <-messages
if msg == nil {
log.Fatal("Server didn't returned message")
}
r := msg.GetBody(section)
if r == nil {
log.Fatal("Server didn't returned message body")
}
var mailitem = new(MailItem)
// Create a new mail reader
mr, _ := mail.CreateReader(r)
// Print some info about the message
header := mr.Header
date, _ := header.Date()
mailitem.Date = date.String()
var f string
dec := GetDecoder()
if from, err := header.AddressList("From"); err == nil {
for _, address := range from {
fromStr := address.String()
temp, _ := dec.DecodeHeader(fromStr)
f += " " + temp
}
}
mailitem.From = f
log.Println("From:", mailitem.From)
var t string
if to, err := header.AddressList("To"); err == nil {
log.Println("To:", to)
for _, address := range to {
toStr := address.String()
temp, _ := dec.DecodeHeader(toStr)
t += " " + temp
}
}
mailitem.To = t
subject, _ := header.Subject()
s, err := dec.Decode(subject)
if err != nil {
s, _ = dec.DecodeHeader(subject)
}
log.Println("Subject:", s)
mailitem.Subject = s
// Process each message's part
var bodyMap = make(map[string]string)
bodyMap["text/plain"] = ""
bodyMap["text/html"] = ""
for {
p, err := mr.NextPart()
if err == io.EOF {
break
} else if err != nil {
//log.Fatal(err)
}
switch h := p.Header.(type) {
case *mail.InlineHeader:
// This is the message's text (can be plain-text or HTML)
b, _ := ioutil.ReadAll(p.Body)
ct := p.Header.Get("Content-Type")
if strings.Contains(ct, "text/plain") {
bodyMap["text/plain"] += Encoding(string(b), ct)
} else {
bodyMap["text/html"] += Encoding(string(b), ct)
}
//body,_:=dec.Decode(string(b))
case *mail.AttachmentHeader:
// This is an attachment
filename, _ := h.Filename()
log.Println("Got attachment: ", filename)
}
}
if bodyMap["text/html"] != "" {
mailitem.Body = bodyMap["text/html"]
} else {
mailitem.Body = bodyMap["text/plain"]
}
//log.Println(mailitem.Body)
return mailitem
}
func GetDecoder() *mime.WordDecoder {
dec := new(mime.WordDecoder)
dec.CharsetReader = func(charset string, input io.Reader) (io.Reader, error) {
charset = strings.ToLower(charset)
switch charset {
case "gb2312":
content, err := ioutil.ReadAll(input)
if err != nil {
return nil, err
}
//ret:=bytes.NewReader(content)
//ret:=transform.NewReader(bytes.NewReader(content), simplifiedchinese.HZGB2312.NewEncoder())
utf8str := ConvertToStr(string(content), "gbk", "utf-8")
t := bytes.NewReader([]byte(utf8str))
//ret:=utf8.DecodeRune(t)
//log.Println(ret)
return t, nil
case "gbk":
content, err := ioutil.ReadAll(input)
if err != nil {
return nil, err
}
//ret:=bytes.NewReader(content)
//ret:=transform.NewReader(bytes.NewReader(content), simplifiedchinese.HZGB2312.NewEncoder())
utf8str := ConvertToStr(string(content), "gbk", "utf-8")
t := bytes.NewReader([]byte(utf8str))
//ret:=utf8.DecodeRune(t)
//log.Println(ret)
return t, nil
case "gb18030":
content, err := ioutil.ReadAll(input)
if err != nil {
return nil, err
}
//ret:=bytes.NewReader(content)
//ret:=transform.NewReader(bytes.NewReader(content), simplifiedchinese.HZGB2312.NewEncoder())
utf8str := ConvertToStr(string(content), "gbk", "utf-8")
t := bytes.NewReader([]byte(utf8str))
//ret:=utf8.DecodeRune(t)
//log.Println(ret)
return t, nil
default:
return nil, fmt.Errorf("unhandle charset:%s", charset)
}
}
return dec
}
// 任意编码转特定编码
func ConvertToStr(src string, srcCode string, tagCode string) string {
result := mahonia.NewDecoder(srcCode).ConvertString(src)
//srcCoder := mahonia.NewDecoder(srcCode)
//srcResult := srcCoder.ConvertString(src)
//tagCoder := mahonia.NewDecoder(tagCode)
//_, cdata, _ := tagCoder.Translate([]byte(srcResult), true)
//result := string(cdata)
return result
}

@ -1,217 +0,0 @@
package tools
import (
"bufio"
"flag"
"fmt"
"io"
"io/ioutil"
"log"
"os"
"strconv"
"strings"
"github.com/emersion/go-imap"
"github.com/emersion/go-imap/client"
"github.com/emersion/go-message/mail"
)
//全局变量
//imap服务地址,邮箱,密码
var (
server, email, password string
folders map[int]string
)
func testmain() {
//获取参数中的数据
flag.StringVar(&server, "server", "", "imap服务地址(包含端口)")
flag.StringVar(&email, "email", "", "邮箱名")
flag.StringVar(&password, "password", "", "密码")
flag.Parse()
if flag.NFlag() < 3 {
flag.PrintDefaults()
os.Exit(1)
}
if server == "" || email == "" || password == "" {
log.Fatal("服务器地址,用户名,密码,参数必填")
}
log.Println("正在连接服务器...")
//支持加密和非加密端口
if !strings.Contains(server, ":") {
log.Fatal("服务器地址端口号错误:", server)
}
serverSlice := strings.Split(server, ":")
uri := serverSlice[0]
port, _ := strconv.Atoi(serverSlice[1])
if port != 993 && port != 143 {
log.Fatal("服务器地址端口号错误:", port)
}
// 连接到服务器
var c *client.Client
var err error
if port == 993 {
c, err = client.DialTLS(fmt.Sprintf("%s:%d", uri, port), nil)
} else {
c, err = client.Dial(fmt.Sprintf("%s:%d", uri, port))
}
if err != nil {
log.Fatal(err)
}
log.Println("连接成功")
// 不要忘了退出
defer c.Logout()
// 登陆
if err := c.Login(email, password); err != nil {
log.Fatal(err)
}
log.Println("成功登陆")
// 列邮箱
mailboxes := make(chan *imap.MailboxInfo, 10)
done := make(chan error, 1)
go func() {
done <- c.List("", "*", mailboxes)
}()
// 存储邮件夹
folders = make(map[int]string)
i := 1
for m := range mailboxes {
log.Println("* ", i, m.Name)
folders[i] = m.Name
i++
}
log.Println("输入邮件夹序号:")
inLine := readLineFromInput()
folderNum, _ := strconv.Atoi(inLine)
currentFolder := folders[folderNum]
if err := <-done; err != nil {
log.Fatal(err)
}
// Select 邮件夹
mbox, err := c.Select(currentFolder, false)
if err != nil {
log.Fatal(err)
}
log.Printf("%s的邮件个数:%d \r\n", currentFolder, mbox.Messages)
// 获取最新的信
log.Println("读取最新的几封信(all全部):")
inLine = readLineFromInput()
var maxNum uint32
if inLine == "all" {
maxNum = mbox.Messages
} else {
tempNum, _ := strconv.Atoi(inLine)
maxNum = uint32(tempNum)
}
from := uint32(1)
to := mbox.Messages
if mbox.Messages >= maxNum {
// 我们在这使用无符号整型, 这是再获取from的id
from = mbox.Messages - maxNum + 1
} else {
log.Fatal("超出了邮件封数!")
}
seqset := new(imap.SeqSet)
seqset.AddRange(from, to)
messages := make(chan *imap.Message, 10)
done = make(chan error, 1)
go func() {
done <- c.Fetch(seqset, []imap.FetchItem{imap.FetchEnvelope}, messages)
}()
log.Printf("最新的 %d 封信:", maxNum)
for msg := range messages {
log.Printf("* %d:%s\n", to, msg.Envelope.Subject)
to--
}
if err := <-done; err != nil {
log.Fatal(err)
}
for {
log.Println("读取第几封信信体:")
inLine = readLineFromInput()
mesIndex, _ := strconv.Atoi(inLine)
mesSeqSet := new(imap.SeqSet)
mesSeqSet.AddNum(uint32(mesIndex))
//获取整封信体
var section imap.BodySectionName
items := []imap.FetchItem{section.FetchItem()}
bodyMsg := make(chan *imap.Message, 1)
go func() {
if err := c.Fetch(mesSeqSet, items, bodyMsg); err != nil {
log.Fatal(err)
}
}()
msg := <-bodyMsg
if msg == nil {
log.Fatal("服务器没有返回信息")
}
r := msg.GetBody(&section)
if r == nil {
log.Fatal("服务器没有返回 message body")
}
mr, err := mail.CreateReader(r)
if err != nil {
log.Fatal(err)
}
//打印信息
header := mr.Header
if date, err := header.Date(); err == nil {
log.Println("Date:", date)
}
if from, err := header.AddressList("From"); err == nil {
log.Println("From:", from)
}
if to, err := header.AddressList("To"); err == nil {
log.Println("To:", to)
}
if subject, err := header.Subject(); err == nil {
log.Println("Subject:", subject)
}
// Process each message's part
for {
p, err := mr.NextPart()
if err == io.EOF {
break
} else if err != nil {
log.Fatal(err)
}
switch h := p.Header.(type) {
case *mail.InlineHeader:
// This is the message's text (can be plain-text or HTML)
b, _ := ioutil.ReadAll(p.Body)
log.Printf("Got text: %s\n", string(b))
case *mail.AttachmentHeader:
// This is an attachment
filename, _ := h.Filename()
log.Printf("Got attachment: %s\n", filename)
}
}
log.Printf("读取第 %d 封信, 结束!\n", mesIndex)
}
}
//从输入中读取一行
func readLineFromInput() string {
str := ""
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
str = scanner.Text() // Println will add back the final '\n'
break
}
return str
}

@ -4,13 +4,7 @@ package tools
import (
"fmt"
"github.com/gobuffalo/packr/v2"
"golang.org/x/net/html/charset"
"golang.org/x/text/encoding"
"golang.org/x/text/encoding/unicode"
"golang.org/x/text/transform"
"io/ioutil"
"net/http"
"strings"
)
//获取URL的GET参数
@ -43,25 +37,6 @@ func Reverse2(s string) string {
return string(r)
}
//转换编码
func Encoding(html string, ct string) string {
e, name := DetermineEncoding(html)
if name != "utf-8" {
html = ConvertToStr(html, "gbk", "utf-8")
e = unicode.UTF8
}
r := strings.NewReader(html)
utf8Reader := transform.NewReader(r, e.NewDecoder())
//将其他编码的reader转换为常用的utf8reader
all, _ := ioutil.ReadAll(utf8Reader)
return string(all)
}
func DetermineEncoding(html string) (encoding.Encoding, string) {
e, name, _ := charset.DetermineEncoding([]byte(html), "")
return e, name
}
//获取文件内容,可以打包到二进制
func FileGetContent(file string) string {
str := ""

Loading…
Cancel
Save