How to use move method of imap Package

Best Venom code snippet using imap.move

client.go

Source:client.go Github

copy

Full Screen

...3// goimapsync main module, it implements the following actions:4// - "sync" mails from local maildir to IMAP5// - "fetch-new" new mails from IMAP to local maildir folder6// - "fetch-all" all mails from IMAP to local maildir folder7// - "move" mail(s) on IMAP server to given folder and message id8import (9 "bufio"10 "crypto/md5"11 "database/sql"12 "encoding/hex"13 "flag"14 "fmt"15 "io"16 "io/ioutil"17 "log"18 "net/mail"19 "os"20 "runtime"21 "strings"22 "sync"23 "time"24 imap "github.com/emersion/go-imap"25 "github.com/emersion/go-imap/client"26)27// global variable to keep pointer to mdb28var mdb *sql.DB29// version of the code30var gitVersion, gitTag string31// Info function returns version string of the server32func info() string {33 goVersion := runtime.Version()34 tstamp := time.Now().Format("2006-02-01")35 return fmt.Sprintf("gpm git=%s tag=%s go=%s date=%s", gitVersion, gitTag, goVersion, tstamp)36}37// global variables we use across the code38var imapFolders map[string][]string39var hostname string40// Message structure holds all information about emails message41type Message struct {42 Path string // location of the message in local file dir43 MessageId string // message Id44 Flags []string // message Flags45 Imap string // name of imap server it belongs to46 Subject string // message subject47 SeqNumber uint32 // message sequence number48 HashId string // message id md5 hash49}50// String function dumps Message info51func (m *Message) String() string {52 return fmt.Sprintf("<Imap:%s SeqNum:%v HashId:%v Path:%s MessageId:%s Flags:%v Subject: %s>", m.Imap, m.SeqNumber, m.HashId, m.Path, m.MessageId, m.Flags, m.Subject)53}54// ServerClient structure which holds IMAP server alias name and connection pointer55type ServerClient struct {56 Name string // name of IMAP server57 Client *client.Client // connected client to IMAP server58}59// helper function which extracts flags from given email file name60func getFlags(fname string) []string {61 // example of file name in our Inbox62 // <tstamp.id.hostname:2,flags>63 if strings.Contains(fname, ",") {64 arr := strings.Split(fname, ",")65 flags := arr[len(arr)-1]66 return strings.Split(flags, "")67 }68 return []string{}69}70// helper function which extracts message id from given email file71func getMessageId(fname string) string {72 file, err := os.Open(fname)73 if err != nil {74 log.Fatal(err)75 }76 defer file.Close()77 scanner := bufio.NewScanner(file)78 for scanner.Scan() {79 line := scanner.Text()80 if strings.HasPrefix(strings.ToLower(scanner.Text()), "message-id:") {81 arr := strings.Split(line, ":")82 if len(arr) > 0 {83 return strings.Trim(arr[1], " ")84 }85 }86 }87 return ""88}89// helper function to connect to our IMAP servers90func connect() map[string]*client.Client {91 defer timing("connect", time.Now())92 defer profiler("connect")()93 cmap := make(map[string]*client.Client)94 ch := make(chan ServerClient, len(Config.Servers))95 defer close(ch)96 for _, srv := range Config.Servers {97 go func(s Server) {98 var c *client.Client99 var err error100 if s.UseTls {101 c, err = client.DialTLS(s.Uri, nil)102 } else {103 c, err = client.Dial(s.Uri)104 }105 if err != nil {106 log.Fatal(err)107 }108 if err := c.Login(s.Username, s.Password); err != nil {109 log.Fatal(err)110 }111 if Config.Verbose > 0 {112 log.Println("Logged into", s.Uri)113 }114 ch <- ServerClient{Name: s.Name, Client: c}115 }(srv)116 }117 for i := 0; i < len(Config.Servers); i++ {118 s := <-ch119 cmap[s.Name] = s.Client120 }121 return cmap122}123// helper function to logout from all IMAP clients124func logout(cmap map[string]*client.Client) {125 for _, c := range cmap {126 c.Logout()127 }128}129// helper function which takes a snapshot of remote IMAP servers130// and return list of messages131func readImap(c *client.Client, imapName, folder string, newMessages bool) []Message {132 defer timing("readImap", time.Now())133 defer profiler("readImap")()134 // Select given imap folder135 mbox, err := c.Select(folder, false)136 if err != nil {137 log.Printf("Folder '%s' on '%s', error: %v\n", folder, imapName, err)138 return []Message{}139 }140 // get messages141 seqset := new(imap.SeqSet)142 var nmsg uint32143 if newMessages {144 // get only new messages145 criteria := imap.NewSearchCriteria()146 criteria.WithoutFlags = []string{imap.SeenFlag}147 ids, err := c.Search(criteria)148 if err != nil {149 log.Fatal(err)150 }151 if len(ids) > 0 {152 seqset.AddNum(ids...)153 nmsg = uint32(len(ids))154 log.Printf("Found %d new message(s) in folder '%s' on '%s'\n", nmsg, folder, imapName)155 } else {156 log.Printf("No new messages in folder '%s' on '%s'\n", folder, imapName)157 return []Message{}158 }159 } else {160 // get all messages from mailbox161 from := uint32(1)162 to := mbox.Messages163 seqset.AddRange(from, to)164 nmsg = to165 }166 // section will be used only in writeContent167 section := &imap.BodySectionName{}168 messages := make(chan *imap.Message, nmsg)169 items := []imap.FetchItem{section.FetchItem(), imap.FetchFlags, imap.FetchEnvelope}170 // TODO: use goroutine until this issue will be solved171 // https://github.com/emersion/go-imap/issues/382172 done := make(chan error, 1)173 go func() {174 done <- c.Fetch(seqset, items, messages)175 }()176 // err = c.Fetch(seqset, items, messages)177 // if err != nil {178 // log.Fatal(err)179 // }180 seqNum := uint32(1)181 var msgs []Message182 var wg sync.WaitGroup183 for msg := range messages {184 var m Message185 if msg == nil || msg.Envelope == nil {186 continue187 }188 mid := msg.Envelope.MessageId189 sub := msg.Envelope.Subject190 hid := md5hash(mid)191 flags := msg.Flags192 m = Message{MessageId: mid, Flags: flags, Imap: imapName, Subject: sub, SeqNumber: seqNum, HashId: hid}193 if mid == "" || hid == "" {194 log.Printf("read empty mail %s %v out of %v from %s\n", m.String(), seqNum, nmsg, imapName)195 continue196 }197 log.Printf("read %s %v out of %v from %s\n", m.String(), seqNum, nmsg, imapName)198 r := msg.GetBody(section)199 entry, e := findMessage(hid)200 if Config.Verbose > 1 {201 log.Println("hid", hid, "DB entry", entry.String(), e)202 }203 if e == nil && entry.HashId == hid {204 if Config.Verbose > 0 {205 log.Println("Mail with hash", hid, "already exists")206 }207 } else {208 if newMessages {209 m.Flags = append(m.Flags, imap.RecentFlag)210 }211 if !isMailWritten(m) {212 wg.Add(1)213 go writeMail(imapName, folder, m, r, &wg)214 } else {215 // check if mail is presented in our DB, if not we should insert its entry216 msg, e := findMessage(m.HashId)217 if e == nil && msg.HashId == "" {218 m.Path = findPath(m.Imap, m.HashId)219 insertMessage(m)220 }221 }222 }223 msgs = append(msgs, m)224 seqNum += 1225 }226 wg.Wait()227 return msgs228}229// helper function to find message path in local maildir230func findPath(imapName, hid string) string {231 var mdict map[string]string232 if Config.CommonInbox {233 mdict = readMaildir("", "INBOX")234 } else {235 for k, v := range readMaildir(imapName, "INBOX") {236 mdict[k] = v237 }238 }239 if path, ok := mdict[hid]; ok {240 return path241 }242 return ""243}244// helper function to check if mail was previously written in local maildir245func isMailWritten(m Message) bool {246 var mdict map[string]string247 if Config.CommonInbox {248 mdict = readMaildir("", "INBOX")249 } else {250 for k, v := range readMaildir(m.Imap, "INBOX") {251 mdict[k] = v252 }253 }254 for hid := range mdict {255 if hid == m.HashId {256 return true257 }258 }259 return false260}261// helper function to create an md5 hash of given message Id262func md5hash(mid string) string {263 h := md5.New()264 h.Write([]byte(mid))265 return hex.EncodeToString(h.Sum(nil))266}267// helper function to create maildir map of existing mails268func readMaildir(imapName, folder string) map[string]string {269 // when writing to local mail dir the folder name should not cotain slashes270 // replace slash with dot271 folder = strings.Replace(folder, "/", ".", -1)272 // create proper dir structure in maildir area273 var dirs = []string{"cur", "new", "tmp"}274 fdir := localFolder(imapName, folder)275 for _, d := range dirs {276 fpath := fmt.Sprintf("%s/%s/%s", Config.Maildir, fdir, d)277 os.MkdirAll(fpath, os.ModePerm)278 }279 if Config.Verbose > 0 {280 log.Println("Read local mails from", fmt.Sprintf("%s/%s", Config.Maildir, fdir))281 }282 // create mail dict which we'll return upstream283 mdict := make(map[string]string)284 // each file in maildir has format: <tstamp.hid.hostname:2,flags>285 for _, d := range dirs {286 root := fmt.Sprintf("%s/%s/%s", Config.Maildir, fdir, d)287 files, err := ioutil.ReadDir(root)288 if err != nil {289 log.Println("Error reading", root, err)290 continue291 }292 for _, f := range files {293 fname := fmt.Sprintf("%s/%s", root, f.Name())294 arr := strings.Split(fname, ".")295 mdict[arr[1]] = fname296 }297 }298 return mdict299}300// helper to get local maildir folder301func localFolder(imapName, folder string) string {302 if imapName == "" {303 return folder304 } else if strings.ToLower(folder) == "inbox" && Config.CommonInbox {305 return folder306 }307 return fmt.Sprintf("%s/%s", imapName, folder)308}309// helper function to return short flag names310func flagSymbols(flags []string) string {311 var flag string312 for _, f := range flags {313 f = strings.ToLower(strings.Replace(f, "\\", "", -1))314 if f == "seen" {315 f = "S"316 } else if f == "recent" {317 f = "N"318 } else if f == "answered" {319 f = "A"320 } else if f == "junk" {321 f = "J"322 } else {323 continue324 }325 flag = fmt.Sprintf("%s%s", flag, f)326 }327 if flag == "" {328 flag = "S"329 }330 return flag331}332// helper function to write emails in imapName folder of local maildir333func writeMail(imapName, folder string, m Message, r io.Reader, wg *sync.WaitGroup) {334 hid := m.HashId // hash id of the message id335 flags := m.Flags // message flags336 defer timing("writeMail", time.Now())337 defer profiler("writeMail")()338 defer wg.Done()339 // construct file name with the following format:340 // tstamp.hid.hostname:2,flags341 tstamp := time.Now().Unix()342 flag := flagSymbols(flags)343 if Config.Verbose > 0 {344 log.Println("writeMail", tstamp, hid, flags, flag)345 }346 fdir := localFolder(imapName, folder)347 fname := fmt.Sprintf("%d.%s.%s:2,%s", tstamp, hid, hostname, flag)348 fpath := fmt.Sprintf("%s/%s/cur/%s", Config.Maildir, fdir, fname)349 if strings.Contains(flag, "N") {350 fname = fmt.Sprintf("%d.%s.%s", tstamp, hid, hostname)351 fpath = fmt.Sprintf("%s/%s/new/%s", Config.Maildir, fdir, fname)352 }353 // check if our file exist354 if _, err := os.Stat(fpath); err == nil {355 if Config.Verbose > 0 {356 log.Println("File", fpath, "already exists")357 }358 return359 }360 // proceed and create a file with our email361 file, err := os.Create(fpath)362 if err != nil {363 log.Println("unable to open", fpath, err)364 return365 }366 defer file.Close()367 msg, err := mail.ReadMessage(r)368 if err != nil {369 log.Println("Unable to read a message", err)370 return371 }372 // write headers373 for k, v := range msg.Header {374 line := fmt.Sprintf("%s: %s\n", k, strings.Join(v, " "))375 _, e := file.WriteString(line)376 if e != nil {377 log.Printf("unable to write '%s', error: %v\n", line, e)378 return379 }380 }381 // write body382 body, err := ioutil.ReadAll(msg.Body)383 if err == nil {384 _, e := file.Write(body)385 if e != nil {386 log.Println("unable to write msg body, error", e)387 return388 }389 }390 // write message info into DB391 m.Path = fpath392 err = insertMessage(m)393 if err != nil {394 log.Fatal("message was written to file-system but not in DB, error: ", err)395 }396}397// helper function to get list of all imap folders398func getImapFolders(c *client.Client, imapName string) []string {399 // List mailboxes400 mailboxes := make(chan *imap.MailboxInfo, 10)401 done := make(chan error, 1)402 go func() {403 done <- c.List("", "*", mailboxes)404 }()405 var folders []string406 for m := range mailboxes {407 folders = append(folders, m.Name)408 }409 if err := <-done; err != nil {410 log.Fatal(err)411 }412 return folders413}414// helper function to get folder name for given IMAP server415func imapFolder(imapName, folder string) string {416 // if no folder is given, we'll immediately return417 if folder == "" {418 return folder419 }420 folders := imapFolders[imapName]421 for _, f := range folders {422 if strings.ToLower(f) == strings.ToLower(folder) {423 return f424 }425 }426 // defaults427 if strings.ToLower(folder) == "inbox" {428 return "INBOX"429 }430 if strings.ToLower(folder) == "spam" {431 return "Spam"432 }433 // at this point we should through an error434 log.Fatalf("No folder '%s' found in imap '%s' folder list '%v'\n", folder, imapName, folders)435 return ""436}437// MoveMessage moves message in given imap server into specifc folder438func MoveMessage(c *client.Client, imapName string, msg Message, folderName string) {439 defer timing("MoveMessage", time.Now())440 defer profiler("MoveMessage")()441 // inbox folder442 inboxFolder := imapFolder(imapName, "inbox")443 folder := imapFolder(imapName, folderName)444 seqset := new(imap.SeqSet)445 seqset.AddNum(msg.SeqNumber)446 // connect to given Spam folder447 _, err := c.Select(inboxFolder, false)448 if err != nil {449 log.Fatal(err)450 }451 if folder == "" {452 log.Printf("delete %v\n", msg.String())453 } else {454 log.Printf("move %v to '%s' on %s\n", msg.MessageId, folder, imapName)455 }456 // copy mail to folder457 if folder != "" {458 // mark mail as seen in our inbox459 item := imap.FormatFlagsOp(imap.AddFlags, true)460 flags := []interface{}{imap.SeenFlag}461 if err := c.Store(seqset, item, flags, nil); err != nil {462 log.Fatal(err)463 }464 if err := c.Copy(seqset, folder); err != nil {465 log.Fatal(err)466 }467 }468 // mark mail as deleted on IMAP server469 item := imap.FormatFlagsOp(imap.AddFlags, true)470 flags := []interface{}{imap.DeletedFlag}471 if err := c.Store(seqset, item, flags, nil); err != nil {472 log.Fatal(err)473 }474 // then delete it in inbox folder475 if err := c.Expunge(nil); err != nil {476 log.Fatal(err)477 }478}479// Move message on IMAP to a given folder, if folder name is not given the mail480// will be deleted481func Move(c *client.Client, imapName, match, folderName string) {482 if folderName == "" || match == "" {483 log.Fatal("Move operation requires both folder and message id")484 }485 defer timing("Move", time.Now())486 defer profiler("Move")()487 // inbox folder488 inboxFolder := imapFolder(imapName, "inbox")489 folder := imapFolder(imapName, folderName)490 // check if given match is existing file, if so we'll491 // extract from it MatchedId492 if _, err := os.Stat(match); err == nil {493 match = getMessageId(match)494 }495 // Select INBOX496 mbox, err := c.Select(inboxFolder, false)497 if err != nil {498 log.Fatal(err)499 }500 // Get messages from INBOX501 from := uint32(1)502 to := mbox.Messages503 seqset := new(imap.SeqSet)504 seqset.AddRange(from, to)505 if Config.Verbose > 0 {506 log.Println("Fetch from IMAP", imapName, folderName, from, to)507 }508 messages := make(chan *imap.Message, to)509 items := []imap.FetchItem{imap.FetchFlags, imap.FetchUid, imap.FetchEnvelope}510 // TODO: use goroutine until this issue will be solved511 // https://github.com/emersion/go-imap/issues/382512 done := make(chan error, 1)513 go func() {514 done <- c.Fetch(seqset, items, messages)515 }()516 // err = c.Fetch(seqset, items, messages)517 // if err != nil {518 // log.Fatal(err)519 // }520 seqNum := uint32(1)521 for msg := range messages {522 if Config.Verbose > 1 {523 log.Println("* "+msg.Envelope.Subject+" MessageId ", msg.Envelope.MessageId)524 }525 if msg.Envelope.MessageId == match {526 if Config.Verbose > 0 {527 log.Printf("Found match: seq:%v Envelope: %+v Flags: %+v\n", seqNum, msg.Envelope, msg.Flags)528 }529 mid := msg.Envelope.MessageId530 hid := md5hash(mid)531 sub := msg.Envelope.Subject532 flags := msg.Flags533 m := Message{HashId: hid, MessageId: mid, Flags: flags, Imap: imapName, Subject: sub, SeqNumber: seqNum}534 MoveMessage(c, imapName, m, folder)535 return536 }537 seqNum += 1538 }539}540// Fetch content of given folder from IMAP into local maildir541func Fetch(c *client.Client, imapName, folder string, newMessages bool) {542 defer timing("Fetch", time.Now())543 defer profiler("Fetch")()544 log.Printf("Fetch %s from %s\n", folder, imapName)545 for _, m := range readImap(c, imapName, folder, newMessages) {546 if Config.Verbose > 0 {547 log.Println("fetch", m.String())548 }549 }550}551// Sync provides sync between local maildir and IMAP servers552func Sync(cmap map[string]*client.Client, dryRun bool) {553 defer timing("Sync", time.Now())554 defer profiler("Sync")()555 var mlist []Message556 for imapName, c := range cmap {557 // read new messages from IMAP558 newMessages := true559 log.Println("### read new messages on", imapName)560 for _, m := range readImap(c, imapName, "INBOX", newMessages) {561 if Config.Verbose > 0 {562 log.Println("Read new message", m.String())563 }564 }565 // read all messages from IMAP, since we may miss some of them566 // in local maildir if those were read on another device(s)567 // this step will ensure that we get local copies of non-new messages568 log.Println("### read all messages on", imapName)569 newMessages = false570 for _, msg := range readImap(c, imapName, "INBOX", newMessages) {571 mlist = append(mlist, msg)572 }573 }574 // get local maildir snapshot575 log.Println("### read local maildir")576 var mdict map[string]string577 if Config.CommonInbox {578 mdict = readMaildir("", "INBOX")579 } else {580 for name := range cmap {581 for k, v := range readMaildir(name, "INBOX") {582 mdict[k] = v583 }584 }585 }586 // now loop over messages we got from IMAP and compare with our local maildir587 // then we collect message ids for deletion588 var dlist []Message589 for _, msg := range mlist {590 // check if our message exists in DB591 m, e := findMessage(msg.HashId)592 if e == nil && m.HashId == msg.HashId {593 // we found message in DB, check if it exists in local maildir594 if _, ok := mdict[m.HashId]; !ok {595 // message is not found in local maildir and we need to delete it596 if dryRun {597 log.Println("dry-run expunge", msg.String())598 } else {599 dlist = append(dlist, msg)600 }601 }602 }603 }604 if !dryRun {605 removeImapMessages(cmap, dlist)606 }607}608// helper function to remove messages in IMAP server(s)609// it takes list of messages610func removeImapMessages(cmap map[string]*client.Client, mlist []Message) {611 defer timing("removeImapMessages", time.Now())612 defer profiler("removeImapMessages")()613 if Config.Verbose > 0 {614 log.Println("removeImapMessages", mlist)615 }616 for imapName, c := range cmap {617 // select messages from IMAP inbox folder618 inboxFolder := imapFolder(imapName, "inbox")619 _, err := c.Select(inboxFolder, false)620 if err != nil {621 log.Fatal(err)622 }623 // get list of message seq numbers for our IMAP server624 var slist []uint32625 var hlist []string626 for _, m := range mlist {627 if m.Imap == imapName {628 slist = append(slist, m.SeqNumber)629 hlist = append(hlist, m.HashId)630 }631 }632 seqset := new(imap.SeqSet)633 seqset.AddNum(slist...)634 if Config.Verbose > 0 {635 log.Printf("%s, remove seqset: %v\n", imapName, seqset)636 }637 if seqset.Empty() {638 continue639 }640 // now we mark messages for deletion in IMAP641 item := imap.FormatFlagsOp(imap.AddFlags, true)642 flags := []interface{}{imap.DeletedFlag}643 if err := c.Store(seqset, item, flags, nil); err != nil {644 log.Fatal(err)645 }646 // delete messages on IMAP server647 if err := c.Expunge(nil); err != nil {648 log.Fatal(err)649 }650 // delete messages in local maildir DB651 for _, hid := range hlist {652 deleteMessage(hid)653 }654 }655}656// helper function to report timing of given function657func timing(name string, start time.Time) {658 if Config.Verbose > 0 {659 log.Printf("Function '%s' elapsed time: %v\n", name, time.Since(start))660 } else if name == "main" {661 log.Printf("elapsed time: %v\n", time.Since(start))662 }663}664func main() {665 var config string666 flag.StringVar(&config, "config", os.Getenv("HOME")+"/.goimapsyncrc", "config JSON file")667 var dryRun bool668 flag.BoolVar(&dryRun, "dryRun", false, "perform dry-run")669 var mid string670 flag.StringVar(&mid, "mid", "", "mail file or messageid to use")671 var folder string672 flag.StringVar(&folder, "folder", "INBOX", "folder to use")673 var op string674 flag.StringVar(&op, "op", "sync", "perform given operation")675 var profiler string676 flag.StringVar(&profiler, "profiler", "", "profiler file name")677 var version bool678 flag.BoolVar(&version, "version", false, "Show version")679 var verbose int680 flag.IntVar(&verbose, "verbose", 0, "verbosity level")681 flag.Usage = func() {682 fmt.Println("Usage: goimapsync [options]")683 flag.PrintDefaults()684 fmt.Println("Supported operations:")685 fmt.Println(" fetch-new: to get list of new messages from specified IMAP folder")686 fmt.Println(" fetch-all: to get list of all messages from specified IMAP folder")687 fmt.Println(" move : to move givem message on IMAP server, e.g. send to Spam")688 fmt.Println(" sync : to sync local maildir with IMAP server(s)")689 fmt.Println("Examples:")690 fmt.Println(" # fetch new messages from given IMAP folder")691 fmt.Println(" goimapsync -config config.json -op=fetch-new -folder=MyFolder")692 fmt.Println(" # fetch all messages from given IMAP folder")693 fmt.Println(" goimapsync -config config.json -op=fetch-all -folder=MyFolder")694 fmt.Println(" # sync mails form local maildir to IMAP")695 fmt.Println(" goimapsync -config config.json -op=sync")696 fmt.Println(" # the same operation with encrypted (gpg) config")697 fmt.Println(" gpg -d -o - $HOME/.goimapsync.gpg | goimapsync -op=sync -config -")698 fmt.Println(" # sync mails form given IMAP folder into local maildir")699 fmt.Println(" gpg -d -o - $HOME/.goimapsync.gpg | goimapsync -config config.json -op=fetch -folder=MyFolder")700 fmt.Println(" # move given mail id in IMAP server to given folder")701 fmt.Println(" goimapsync -config config.json -op=move -mid=123 -folder=MyFolder")702 }703 flag.Parse()704 if version {705 fmt.Println(info())706 os.Exit(0)707 }708 ParseConfig(config)709 log.SetFlags(log.LstdFlags)710 // overwrite verbose level in config711 if verbose > 0 {712 Config.Verbose = verbose713 log.SetFlags(log.LstdFlags | log.Lshortfile)714 }715 if profiler != "" {716 Config.Profiler = profiler717 initProfiler(profiler)718 }719 // add timing profile720 defer timing("main", time.Now())721 // init imap folders map722 var err error723 imapFolders = make(map[string][]string)724 hostname, err = os.Hostname()725 if err != nil {726 log.Fatal(err)727 }728 // init our message db729 mdb, err = InitDB()730 if err != nil {731 log.Fatal(err)732 }733 // connect to our IMAP servers734 cmap := connect()735 defer logout(cmap)736 for imapName, c := range cmap {737 folders := getImapFolders(c, imapName)738 imapFolders[imapName] = folders739 if Config.Verbose > 0 {740 log.Println("IMAP", imapName, folders)741 }742 }743 switch op {744 case "move":745 // perform move action for given message id and IMAP folder746 for name, c := range cmap {747 Move(c, name, mid, folder)748 }749 case "fetch-new":750 // fetch new messages for given IMAP folder751 for name, c := range cmap {752 Fetch(c, name, folder, true)753 }754 case "fetch-all":755 // fetch all messages (old and new) for given IMAP folder756 for name, c := range cmap {757 Fetch(c, name, folder, false)758 }759 case "sync":...

