imap.go 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830
  1. package goimap
  2. import (
  3. "bufio"
  4. "crypto/tls"
  5. "encoding/base64"
  6. "errors"
  7. "fmt"
  8. "github.com/Jinnrry/pmail/utils/context"
  9. "github.com/Jinnrry/pmail/utils/id"
  10. log "github.com/sirupsen/logrus"
  11. "net"
  12. "strings"
  13. "sync"
  14. "time"
  15. )
  16. var (
  17. eol = "\r\n"
  18. )
  19. // Server Imap服务实例
  20. type Server struct {
  21. Domain string // 域名
  22. Port int // 端口
  23. TlsEnabled bool //是否启用Tls
  24. TlsConfig *tls.Config // tls配置
  25. ConnectAliveTime time.Duration // 连接存活时间,默认不超时
  26. Action Action
  27. stop chan bool
  28. close bool
  29. lck sync.Mutex
  30. }
  31. // NewImapServer 新建一个服务实例
  32. func NewImapServer(port int, domain string, tlsEnabled bool, tlsConfig *tls.Config, action Action) *Server {
  33. return &Server{
  34. Domain: domain,
  35. Port: port,
  36. TlsEnabled: tlsEnabled,
  37. TlsConfig: tlsConfig,
  38. Action: action,
  39. stop: make(chan bool, 1),
  40. }
  41. }
  42. // Start 启动服务
  43. func (s *Server) Start() error {
  44. if !s.TlsEnabled {
  45. return s.startWithoutTLS()
  46. } else {
  47. return s.startWithTLS()
  48. }
  49. }
  50. func (s *Server) startWithTLS() error {
  51. if s.lck.TryLock() {
  52. listener, err := tls.Listen("tcp", fmt.Sprintf(":%d", s.Port), s.TlsConfig)
  53. if err != nil {
  54. return err
  55. }
  56. s.close = false
  57. defer func() {
  58. listener.Close()
  59. }()
  60. go func() {
  61. for {
  62. conn, err := listener.Accept()
  63. if err != nil {
  64. if s.close {
  65. break
  66. } else {
  67. continue
  68. }
  69. }
  70. go s.handleClient(conn)
  71. }
  72. }()
  73. <-s.stop
  74. } else {
  75. return errors.New("Server Is Running")
  76. }
  77. return nil
  78. }
  79. func (s *Server) startWithoutTLS() error {
  80. if s.lck.TryLock() {
  81. listener, err := net.Listen("tcp", fmt.Sprintf(":%d", s.Port))
  82. if err != nil {
  83. return err
  84. }
  85. s.close = false
  86. defer func() {
  87. listener.Close()
  88. }()
  89. go func() {
  90. for {
  91. conn, err := listener.Accept()
  92. if err != nil {
  93. if s.close {
  94. break
  95. } else {
  96. continue
  97. }
  98. }
  99. go s.handleClient(conn)
  100. }
  101. }()
  102. <-s.stop
  103. } else {
  104. return errors.New("Server Is Running")
  105. }
  106. return nil
  107. }
  108. // Stop 停止服务
  109. func (s *Server) Stop() {
  110. s.close = true
  111. s.stop <- true
  112. }
  113. func (s *Server) authenticate(session *Session, args string, nub string, conn net.Conn, reader *bufio.Reader) {
  114. if args == "LOGIN" {
  115. write(session, "+ VXNlciBOYW1lAA=="+eol, "")
  116. line, err2 := reader.ReadString('\n')
  117. if err2 != nil {
  118. if conn != nil {
  119. _ = conn.Close()
  120. }
  121. session.Conn = nil
  122. session.IN_IDLE = false
  123. return
  124. }
  125. account, err := base64.StdEncoding.DecodeString(line)
  126. if err != nil {
  127. showBad(session, "Data Error.", nub)
  128. return
  129. }
  130. write(session, "+ UGFzc3dvcmQA"+eol, "")
  131. line, err = reader.ReadString('\n')
  132. if err2 != nil {
  133. if conn != nil {
  134. _ = conn.Close()
  135. }
  136. session.Conn = nil
  137. session.IN_IDLE = false
  138. return
  139. }
  140. password, err := base64.StdEncoding.DecodeString(line)
  141. res := s.Action.Login(session, string(account), string(password))
  142. if res.Type == SUCCESS {
  143. showSucc(session, res.Message, nub)
  144. } else if res.Type == BAD {
  145. showBad(session, res.Message, nub)
  146. } else {
  147. showNo(session, res.Message, nub)
  148. }
  149. } else {
  150. showBad(session, "Unsupported AUTHENTICATE mechanism.", nub)
  151. }
  152. }
  153. func (s *Server) capability(session *Session, args string, nub string, conn net.Conn, reader *bufio.Reader) {
  154. res := s.Action.CapaBility(session)
  155. if res.Type == BAD {
  156. write(session, fmt.Sprintf("* BAD %s%s", res.Message, eol), nub)
  157. } else {
  158. ret := "*"
  159. for _, command := range res.Data {
  160. ret += " " + command
  161. }
  162. ret += eol
  163. write(session, ret, nub)
  164. showSucc(session, res.Message, nub)
  165. }
  166. }
  167. func (s *Server) create(session *Session, args string, nub string, conn net.Conn, reader *bufio.Reader) {
  168. if session.Status != AUTHORIZED {
  169. showBad(session, "Need Login", nub)
  170. return
  171. }
  172. if args == "" {
  173. paramsErr(session, "CREATE", nub)
  174. return
  175. }
  176. res := s.Action.Create(session, args)
  177. showSucc(session, res.Message, nub)
  178. }
  179. func (s *Server) delete(session *Session, args string, nub string, conn net.Conn, reader *bufio.Reader) {
  180. if session.Status != AUTHORIZED {
  181. showBad(session, "Need Login", nub)
  182. return
  183. }
  184. if args == "" {
  185. paramsErr(session, "DELETE", nub)
  186. return
  187. }
  188. res := s.Action.Delete(session, args)
  189. if res.Type == SUCCESS {
  190. showSucc(session, res.Message, nub)
  191. } else if res.Type == BAD {
  192. showBad(session, res.Message, nub)
  193. } else {
  194. showNo(session, res.Message, nub)
  195. }
  196. }
  197. func (s *Server) rename(session *Session, args string, nub string, conn net.Conn, reader *bufio.Reader) {
  198. if session.Status != AUTHORIZED {
  199. showBad(session, "Need Login", nub)
  200. return
  201. }
  202. if args == "" {
  203. paramsErr(session, "RENAME", nub)
  204. } else {
  205. dt := strings.Split(args, " ")
  206. res := s.Action.Rename(session, dt[0], dt[1])
  207. if res.Type == SUCCESS {
  208. showSucc(session, res.Message, nub)
  209. } else if res.Type == BAD {
  210. showBad(session, res.Message, nub)
  211. } else {
  212. showNo(session, res.Message, nub)
  213. }
  214. }
  215. }
  216. func (s *Server) list(session *Session, args string, nub string, conn net.Conn, reader *bufio.Reader) {
  217. if session.Status != AUTHORIZED {
  218. showBad(session, "Need Login", nub)
  219. return
  220. }
  221. if args == "" {
  222. paramsErr(session, "LIST", nub)
  223. } else {
  224. dt := strings.Split(args, " ")
  225. dt[0] = strings.Trim(dt[0], `"`)
  226. dt[1] = strings.Trim(dt[1], `"`)
  227. res := s.Action.List(session, dt[0], dt[1])
  228. if res.Type == SUCCESS {
  229. showSuccWithData(session, res.Data, res.Message, nub)
  230. } else if res.Type == BAD {
  231. showBad(session, res.Message, nub)
  232. } else {
  233. showNo(session, res.Message, nub)
  234. }
  235. }
  236. }
  237. func (s *Server) append(session *Session, args string, nub string, conn net.Conn, reader *bufio.Reader) {
  238. if session.Status != AUTHORIZED {
  239. showBad(session, "Need Login", nub)
  240. return
  241. }
  242. log.WithContext(session.Ctx).Debugf("Append: %+v", args)
  243. }
  244. func (s *Server) cselect(session *Session, args string, nub string, conn net.Conn, reader *bufio.Reader) {
  245. if session.Status != AUTHORIZED {
  246. showBad(session, "Need Login", nub)
  247. return
  248. }
  249. res := s.Action.Select(session, args)
  250. if res.Type == SUCCESS {
  251. showSuccWithData(session, res.Data, res.Message, nub)
  252. } else if res.Type == BAD {
  253. showBad(session, res.Message, nub)
  254. } else {
  255. showNo(session, res.Message, nub)
  256. }
  257. }
  258. func (s *Server) fetch(session *Session, args string, nub string, conn net.Conn, reader *bufio.Reader, uid bool) {
  259. if session.Status != AUTHORIZED {
  260. showBad(session, "Need Login", nub)
  261. return
  262. }
  263. if args == "" {
  264. paramsErr(session, "FETCH", nub)
  265. } else {
  266. dt := strings.SplitN(args, " ", 2)
  267. if len(dt) != 2 {
  268. showBad(session, "Error Params", nub)
  269. return
  270. }
  271. res := s.Action.Fetch(session, dt[0], dt[1], uid)
  272. if res.Type == SUCCESS {
  273. showSuccWithData(session, res.Data, res.Message, nub)
  274. } else if res.Type == BAD {
  275. showBad(session, res.Message, nub)
  276. } else {
  277. showNo(session, res.Message, nub)
  278. }
  279. }
  280. }
  281. func (s *Server) store(session *Session, args string, nub string, conn net.Conn, reader *bufio.Reader, uid bool) {
  282. if session.Status != AUTHORIZED {
  283. showBad(session, "Need Login", nub)
  284. return
  285. }
  286. if args == "" {
  287. paramsErr(session, "RENAME", nub)
  288. } else {
  289. dt := strings.SplitN(args, " ", 2)
  290. res := s.Action.Store(session, dt[0], dt[1], uid)
  291. if res.Type == SUCCESS {
  292. showSucc(session, res.Message, nub)
  293. } else if res.Type == BAD {
  294. showBad(session, res.Message, nub)
  295. } else {
  296. showNo(session, res.Message, nub)
  297. }
  298. }
  299. }
  300. func (s *Server) cclose(session *Session, args string, nub string, conn net.Conn, reader *bufio.Reader) {
  301. res := s.Action.Close(session)
  302. if res.Type == SUCCESS {
  303. showSucc(session, res.Message, nub)
  304. } else if res.Type == BAD {
  305. showBad(session, res.Message, nub)
  306. } else {
  307. showNo(session, res.Message, nub)
  308. }
  309. }
  310. func (s *Server) expunge(session *Session, args string, nub string, conn net.Conn, reader *bufio.Reader) {
  311. if session.Status != AUTHORIZED {
  312. showBad(session, "Need Login", nub)
  313. return
  314. }
  315. res := s.Action.Expunge(session)
  316. if res.Type == SUCCESS {
  317. showSucc(session, res.Message, nub)
  318. } else if res.Type == BAD {
  319. showBad(session, res.Message, nub)
  320. } else {
  321. showNo(session, res.Message, nub)
  322. }
  323. }
  324. func (s *Server) examine(session *Session, args string, nub string, conn net.Conn, reader *bufio.Reader) {
  325. if session.Status != AUTHORIZED {
  326. showBad(session, "Need Login", nub)
  327. return
  328. }
  329. if args == "" {
  330. paramsErr(session, "EXAMINE", nub)
  331. }
  332. res := s.Action.Examine(session, args)
  333. if res.Type == SUCCESS {
  334. showSucc(session, res.Message, nub)
  335. } else if res.Type == BAD {
  336. showBad(session, res.Message, nub)
  337. } else {
  338. showNo(session, res.Message, nub)
  339. }
  340. }
  341. func (s *Server) unsubscribe(session *Session, args string, nub string, conn net.Conn, reader *bufio.Reader) {
  342. if session.Status != AUTHORIZED {
  343. showBad(session, "Need Login", nub)
  344. return
  345. }
  346. if args == "" {
  347. paramsErr(session, "UNSUBSCRIBE", nub)
  348. } else {
  349. res := s.Action.UnSubscribe(session, args)
  350. if res.Type == SUCCESS {
  351. showSucc(session, res.Message, nub)
  352. } else if res.Type == BAD {
  353. showBad(session, res.Message, nub)
  354. } else {
  355. showNo(session, res.Message, nub)
  356. }
  357. }
  358. }
  359. func (s *Server) lsub(session *Session, args string, nub string, conn net.Conn, reader *bufio.Reader) {
  360. if session.Status != AUTHORIZED {
  361. showBad(session, "Need Login", nub)
  362. return
  363. }
  364. if args == "" {
  365. paramsErr(session, "LSUB", nub)
  366. } else {
  367. dt := strings.Split(args, " ")
  368. dt[0] = strings.Trim(dt[0], `"`)
  369. res := s.Action.LSub(session, dt[0], dt[1])
  370. if res.Type == SUCCESS {
  371. showSuccWithData(session, res.Data, res.Message, nub)
  372. } else if res.Type == BAD {
  373. showBad(session, res.Message, nub)
  374. } else {
  375. showNo(session, res.Message, nub)
  376. }
  377. }
  378. }
  379. func (s *Server) status(session *Session, args string, nub string, conn net.Conn, reader *bufio.Reader) {
  380. if session.Status != AUTHORIZED {
  381. showBad(session, "Need Login", nub)
  382. return
  383. }
  384. if args == "" {
  385. paramsErr(session, "STATUS", nub)
  386. } else {
  387. var mailBox string
  388. var params []string
  389. if strings.HasPrefix(args, `"`) {
  390. dt := strings.Split(args, `"`)
  391. if len(dt) >= 3 {
  392. mailBox = dt[1]
  393. }
  394. dt[2] = strings.Trim(dt[2], "() ")
  395. params = strings.Split(dt[2], " ")
  396. } else {
  397. dt := strings.SplitN(args, " ", 2)
  398. dt[0] = strings.ReplaceAll(dt[0], `"`, "")
  399. dt[1] = strings.Trim(dt[1], "()")
  400. mailBox = dt[0]
  401. params = strings.Split(dt[1], " ")
  402. }
  403. res := s.Action.Status(session, mailBox, params)
  404. if res.Type == SUCCESS {
  405. showSuccWithData(session, res.Data, res.Message, nub)
  406. } else if res.Type == BAD {
  407. showBad(session, res.Message, nub)
  408. } else {
  409. showNo(session, res.Message, nub)
  410. }
  411. }
  412. }
  413. func (s *Server) check(session *Session, args string, nub string, conn net.Conn, reader *bufio.Reader) {
  414. if session.Status != AUTHORIZED {
  415. showBad(session, "Need Login", nub)
  416. return
  417. }
  418. res := s.Action.Check(session)
  419. if res.Type == SUCCESS {
  420. showSucc(session, res.Message, nub)
  421. } else if res.Type == BAD {
  422. showBad(session, res.Message, nub)
  423. } else {
  424. showNo(session, res.Message, nub)
  425. }
  426. }
  427. func (s *Server) search(session *Session, args string, nub string, conn net.Conn, reader *bufio.Reader, uid bool) {
  428. if session.Status != AUTHORIZED {
  429. showBad(session, "Need Login", nub)
  430. return
  431. }
  432. if args == "" {
  433. paramsErr(session, "SEARCH", nub)
  434. } else {
  435. var res CommandResponse
  436. if args == "ALL" {
  437. res = s.Action.Search(session, "", "UID 1:*", uid)
  438. } else {
  439. res = s.Action.Search(session, "", args, uid)
  440. }
  441. if res.Type == SUCCESS {
  442. content := "* SEARCH"
  443. for _, datum := range res.Data {
  444. content += " " + datum
  445. }
  446. content += eol
  447. content += fmt.Sprintf("%s OK SEARCH completed (Success)%s", nub, eol)
  448. write(session, content, nub)
  449. } else if res.Type == BAD {
  450. showBad(session, res.Message, nub)
  451. } else {
  452. showNo(session, res.Message, nub)
  453. }
  454. }
  455. }
  456. func (s *Server) copy(session *Session, args string, nub string, conn net.Conn, reader *bufio.Reader) {
  457. if session.Status != AUTHORIZED {
  458. showBad(session, "Need Login", nub)
  459. return
  460. }
  461. if args == "" {
  462. paramsErr(session, "COPY", nub)
  463. } else {
  464. dt := strings.SplitN(args, " ", 2)
  465. res := s.Action.Copy(session, dt[0], dt[1])
  466. if res.Type == SUCCESS {
  467. showSucc(session, res.Message, nub)
  468. } else if res.Type == BAD {
  469. showBad(session, res.Message, nub)
  470. } else {
  471. showNo(session, res.Message, nub)
  472. }
  473. }
  474. }
  475. func (s *Server) noop(session *Session, args string, nub string, conn net.Conn, reader *bufio.Reader) {
  476. res := s.Action.Noop(session)
  477. if res.Type == SUCCESS {
  478. showSucc(session, res.Message, nub)
  479. } else if res.Type == BAD {
  480. showBad(session, res.Message, nub)
  481. } else {
  482. showNo(session, res.Message, nub)
  483. }
  484. }
  485. func (s *Server) login(session *Session, args string, nub string, conn net.Conn, reader *bufio.Reader) {
  486. if args == "" {
  487. paramsErr(session, "LOGIN", nub)
  488. } else {
  489. dt := strings.SplitN(args, " ", 2)
  490. res := s.Action.Login(session, strings.Trim(dt[0], `"`), strings.Trim(dt[1], `"`))
  491. if res.Type == SUCCESS {
  492. showSucc(session, res.Message, nub)
  493. } else if res.Type == BAD {
  494. showBad(session, res.Message, nub)
  495. } else {
  496. showNo(session, res.Message, nub)
  497. }
  498. }
  499. }
  500. func (s *Server) logout(session *Session, args string, nub string, conn net.Conn, reader *bufio.Reader) {
  501. res := s.Action.Logout(session)
  502. write(session, "* BYE PMail Server logging out"+eol, nub)
  503. if res.Type == SUCCESS {
  504. showSucc(session, res.Message, nub)
  505. } else if res.Type == BAD {
  506. showBad(session, res.Message, nub)
  507. } else {
  508. showNo(session, res.Message, nub)
  509. }
  510. if conn != nil {
  511. _ = conn.Close()
  512. }
  513. }
  514. func (s *Server) unselect(session *Session, args string, nub string, conn net.Conn, reader *bufio.Reader) {
  515. if session.Status != AUTHORIZED {
  516. showBad(session, "Need Login", nub)
  517. return
  518. }
  519. res := s.Action.Unselect(session)
  520. if res.Type == SUCCESS {
  521. showSucc(session, res.Message, nub)
  522. } else if res.Type == BAD {
  523. showBad(session, res.Message, nub)
  524. } else {
  525. showNo(session, res.Message, nub)
  526. }
  527. }
  528. func (s *Server) subscribe(session *Session, args string, nub string, conn net.Conn, reader *bufio.Reader) {
  529. if session.Status != AUTHORIZED {
  530. showBad(session, "Need Login", nub)
  531. return
  532. }
  533. if args == "" {
  534. paramsErr(session, "SUBSCRIBE", nub)
  535. } else {
  536. res := s.Action.Subscribe(session, args)
  537. if res.Type == SUCCESS {
  538. showSucc(session, res.Message, nub)
  539. } else if res.Type == BAD {
  540. showBad(session, res.Message, nub)
  541. } else {
  542. showNo(session, res.Message, nub)
  543. }
  544. }
  545. }
  546. func (s *Server) idle(session *Session, args string, nub string, conn net.Conn, reader *bufio.Reader) {
  547. if session.Status != AUTHORIZED {
  548. showBad(session, "Need Login", nub)
  549. return
  550. }
  551. session.IN_IDLE = true
  552. res := s.Action.IDLE(session)
  553. if res.Type == SUCCESS {
  554. write(session, "+ idling"+eol, nub)
  555. } else if res.Type == BAD {
  556. showBad(session, res.Message, nub)
  557. } else {
  558. showNo(session, res.Message, nub)
  559. }
  560. }
  561. func (s *Server) custom(session *Session, cmd string, args string, nub string, conn net.Conn, reader *bufio.Reader) {
  562. res := s.Action.Custom(session, cmd, args)
  563. if res.Type == BAD {
  564. write(session, fmt.Sprintf("* BAD %s %s", res.Message, eol), nub)
  565. } else if res.Type == NO {
  566. showNo(session, res.Message, nub)
  567. } else {
  568. if len(res.Data) == 0 {
  569. showSucc(session, res.Message, nub)
  570. } else {
  571. ret := ""
  572. for _, re := range res.Data {
  573. ret += fmt.Sprintf("%s%s", re, eol)
  574. }
  575. ret += "." + eol
  576. write(session, fmt.Sprintf(ret), nub)
  577. }
  578. }
  579. }
  580. func (s *Server) doCommand(session *Session, rawLine string, conn net.Conn, reader *bufio.Reader) {
  581. nub, cmd, args := getCommand(rawLine)
  582. log.WithContext(session.Ctx).Debugf("Imap Input:\t %s", rawLine)
  583. if cmd != "IDLE" {
  584. session.IN_IDLE = false
  585. }
  586. switch cmd {
  587. case "":
  588. if conn != nil {
  589. conn.Close()
  590. conn = nil
  591. }
  592. break
  593. case "AUTHENTICATE":
  594. s.authenticate(session, args, nub, conn, reader)
  595. case "CAPABILITY":
  596. s.capability(session, rawLine, nub, conn, reader)
  597. case "CREATE":
  598. s.create(session, args, nub, conn, reader)
  599. case "DELETE":
  600. s.delete(session, args, nub, conn, reader)
  601. case "RENAME":
  602. s.rename(session, args, nub, conn, reader)
  603. case "LIST":
  604. s.list(session, args, nub, conn, reader)
  605. case "APPEND":
  606. s.append(session, args, nub, conn, reader)
  607. case "SELECT":
  608. s.cselect(session, args, nub, conn, reader)
  609. case "FETCH":
  610. s.fetch(session, args, nub, conn, reader, false)
  611. case "UID FETCH":
  612. s.fetch(session, args, nub, conn, reader, true)
  613. case "STORE":
  614. s.store(session, args, nub, conn, reader, false)
  615. case "UID STORE":
  616. s.store(session, args, nub, conn, reader, true)
  617. case "CLOSE":
  618. s.cclose(session, args, nub, conn, reader)
  619. case "EXPUNGE":
  620. s.expunge(session, args, nub, conn, reader)
  621. case "EXAMINE":
  622. s.examine(session, args, nub, conn, reader)
  623. case "SUBSCRIBE":
  624. s.subscribe(session, args, nub, conn, reader)
  625. case "UNSUBSCRIBE":
  626. s.unsubscribe(session, args, nub, conn, reader)
  627. case "LSUB":
  628. s.lsub(session, args, nub, conn, reader)
  629. case "STATUS":
  630. s.status(session, args, nub, conn, reader)
  631. case "CHECK":
  632. s.check(session, args, nub, conn, reader)
  633. case "SEARCH":
  634. s.search(session, args, nub, conn, reader, false)
  635. case "UID SEARCH":
  636. s.search(session, args, nub, conn, reader, true)
  637. case "COPY":
  638. s.copy(session, args, nub, conn, reader)
  639. case "NOOP":
  640. s.noop(session, args, nub, conn, reader)
  641. case "LOGIN":
  642. s.login(session, args, nub, conn, reader)
  643. case "LOGOUT":
  644. s.logout(session, args, nub, conn, reader)
  645. case "UNSELECT":
  646. s.unselect(session, args, nub, conn, reader)
  647. case "IDLE":
  648. s.idle(session, args, nub, conn, reader)
  649. default:
  650. s.custom(session, cmd, args, nub, conn, reader)
  651. }
  652. }
  653. func (s *Server) handleClient(conn net.Conn) {
  654. defer func() {
  655. if conn != nil {
  656. _ = conn.Close()
  657. }
  658. }()
  659. session := &Session{
  660. Conn: conn,
  661. Status: UNAUTHORIZED,
  662. AliveTime: time.Now(),
  663. }
  664. tc := &context.Context{}
  665. tc.SetValue(context.LogID, id.GenLogID())
  666. session.Ctx = tc
  667. if s.TlsEnabled && s.TlsConfig != nil {
  668. session.InTls = true
  669. }
  670. // 检查连接是否超时
  671. if s.ConnectAliveTime != 0 {
  672. go func() {
  673. for {
  674. if time.Now().Sub(session.AliveTime) >= s.ConnectAliveTime {
  675. if session.Conn != nil {
  676. write(session, "* BYE AutoLogout; idle for too long", "")
  677. _ = session.Conn.Close()
  678. }
  679. session.Conn = nil
  680. session.IN_IDLE = false
  681. return
  682. }
  683. time.Sleep(3 * time.Second)
  684. }
  685. }()
  686. }
  687. reader := bufio.NewReader(conn)
  688. write(session, fmt.Sprintf(`* OK [CAPABILITY IMAP4 IMAP4rev1 AUTH=LOGIN] PMail Server ready%s`, eol), "")
  689. for {
  690. rawLine, err := reader.ReadString('\n')
  691. if err != nil {
  692. if conn != nil {
  693. _ = conn.Close()
  694. }
  695. session.Conn = nil
  696. session.IN_IDLE = false
  697. return
  698. }
  699. session.AliveTime = time.Now()
  700. s.doCommand(session, rawLine, conn, reader)
  701. }
  702. }
  703. // cuts the line into command and arguments
  704. func getCommand(line string) (string, string, string) {
  705. line = strings.Trim(line, "\r \n")
  706. cmd := strings.SplitN(line, " ", 3)
  707. if len(cmd) == 1 {
  708. return "", "", ""
  709. }
  710. if len(cmd) == 3 {
  711. if strings.ToTitle(cmd[1]) == "UID" {
  712. args := strings.SplitN(cmd[2], " ", 2)
  713. if len(args) >= 2 {
  714. return cmd[0], strings.ToTitle(cmd[1]) + " " + strings.ToTitle(args[0]), args[1]
  715. }
  716. }
  717. return cmd[0], strings.ToTitle(cmd[1]), cmd[2]
  718. }
  719. return cmd[0], strings.ToTitle(cmd[1]), ""
  720. }
  721. func getSafeArg(args []string, nr int) string {
  722. if nr < len(args) {
  723. return args[nr]
  724. }
  725. return ""
  726. }
  727. func showSucc(s *Session, msg, nub string) {
  728. if msg == "" {
  729. write(s, fmt.Sprintf("%s OK success %s", nub, eol), nub)
  730. } else {
  731. write(s, fmt.Sprintf("%s %s %s", nub, msg, eol), nub)
  732. }
  733. }
  734. func showSuccWithData(s *Session, data []string, msg string, nub string) {
  735. content := ""
  736. for _, datum := range data {
  737. content += fmt.Sprintf("%s%s", datum, eol)
  738. }
  739. content += fmt.Sprintf("%s OK %s%s", nub, msg, eol)
  740. write(s, content, nub)
  741. }
  742. func showBad(s *Session, err string, nub string) {
  743. if nub == "" {
  744. nub = "*"
  745. }
  746. if err == "" {
  747. write(s, fmt.Sprintf("%s BAD %s", nub, eol), nub)
  748. return
  749. }
  750. write(s, fmt.Sprintf("%s BAD %s%s", nub, err, eol), nub)
  751. }
  752. func showNo(s *Session, msg string, nub string) {
  753. write(s, fmt.Sprintf("%s NO %s%s", nub, msg, eol), nub)
  754. }
  755. func paramsErr(session *Session, commend string, nub string) {
  756. write(session, fmt.Sprintf("* BAD %s parameters! %s", commend, eol), nub)
  757. }
  758. func write(session *Session, content string, nub string) {
  759. if !strings.HasSuffix(content, eol) {
  760. log.WithContext(session.Ctx).Errorf("Error:返回结尾错误 %s", content)
  761. }
  762. log.WithContext(session.Ctx).Debugf("Imap Out:\t |%s", content)
  763. fmt.Fprintf(session.Conn, content)
  764. }