action.go 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. package pop3_server
  2. import (
  3. "database/sql"
  4. "github.com/Jinnrry/gopop"
  5. log "github.com/sirupsen/logrus"
  6. "github.com/spf13/cast"
  7. "pmail/db"
  8. "pmail/models"
  9. "pmail/services/detail"
  10. "pmail/utils/array"
  11. "pmail/utils/context"
  12. "pmail/utils/errors"
  13. "pmail/utils/id"
  14. "pmail/utils/password"
  15. "strings"
  16. )
  17. type action struct {
  18. }
  19. func (a action) User(ctx *gopop.Data, username string) error {
  20. if ctx.Ctx == nil {
  21. tc := &context.Context{}
  22. tc.SetValue(context.LogID, id.GenLogID())
  23. ctx.Ctx = tc
  24. }
  25. infos := strings.Split(username, "@")
  26. if len(infos) > 1 {
  27. username = infos[0]
  28. }
  29. log.WithContext(ctx.Ctx).Debugf("POP3 User %s", username)
  30. ctx.User = username
  31. return nil
  32. }
  33. func (a action) Pass(ctx *gopop.Data, pwd string) error {
  34. if ctx.Ctx == nil {
  35. tc := &context.Context{}
  36. tc.SetValue(context.LogID, id.GenLogID())
  37. ctx.Ctx = tc
  38. }
  39. log.WithContext(ctx.Ctx).Debugf("POP3 PASS %s , User:%s", pwd, ctx.User)
  40. var user models.User
  41. encodePwd := password.Encode(pwd)
  42. err := db.Instance.Get(&user, db.WithContext(ctx.Ctx.(*context.Context), "select * from user where account =? and password =?"), ctx.User, encodePwd)
  43. if err != nil && !errors.Is(err, sql.ErrNoRows) {
  44. log.WithContext(ctx.Ctx.(*context.Context)).Errorf("%+v", err)
  45. }
  46. if user.ID > 0 {
  47. ctx.Status = gopop.TRANSACTION
  48. ctx.Ctx.(*context.Context).UserID = user.ID
  49. ctx.Ctx.(*context.Context).UserName = user.Name
  50. ctx.Ctx.(*context.Context).UserAccount = user.Account
  51. return nil
  52. }
  53. return errors.New("password error")
  54. }
  55. func (a action) Apop(ctx *gopop.Data, username, digest string) error {
  56. if ctx.Ctx == nil {
  57. tc := &context.Context{}
  58. tc.SetValue(context.LogID, id.GenLogID())
  59. ctx.Ctx = tc
  60. }
  61. infos := strings.Split(username, "@")
  62. if len(infos) > 1 {
  63. username = infos[0]
  64. }
  65. log.WithContext(ctx.Ctx).Debugf("POP3 APOP %s %s", username, digest)
  66. var user models.User
  67. err := db.Instance.Get(&user, db.WithContext(ctx.Ctx.(*context.Context), "select * from user where account =? "), username)
  68. if err != nil && !errors.Is(err, sql.ErrNoRows) {
  69. log.WithContext(ctx.Ctx.(*context.Context)).Errorf("%+v", err)
  70. }
  71. if user.ID > 0 && digest == password.Md5Encode(user.Password) {
  72. ctx.User = username
  73. ctx.Status = gopop.TRANSACTION
  74. ctx.Ctx.(*context.Context).UserID = user.ID
  75. ctx.Ctx.(*context.Context).UserName = user.Name
  76. ctx.Ctx.(*context.Context).UserAccount = user.Account
  77. return nil
  78. }
  79. return errors.New("password error")
  80. }
  81. type statInfo struct {
  82. Num int64 `json:"num"`
  83. Size int64 `json:"size"`
  84. }
  85. func (a action) Stat(ctx *gopop.Data) (msgNum, msgSize int64, err error) {
  86. var si statInfo
  87. err = db.Instance.Get(&si, db.WithContext(ctx.Ctx.(*context.Context), "select count(1) as `num`, sum(length(text)+length(html)) as `size` from email"))
  88. if err != nil && !errors.Is(err, sql.ErrNoRows) {
  89. log.WithContext(ctx.Ctx.(*context.Context)).Errorf("%+v", err)
  90. err = nil
  91. log.WithContext(ctx.Ctx).Debugf("POP3 STAT RETURT :0,0")
  92. return 0, 0, nil
  93. }
  94. log.WithContext(ctx.Ctx).Debugf("POP3 STAT RETURT : %d,%d", si.Num, si.Size)
  95. return si.Num, si.Size, nil
  96. }
  97. func (a action) Uidl(ctx *gopop.Data, id int64) (string, error) {
  98. log.WithContext(ctx.Ctx).Debugf("POP3 Uidl RETURT : %d", id)
  99. return cast.ToString(id), nil
  100. }
  101. type listItem struct {
  102. Id int64 `json:"id"`
  103. Size int64 `json:"size"`
  104. }
  105. func (a action) List(ctx *gopop.Data, msg string) ([]gopop.MailInfo, error) {
  106. var res []listItem
  107. var id int64
  108. if msg != "" {
  109. id = cast.ToInt64(msg)
  110. if id == 0 {
  111. return nil, errors.New("params error")
  112. }
  113. }
  114. var err error
  115. if id != 0 {
  116. err = db.Instance.Select(&res, db.WithContext(ctx.Ctx.(*context.Context), "select id, length(text)+length(html) as `size` from email where id =?"), id)
  117. } else {
  118. err = db.Instance.Select(&res, db.WithContext(ctx.Ctx.(*context.Context), "select id, length(text)+length(html) as `size` from email"))
  119. }
  120. if err != nil && !errors.Is(err, sql.ErrNoRows) {
  121. log.WithContext(ctx.Ctx.(*context.Context)).Errorf("%+v", err)
  122. err = nil
  123. return []gopop.MailInfo{}, nil
  124. }
  125. ret := []gopop.MailInfo{}
  126. for _, re := range res {
  127. ret = append(ret, gopop.MailInfo{
  128. Id: re.Id,
  129. Size: re.Size,
  130. })
  131. }
  132. return ret, nil
  133. }
  134. func (a action) Retr(ctx *gopop.Data, id int64) (string, int64, error) {
  135. email, err := detail.GetEmailDetail(ctx.Ctx.(*context.Context), cast.ToInt(id), false)
  136. if err != nil {
  137. log.WithContext(ctx.Ctx.(*context.Context)).Errorf("%+v", err)
  138. return "", 0, errors.New("server error")
  139. }
  140. ret := email.ToTransObj().BuildBytes(ctx.Ctx.(*context.Context), false)
  141. return string(ret), cast.ToInt64(len(ret)), nil
  142. }
  143. func (a action) Delete(ctx *gopop.Data, id int64) error {
  144. ctx.DeleteIds = append(ctx.DeleteIds, id)
  145. ctx.DeleteIds = array.Unique(ctx.DeleteIds)
  146. return nil
  147. }
  148. func (a action) Rest(ctx *gopop.Data) error {
  149. ctx.DeleteIds = []int64{}
  150. return nil
  151. }
  152. func (a action) Top(ctx *gopop.Data, id int64, n int) (string, error) {
  153. //email, err := detail.GetEmailDetail(ctx.Ctx.(*context.Context), cast.ToInt(id), false)
  154. //if err != nil {
  155. // log.WithContext(ctx.Ctx.(*context.Context)).Errorf("%+v", err)
  156. // return "", errors.New("server error")
  157. //}
  158. //
  159. //ret := email.ToTransObj().BuilderHeaders(ctx.Ctx.(*context.Context))
  160. //return string(ret), nil
  161. return "", errors.New("not supported")
  162. }
  163. func (a action) Noop(ctx *gopop.Data) error {
  164. return nil
  165. }
  166. func (a action) Quit(ctx *gopop.Data) error {
  167. if len(ctx.DeleteIds) > 0 {
  168. _, err := db.Instance.Exec(db.WithContext(ctx.Ctx.(*context.Context), "DELETE FROM email WHERE id in ?"), ctx.DeleteIds)
  169. if err != nil {
  170. log.WithContext(ctx.Ctx.(*context.Context)).Errorf("%+v", err)
  171. }
  172. }
  173. return nil
  174. }