Full Screen

Full Screen

imap.go

Source:imap.go Github

copy

Full Screen

...8 "github.com/CrawX/go-imap-assassin/domain"9 "github.com/CrawX/go-imap-assassin/log"10 "github.com/CrawX/go-imap-assassin/mail"11 "github.com/emersion/go-imap"12 "github.com/emersion/go-imap-move"13 "github.com/emersion/go-imap-uidplus"14 "github.com/emersion/go-imap/client"15 "github.com/sirupsen/logrus"16)17type ImapConnection struct {18 connection *client.Client19 mailDeleter deleter20 mailMover mover21 server, user, password string22 selectedFolder string23 l *logrus.Logger24}25func NewImapConnection(server string, user string, password string) (*ImapConnection, error) {26 imapClient, err := client.DialTLS(server, nil)27 if err != nil {28 return nil, fmt.Errorf("could not dial to imap: %w", err)29 }30 err = imapClient.Login(user, password)31 if err != nil {32 return nil, fmt.Errorf("could not login to imap: %w", err)33 }34 uidPlusClient := uidplus.NewClient(imapClient)35 uidPlusSupported, err := uidPlusClient.SupportUidPlus()36 if err != nil {37 return nil, fmt.Errorf("could not check for UIDPLUS support: %w", err)38 }39 moveClient := move.NewClient(imapClient)40 moveSupported, err := moveClient.SupportMove()41 if err != nil {42 return nil, fmt.Errorf("could not check for MOVE support: %w", err)43 }44 conn := &ImapConnection{45 connection: imapClient,46 server: server,47 user: user,48 password: password,49 l: log.Logger(log.LOG_IMAP),50 }51 baseLogger := conn.l.WithFields(logrus.Fields{"server": server})52 baseLogger.Debug("Logged in to server")53 if uidPlusSupported {54 baseLogger.Debug("UIDPLUS supported on server, using UID delete")55 conn.mailDeleter = &uidPlusDeleter{56 imapConn: struct {57 *ImapConnection58 *uidplus.Client59 }{60 conn, uidPlusClient,61 },62 }63 } else {64 baseLogger.Info("UIDPLUS not supported on server, falling back to flag&expunge")65 conn.mailDeleter = &compatibilityDeleter{66 imapConn: struct {67 *ImapConnection68 *client.Client69 }{70 conn, imapClient,71 },72 }73 }74 if moveSupported {75 baseLogger.Debug("MOVE supported on server")76 conn.mailMover = &moveMover{77 moveClient: moveClient,78 }79 } else {80 baseLogger.Info("MOVE not supported on server, falling back to copy&delete")81 if uidPlusSupported {82 baseLogger.Debug("UIDPLUS supported on server, using UID delete for copy")83 } else {84 baseLogger.Info("UIDPLUS not supported on server, falling back to flag&expunge for copy")85 }86 conn.mailMover = &compatibilityMover{87 imapConn: struct {88 deleter89 *client.Client90 }{91 conn.mailDeleter, imapClient,92 },93 }94 }95 return conn, nil96}97func (ic *ImapConnection) Select(folder string) (uint32, error) {98 m, err := ic.connection.Select(folder, false)99 if err != nil {100 return 0, fmt.Errorf("could not select folder: %w", err)101 }102 ic.selectedFolder = folder103 return m.UidValidity, nil104}105func (ic *ImapConnection) ListUids() ([]uint32, error) {106 // Get all UIDs in folder (empty search criteria)107 criteria := imap.NewSearchCriteria()108 ids, err := ic.connection.UidSearch(criteria)109 if err != nil {110 return nil, fmt.Errorf("could not list folder: %w", err)111 }112 return ids, nil113}114func (ic *ImapConnection) FetchMails(uids []uint32) ([]*domain.RawImapMail, error) {115 seqset := &imap.SeqSet{}116 seqset.AddNum(uids...)117 messages := make(chan *imap.Message, 10)118 fullBodySection := &imap.BodySectionName{119 Peek: true,120 }121 fetchItems := []imap.FetchItem{fullBodySection.FetchItem()}122 done := make(chan error, 1)123 go func() {124 done <- ic.connection.UidFetch(seqset, fetchItems, messages)125 }()126 mails := []*domain.RawImapMail{}127 for msg := range messages {128 r := msg.GetBody(fullBodySection)129 if r == nil {130 fmt.Println(msg)131 }132 rawBody, err := ioutil.ReadAll(r)133 if err != nil {134 return nil, fmt.Errorf("could not read mail body: %w", err)135 }136 subject, mailIdHash, err := mail.MailHeaderInfos(rawBody)137 if err != nil {138 return nil, fmt.Errorf("could not parse mail header infos: %w", err)139 }140 mails = append(141 mails,142 &domain.RawImapMail{143 Uid: msg.Uid,144 Subject: subject,145 MailIdHash: mailIdHash,146 RawMail: rawBody,147 },148 )149 }150 err := <-done151 if err != nil {152 return nil, fmt.Errorf("could not fetch mails: %w", err)153 }154 return mails, nil155}156func (ic *ImapConnection) FetchIdHeaders(uids []uint32) ([]*domain.ImapIdInfo, error) {157 seqset := &imap.SeqSet{}158 seqset.AddNum(uids...)159 section := &imap.BodySectionName{160 BodyPartName: imap.BodyPartName{161 Specifier: imap.HeaderSpecifier,162 Fields: []string{163 "Received",164 "Message-Id",165 "Subject",166 },167 },168 Peek: true,169 }170 fetchItems := []imap.FetchItem{section.FetchItem()}171 out := make(chan *imap.Message)172 done := make(chan error, 1)173 go func() {174 done <- ic.connection.UidFetch(seqset, fetchItems, out)175 }()176 results := []*domain.ImapIdInfo{}177 for msg := range out {178 r := msg.GetBody(section)179 rawHeaders, err := ioutil.ReadAll(r)180 if err != nil {181 return nil, fmt.Errorf("could not read mail body: %w", err)182 }183 subject, mailIdHash, err := mail.MailHeaderInfos(rawHeaders)184 if err != nil {185 return nil, fmt.Errorf("could not parse mail header infos: %w", err)186 }187 results = append(188 results,189 &domain.ImapIdInfo{190 Uid: msg.Uid,191 Subject: subject,192 MailIdHash: mailIdHash,193 },194 )195 }196 err := <-done197 if err != nil {198 return nil, fmt.Errorf("could not fetch mails: %w", err)199 }200 return results, nil201}202func (ic *ImapConnection) Close() error {203 return ic.connection.Logout()204}205type RawMail struct {206 Uid uint32207 Data []byte208}209func (ic *ImapConnection) Check(ids []uint32) ([]*RawMail, error) {210 section := &imap.BodySectionName{}211 items := []imap.FetchItem{section.FetchItem()}212 seqset := new(imap.SeqSet)213 for _, v := range ids {214 seqset.AddNum(v)215 }216 messages := make(chan *imap.Message, 10)217 done := make(chan error, 1)218 go func() {219 done <- ic.connection.UidFetch(seqset, items, messages)220 }()221 results := []*RawMail{}222 for {223 select {224 case err := <-done:225 if err != nil {226 return nil, fmt.Errorf("imap command to ListUids failed: %w", err)227 }228 done = nil229 case msg, ok := <-messages:230 if !ok {231 done = nil232 messages = nil233 break234 }235 r := msg.GetBody(section)236 rawMail, err := ioutil.ReadAll(r)237 if err != nil {238 return nil, fmt.Errorf("could not read mail: %w", err)239 }240 results = append(241 results,242 &RawMail{243 msg.Uid,244 rawMail,245 },246 )247 }248 if done == nil && messages == nil {249 break250 }251 }252 return results, nil253}254func (ic *ImapConnection) Put(body []byte, folder string) error {255 err := ic.connection.Append(folder, nil, time.Now(), bytes.NewReader(body))256 if err != nil {257 return fmt.Errorf("could not append: %w", err)258 }259 return nil260}261func (ic *ImapConnection) Delete(uids []uint32) error {262 return ic.mailDeleter.delete(uids)263}264func (ic *ImapConnection) DeleteReady() (error, error) {265 return ic.mailDeleter.deleteReady()266}267func (ic *ImapConnection) flagDeleted(uids []uint32) (*imap.SeqSet, error) {268 seqset := &imap.SeqSet{}269 seqset.AddNum(uids...)270 err := ic.connection.UidStore(seqset, imap.FormatFlagsOp(imap.AddFlags, true), []interface{}{imap.DeletedFlag}, nil)271 if err != nil {272 return nil, fmt.Errorf("could set delete flag: %w", err)273 }274 return seqset, nil275}276func (ic *ImapConnection) MoveReady() (error, error) {277 return ic.mailMover.moveReady()278}279func (ic *ImapConnection) Move(uids []uint32, folder string) error {280 return ic.mailMover.move(uids, folder)281}...

Full Screen

Full Screen

imapstuff.go

Source:imapstuff.go Github

copy

Full Screen

...43 }44 return nil45}46func imapMoveTo(c *client.Client, seqset *imap.SeqSet, targetFolder string) error {47 // copy to moved folder48 log.Printf("imapMoveTo: copy to folder %v...", targetFolder)49 if err := c.Copy(seqset, targetFolder); err != nil {50 return err51 }52 // delete inbox msg53 log.Println("imapMoveTo: mark deleted...")54 if err := c.Store(seqset, imap.FormatFlagsOp(imap.AddFlags, false), []interface{}{imap.DeletedFlag}, nil); err != nil {55 return err56 }57 log.Println("imapMoveTo: expunge...")58 if err := c.Expunge(nil); err != nil {59 return err60 }61 return nil62}63func imapHandleFirstMsg(c *client.Client, mbox *imap.MailboxStatus) error {64 log.Println("handlefirst: begin")65 seqset := new(imap.SeqSet)66 seqset.AddNum(mbox.Messages) // newest message first67 messages := make(chan *imap.Message, 1)68 done := make(chan error, 1)69 log.Println("handlefirst: get first message envelope & size")70 go func() {71 done <- c.Fetch(seqset, []imap.FetchItem{imap.FetchEnvelope, imap.FetchRFC822Size}, messages)72 }()73 msg := <-messages74 if msg == nil {75 return errors.New("Couldn't get first message envelope & size")76 }77 mSubject := msg.Envelope.Subject78 mID := msg.Envelope.MessageId79 mSize := msg.Size // note that at least for exchange servers, this is useless orig file size(s), NOT b64 encoded. joke.80 log.Printf("handlefirst: size=%v, id=%v, subject=%v", mSize, mID, mSubject)81 if mSize > uint32(Conf.ConfImap.MaxEmailSize) {82 log.Printf("handlefirst: message too big: %v, moving to quarantine...", mSize)83 SendEmail(fmt.Sprintf("Moving message to quarantine mid=%v", mID), fmt.Sprintf("Message too big: %v\nsubject=%v", mSize, mSubject))84 return imapMoveTo(c, seqset, Conf.ConfImap.FolderQuarantine)85 }86 log.Println("handlefirst: get first message raw")87 messages = make(chan *imap.Message, 1) // channels need to be reopened88 done = make(chan error, 1)89 section := &imap.BodySectionName{}90 go func() {91 done <- c.Fetch(seqset, []imap.FetchItem{section.FetchItem()}, messages)92 }()93 msg = <-messages94 if msg == nil {95 return errors.New("Couldn't get first message raw")96 }97 r := msg.GetBody(section)98 if r == nil {99 return errors.New("Server didn't returned message body")100 }101 if err := <-done; err != nil {102 return err103 }104 origlen := r.Len()105 log.Printf("handlefirst: read raw... (origlen=%v)", origlen)106 p := make([]byte, origlen)107 rlen, err := r.Read(p)108 if err != nil {109 return err110 }111 if origlen != rlen {112 return fmt.Errorf("read wrong: origlen=%v and rlen=%v", origlen, rlen)113 }114 log.Println("handlefirst: import into gmail...")115 if err := GmailImport(string(p)); err != nil {116 log.Println("handlefirst: GmailImport gave error, moving to quarantine: ", err)117 SendEmail(fmt.Sprintf("Moving message to quarantine mid=%v", mID), fmt.Sprintf("GmailImport error: %v\nsubject=%v", err, mSubject))118 return imapMoveTo(c, seqset, Conf.ConfImap.FolderQuarantine)119 }120 log.Println("handlefirst: move to moved folder...")121 if err := imapMoveTo(c, seqset, Conf.ConfImap.FolderMoved); err != nil {122 return err123 }124 log.Println("handlefirst: done!")125 return nil126}127func imapIdleWait(c *client.Client, mbox *imap.MailboxStatus) error {128 idleClient := idle.NewClient(c)129 chChUpdates := make(chan client.Update)130 c.Updates = chChUpdates131 defer func() { c.Updates = nil }() // important, before return release this otherwise imap hangs!132 chStopIdle := make(chan struct{})133 chIdleres := make(chan error, 1)134 // run idle135 go func() {136 chIdleres <- idleClient.IdleWithFallback(chStopIdle, 0)137 }()138 log.Println("wait for idle events, msgcount: ", mbox.Messages)139 for {140 select {141 case update := <-chChUpdates: // stop idle if update142 log.Printf("idle update: %v (type %T), msgcount %v", update, update, mbox.Messages)143 go func() { chStopIdle <- struct{}{} }()144 case <-time.After(Conf.ConfImap.IdleTimeout): // stop idle after custom timeout145 log.Printf("idle stop by user timeout!")146 go func() { chStopIdle <- struct{}{} }()147 case err := <-chIdleres: // this is called after chStopIdle is notified or idle error148 log.Printf("idle done, res=%v", err)149 if err != nil {150 return err151 }152 return nil153 }154 }155}156// ImapLoop is the main loop. It returns if error or imap conn broken.157func ImapLoop(wdog chan error) (errres error) {158 // catch all panics159 defer func() {160 if r := recover(); r != nil {161 fmt.Printf("Recovering from panic in ImapLoop, r=%v \n", r)162 errres = fmt.Errorf("ImapLoop: recovered panic: %v", r)163 }164 }()165 c, err := imapGetClient()166 if err != nil {167 return err168 }169 // Select INBOX170 mbox, err := c.Select(Conf.ConfImap.Folder, false)171 if err != nil {172 return err173 }174 for {175 log.Printf("imaploop: have %v messages", mbox.Messages)176 // move existing messages to gmail177 for mbox.Messages > 0 {178 log.Printf("imaploop: handle first message...")179 if err := imapHandleFirstMsg(c, mbox); err != nil {180 log.Printf("imaploop: handle error: %v", err)181 return err182 }183 log.Println("imaploop: import of one message done!")184 }185 // wait clever186 log.Println("imaploop: before imap idle wait...")187 if err := imapIdleWait(c, mbox); err != nil {188 return err189 }190 wdog <- nil // if no errors, silence watchdog...

Full Screen

Full Screen

move

Using AI Code Generation

copy

Full Screen

1import (2func main() {3 mc := memcache.New("localhost:11211")4 mc.Set(&memcache.Item{Key: "foo", Value: []byte("my value")})5 item, err := mc.Get("foo")6 if err != nil {7 panic(err)8 }9 fmt.Printf("key=%q, value=%q\n", item.Key, item.Value)10}

Full Screen

Full Screen

move

Using AI Code Generation

copy

Full Screen

1import "fmt"2func (m Imap) move(key string, value int) {3}4func main() {5 m := Imap{"a": 1, "b": 2, "c": 3}6 m.move("b", 10)7 fmt.Println(m)8}

Full Screen

Full Screen

move

Using AI Code Generation

copy

Full Screen

1import "fmt"2func main() {3 var i I = &T{"hello"}4 i.M()5}6import "fmt"7func main() {8 var i I = F(math.Pi)9 describe(i)10 i.M()11}12import "fmt"13func main() {14 describe(i)15 i.M()16}17import "fmt"18func main() {19 describe(i)20 i.M()21}22import "fmt"23func main() {24 describe(i)25 i.M()26}27Method M()28type Vertex struct {29}30func (v Vertex) Abs() float64 {31 return math.Sqrt(v.X*v.X + v.Y*v.Y)32}

Full Screen

Full Screen

move

Using AI Code Generation

copy

Full Screen

1import "fmt"2func main() {3 imap := new(imap)4 imap.move()5}6import "fmt"7type imap interface {8 move()9}10type imap struct {11}12func (imap *imap) move() {13 fmt.Println("moving")14}15import "fmt"16func main() {17 imap := new(imap)18 imap.move()19}20import "fmt"21type imap interface {22 move()23}24type imap struct {25}26func (imap *imap) move() {27 fmt.Println("moving")28}29import "fmt"30func main() {31 imap := new(imap)32 imap.move()33}34import "fmt"35type imap interface {36 move()37}38type imap struct {39}40func (imap *imap) move() {41 fmt.Println("moving")42}43import "fmt"44func main() {45 imap := new(imap)46 imap.move()47}48import "fmt"49type imap interface {50 move()51}52type imap struct {53}54func (imap *imap) move() {55 fmt.Println("moving")56}57import "fmt"58func main() {59 imap := new(imap)60 imap.move()61}62import "fmt"63type imap interface {64 move()65}66type imap struct {67}68func (imap *imap) move() {69 fmt.Println("moving")70}

Full Screen

Full Screen

move

Using AI Code Generation

copy

Full Screen

1import (2func main() {3 c, err := imap.DialTLS("imap.gmail.com:993", nil)4 if err != nil {5 fmt.Println(err)6 }7 defer c.Logout(30)8 if err := c.Login("username", "password"); err != nil {9 fmt.Println(err)10 }11 mbox, err := c.Select("INBOX", false)12 if err != nil {13 fmt.Println(err)14 }15 from := uint32(1)16 if mbox.Messages > 4 {17 }18 seqset := new(imap.SeqSet)19 seqset.AddRange(from, to)20 section := &imap.BodySectionName{}21 items := []imap.FetchItem{section.FetchItem()}22 messages := make(chan *imap.Message, 10)23 done := make(chan error, 1)24 go func() {25 done <- c.Fetch(seqset, items, messages)26 }()27 for msg := range messages {28 r := msg.GetBody(section)29 if r == nil {30 fmt.Println("Server didn't returned message body")31 }32 mr, err := mail.CreateReader(r)33 if err != nil {34 fmt.Println(err)35 }36 fmt.Println("Date:", header.Get("Date"))37 fmt.Println("From:", header.Get("From"))38 fmt.Println("To:", header.Get("To"))39 fmt.Println("Subject:", header.Get("Subject"))40 for {41 p, err := mr.NextPart()42 if err == io.EOF {43 }44 if err != nil {45 fmt.Println(err)46 }47 switch h := p.Header.(type) {

Full Screen

Full Screen

move

Using AI Code Generation

copy

Full Screen

1import (2func main() {3 imap := imap.NewImap("imap.gmail.com", "993", "username", "password")4 imap.Move("INBOX", "INBOX/Processed")5 fmt.Println("Done")6}7import (8type Imap struct {9}10func NewImap(host string, port string, username string, password string) *Imap {11 return &Imap{Host: host, Port: port, Username: username, Password: password}12}13func (i *Imap) Move(source string, destination string) {14 conn, err := tls.Dial("tcp", i.Host+":"+i.Port, nil)15 if err != nil {16 log.Fatal(err)17 }18 defer conn.Close()19 reader := textproto.NewReader(bufio.NewReader(conn))20 _, _, err = reader.ReadResponse(200)21 if err != nil {22 log.Fatal(err)23 }24 fmt.Fprintf(conn, "a login %s %s\r\n", i.Username, i.Password)25 _, _, err = reader.ReadResponse(200)26 if err != nil {27 log.Fatal(err)28 }29 fmt.Fprintf(conn, "a select %s\r\n", source)30 _, _, err = reader.ReadResponse(200)31 if err != nil {32 log.Fatal(err)33 }34 fmt.Fprintf(conn, "a search all\r\n")35 _, _, err = reader.ReadResponse(200)36 if err != nil {37 log.Fatal(err)38 }39 fmt.Fprintf(conn, "a fetch 1:* (uid)\r\n")40 _, _, err = reader.ReadResponse(200)41 if err != nil {42 log.Fatal(err)43 }44 fmt.Fprintf(conn, "a copy 1:* %s\r\n", destination)45 _, _, err = reader.ReadResponse(200)46 if err != nil {47 log.Fatal(err)48 }49 fmt.Fprintf(conn, "a store 1:*

Full Screen

Full Screen

move

Using AI Code Generation

copy

Full Screen

1import (2func main() {3 err := os.Rename("1.txt", "2.txt")4 if err != nil {5 fmt.Println(err)6 }7 fmt.Println("File moved successfully")8}9import (10func main() {11 err := ioutil.WriteFile("1.txt", []byte("Hello World"), 0644)12 if err != nil {13 fmt.Println(err)14 }15 fmt.Println("File created successfully")16 bs, err := ioutil.ReadFile("1.txt")17 if err != nil {18 fmt.Println(err)19 }20 str := string(bs)21 fmt.Println(str)22}23import (24func main() {25 f, err := os.Open("1.txt")26 if err != nil {27 fmt.Println(err)28 }29 defer f.Close()30 fmt.Println("File opened successfully")31}32import (33func main() {34 f, err := os.OpenFile("1.txt", os.O_RDONLY, 0644)35 if err != nil {36 fmt.Println(err)37 }38 defer f.Close()39 fmt.Println("File opened successfully")40}41import (42func main() {43 f, err := os.OpenFile("1.txt", os.O_WRONLY, 0644)44 if err != nil {45 fmt.Println(err)46 }47 defer f.Close()48 fmt.Println("File opened successfully")49}

Full Screen

Full Screen

move

Using AI Code Generation

copy

Full Screen

1import "fmt"2type IMap interface {3 Move()4}5type IMap1 struct {6}7func (im *IMap1) Move() {8 fmt.Println("Moving in IMap1")9}10func main() {11 imap = &IMap1{}12 imap.Move()13}14import "fmt"15type IMap interface {16 Move()17}18type IMap1 struct {19}20func (im IMap1) Move() {21 fmt.Println("Moving in IMap1")22}23func main() {24 imap = IMap1{}25 imap.Move()26}27import "fmt"28type IMap interface {29 Move()30}31type IMap1 struct {32}33func (im IMap1) Move() {34 fmt.Println("Moving in IMap1")35}36func main() {37 imap = IMap1{}38 imap.Move()39}40import "fmt"41type IMap interface {42 Move()43}44type IMap1 struct {45}46func (im *IMap1) Move() {47 fmt.Println("Moving in IMap1")48}49func main() {50 imap = &IMap1{}51 imap.Move()52}53import "fmt"54type IMap interface {55 Move()56}57type IMap1 struct {58}59func (im IMap1) Move() {60 fmt.Println("Moving in IMap1")61}62func main() {63 imap = IMap1{}64 imap.Move()65}66import "fmt"67type IMap interface {68 Move()69}70type IMap1 struct {71}72func (im IMap1) Move() {73 fmt.Println("Moving in IMap1")74}75func main() {

Full Screen

Full Screen

move

Using AI Code Generation

copy

Full Screen

1import "fmt"2func main() {3 m := imap{1, 2}4 m.move(3, 4)5 fmt.Println(m)6}7import "fmt"8type imap struct {9}10func (m imap) move(dx, dy int) {11}12import "fmt"13type imap struct {14}15func (m imap) move(dx, dy int) {16}17import "fmt"18type imap struct {19}20func (m *imap) move(dx, dy int) {21}22import "fmt"23func main() {24 m := imap{1, 2}25 m.move(3, 4)26 fmt.Println(m)27}28import "fmt"29type imap struct {30}31func (m imap) move(dx, dy int) {32}33import "fmt"34type imap struct {35}36func (m *imap) move(dx, dy int) {37}

Full Screen

Full Screen

Automation Testing Tutorials

Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.

LambdaTest Learning Hubs:

YouTube

You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.

Run Venom automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful