Beispiel #1
0
func FetchMessages(c *imap.Client, uidSet *imap.SeqSet) (fetched []MsgData, err error) {
	cmd, errF := c.UIDFetch(uidSet, "RFC822")
	if errF != nil {
		err = errF
		return
	}

	for cmd.InProgress() {
		errC := c.Recv(-1)
		if errC != nil {
			return
		}
		for _, rsp := range cmd.Data {

			uid := imap.AsNumber(rsp.MessageInfo().Attrs["UID"])
			mime := imap.AsBytes(rsp.MessageInfo().Attrs["RFC822"])
			msg, errR := mail.ReadMessage(bytes.NewReader(mime))
			if errR != nil {
				continue
			}
			if msg != nil {
				msgdata := GetMessage(msg, uid)
				fetched = append(fetched, msgdata)
			}
		}
		cmd.Data = nil
	}

	return
}
Beispiel #2
0
func (c *chatSyncClient) processChat(resp *imap.Response) {
	msgInfo := resp.MessageInfo()
	message := c.getMessage(msgInfo.Seq)

	headerBytes := msgInfo.Attrs["RFC822.HEADER"]
	headers := imap.AsBytes(headerBytes)
	message.headers, _ = mail.ReadMessage(bytes.NewReader(headers))

	bodyBytes := msgInfo.Attrs["BODY[TEXT]"]
	body := imap.AsBytes(bodyBytes)
	message.body, _ = mail.ReadMessage(bytes.NewReader(body))

	err := message.process()
	checkError(err)

	c.done <- message.seq
}
Beispiel #3
0
// Retrieve metadata for all messages in a given mailbox.
func (conn *Connection) Messages(box string, count uint32) ([]*MessageMeta,
	error) {
	conn.client.Select(box, true)

	// Create a range set that selects the most recent `count` messages (or
	// all messages if the mailbox contains fewer than that). Also, allocate a
	// slice for the results.
	set, _ := imap.NewSeqSet("")
	var messages []*MessageMeta
	totalCount := conn.client.Mailbox.Messages
	if totalCount >= count {
		set.AddRange(totalCount-(count-1), totalCount)
		messages = make([]*MessageMeta, count)
	} else {
		set.Add("1:*")
		messages = make([]*MessageMeta, totalCount)
	}

	// Fetch messages.
	cmd, err := conn.client.Fetch(set, "RFC822.HEADER RFC822.SIZE UID")
	if err != nil {
		return nil, err
	}

	// Parse each message.
	i := 0
	for cmd.InProgress() {
		err = conn.client.Recv(time.Second * 5)
		if err != nil {
			return nil, err
		}

		// Process the message data received so far.
		for _, rsp := range cmd.Data {
			msgInfo := rsp.MessageInfo()
			header := imap.AsBytes(msgInfo.Attrs["RFC822.HEADER"])
			msg, err := mail.ReadMessage(bytes.NewReader(header))
			if err != nil {
				return nil, err
			}

			messages[i] = &MessageMeta{
				UID:     msgInfo.UID,
				Size:    msgInfo.Size,
				Subject: msg.Header.Get("Subject"),
			}
			i++
		}
		cmd.Data = nil
	}

	return messages, nil
}
Beispiel #4
0
func FetchMessages(c *imap.Client, uidSet *imap.SeqSet) (err error) {
	cmd, err := c.UIDFetch(uidSet, "RFC822")

	for cmd.InProgress() {
		c.Recv(-1)
		for _, rsp := range cmd.Data {
			uid := imap.AsNumber(rsp.MessageInfo().Attrs["UID"])
			mime := imap.AsBytes(rsp.MessageInfo().Attrs["RFC822"])
			if msg, _ := mail.ReadMessage(bytes.NewReader(mime)); msg != nil {
				PrintMessageAsJSON(msg, uid)
			}
		}
		cmd.Data = nil
	}

	return
}
Beispiel #5
0
// checkAndPurge will pull message message ids off of requests and do some work
func purgeDestination(user string, dsts []*imap.Client, checkRequests chan checkExistsRequest, wg *sync.WaitGroup) {
	defer wg.Done()

	cmd, err := GetAllMessages(dsts[0])
	if err != nil {
		log.Printf("Unable to find destination messages: %s", err.Error())
	}

	workRequests := make(chan WorkRequest)

	// launch purgers
	var purgers sync.WaitGroup
	for _, dstConn := range dsts {
		purgers.Add(1)
		go checkAndPurgeMessages(dstConn, workRequests, checkRequests, &purgers)
	}

	// build the requests and send them
	var rsp *imap.Response
	var indx int
	startTime := time.Now()
	log.Printf("Beginning check/purge for %s with %d messages", user, len(cmd.Data))
	for indx, rsp = range cmd.Data {
		header := imap.AsBytes(rsp.MessageInfo().Attrs["RFC822.HEADER"])
		if msg, _ := mail.ReadMessage(bytes.NewReader(header)); msg != nil {
			header := "Message-Id"
			value := msg.Header.Get(header)

			// create the store request and pass it to each dst's storers
			workRequests <- WorkRequest{Value: value, Header: header, UID: rsp.MessageInfo().UID}

			if ((indx % 100) == 0) && (indx > 0) {
				since := time.Since(startTime)
				rate := 100 / since.Seconds()
				startTime = time.Now()
				log.Printf("Processed %d messages from %s. Rate: %f msg/s", indx, user, rate)
			}
		}
	}
	log.Printf("Done passing purge requests for %s", user)
	close(workRequests)
	purgers.Wait()

	return
}
Beispiel #6
0
func FetchMessage(conn *imap.Client, messageUID uint32) (msg MessageData, err error) {
	seq, _ := imap.NewSeqSet("")
	seq.AddNum(messageUID)
	var cmd *imap.Command
	cmd, err = imap.Wait(conn.UIDFetch(seq, "INTERNALDATE", "BODY[]", "UID", "RFC822.HEADER"))
	if err != nil {
		log.Printf("Unable to fetch message (%d): %s", messageUID, err.Error())
		return
	}

	if len(cmd.Data) == 0 {
		log.Printf("Unable to fetch message (%d) from src: NO DATA", messageUID)
		return msg, NotFound
	}

	msgFields := cmd.Data[0].MessageInfo().Attrs
	msg = MessageData{InternalDate: imap.AsDateTime(msgFields["INTERNALDATE"]), Body: imap.AsBytes(msgFields["BODY[]"])}
	return msg, nil
}
Beispiel #7
0
// newEmailMessage will parse an imap.FieldMap into an map[string]interface{}. This
// will expect the message to container the internaldate and the body with
// all headers included.
func newEmailMessage(msgFields imap.FieldMap) (map[string]interface{}, error) {
	var email map[string]interface{}
	// parse the header
	rawHeader := imap.AsBytes(msgFields["RFC822.HEADER"])
	msg, err := mail.ReadMessage(bytes.NewReader(rawHeader))
	if err != nil {
		return email, err
	}

	email = map[string]interface{}{
		"internal_date": imap.AsDateTime(msgFields["INTERNALDATE"]),
		"body":          imap.AsString(msgFields["BODY[]"]),
		"from":          msg.Header.Get("From"),
		"to":            msg.Header.Get("To"),
		"subject":       msg.Header.Get("Subject"),
	}

	return email, nil
}
Beispiel #8
0
// messages are usually created with just header information
// this method downloads the actual body of the message from the server,
// optionally marking the message as '\Seen', in IMAP terms.
func (m *Email) Body(setRead bool) (body []byte, err error) {
	// cache
	if m.bodyData != nil {
		return m.bodyData, nil
	}

	// what will our FETCH request?
	var requestType string
	if setRead {
		requestType = "BODY[TEXT]"
	} else {
		requestType = "BODY.PEEK[TEXT]"
	}

	cmd, err := m.RetrieveRaw(requestType)
	cmd, err = imap.Wait(cmd, err)
	if err != nil {
		return
	}

	info := cmd.Data[0].MessageInfo()
	m.bodyData = imap.AsBytes(info.Attrs["BODY[TEXT]"])
	return m.bodyData, nil
}
Beispiel #9
0
func connectNet(user string) {
	netTimeout := time.Second * 30
	cl, err := imap.DialTLS("imap.gmail.com", nil)
	if err != nil {
		log.Println(err)
		time.Sleep(netTimeout)
		return
	}
	defer cl.Logout(-1)
	log.Println("server says hello:", cl.Data[0].Info)
	cl.Data = nil
	log.Println("logging in")
	if cl.State() == imap.Login {
		_, err = cl.Login(user+"@gmail.com", "PASSHERE")
		if err != nil {
			log.Println(err)
			time.Sleep(netTimeout)
			return
		}
	}
	log.Println("logged in")
	log.Println("selecting INBOX")
	_, err = cl.Select("INBOX", false)
	if err != nil {
		log.Println(err)
		time.Sleep(netTimeout)
		return
	}
	log.Println("selected INBOX")
	set, _ := imap.NewSeqSet("")
searchLoop:
	for {
		var successCounter int
		conTimeout := 5
		log.Println("searching INBOX")
		cmd, err := imap.Wait(cl.Search("SUBJECT \"Confirm your email\""))
		if err != nil {
			log.Println(err)
			break searchLoop
		}
		searchResults := cmd.Data[0].SearchResults()
		if searchResults == nil {
			log.Println("no email[s] found")
			time.Sleep(time.Second * 5)
			break searchLoop
		} else {
			log.Println("found", len(searchResults), "emails to spoof, results:", searchResults)
			set.AddNum(searchResults...)
		}
		var rsp *imap.Response
		link := regexp.MustCompile(`https:=\r\n\/\/invites.oneplus.net\/confirm\/[0-9A-Z]*.`)
		var UIDCounter int
		log.Println("beginning spoof confirmation loop")
		cmd, err = cl.Fetch(set, "RFC822")
		if err != nil {
			log.Println(err)
			break searchLoop
		}
		setDone, _ := imap.NewSeqSet("")
	getMailLoop:
		for cmd.InProgress() {
			cl.Recv(-1)
			for _, rsp = range cmd.Data {
				message := imap.AsBytes(rsp.MessageInfo().Attrs["RFC822"])
				if msg, err := mail.ReadMessage(bytes.NewReader(message)); msg != nil {
					log.Println("current conTimeout", conTimeout)
					body, err := ioutil.ReadAll(msg.Body)
					if err != nil {
						log.Println(err)
						break searchLoop
					}
					linkRawM := link.FindSubmatch(body)
					var linkRaw []byte
					if len(linkRawM) > 0 {
						linkRaw = linkRawM[0]
					} else {
						log.Println("found nolink mail")
						continue getMailLoop
					}
					log.Println(string(linkRaw))
					url, err := url.Parse(string(linkRaw[:6]) + string(linkRaw[9:]))
					if err != nil {
						log.Println(err)
						break searchLoop
					}
					log.Println(url)
					req := confirmURL.ReplaceAll(reqTemplate, []byte(url.Path)[:len(url.Path)-1])
					for {
						log.Println("attempting to spoof confirmation for", searchResults[UIDCounter])
						c, err := tls.Dial("tcp", url.Host+":443", nil)
						if err != nil {
							log.Println(err)
							break searchLoop
						}
						_, err = c.Write(req)
						if err != nil {
							log.Println(err)
							break searchLoop
						}
						resp, err := http.ReadResponse(bufio.NewReader(c), nil)
						if err != nil {
							log.Println(err)
							break searchLoop
						}
						if resp.StatusCode == 302 {
							redirectReg := regexp.MustCompile(`https:\/\/oneplus\.net\/invites\?kid=[0-9A-Z]*`)
							redirectURL, err := resp.Location()
							if err != nil {
								log.Println(err)
								break searchLoop
							}
							log.Println(resp.Location())
							if redirectReg.MatchString(redirectURL.String()) {
								log.Println("successfully spoofed confirmation for", searchResults[UIDCounter])
								setDone.AddNum(searchResults[UIDCounter])
								UIDCounter++
								if successCounter == 10 {
									conTimeout--
									successCounter = 0
								}
								break
							} else {
								log.Println("server trying to migitate spoofing")
								conTimeout++
								successCounter = 0
							}
						} else {
							log.Println("gg rip hamsters")
							conTimeout++
							successCounter = 0
						}
						time.Sleep(time.Second * time.Duration(conTimeout))
					}
				} else {
					log.Println(err)
				}
			}
			time.Sleep(time.Second * time.Duration(conTimeout))
			cmd.Data = nil
		}
		log.Println("deleting mail", setDone)
		_, err = imap.Wait(cl.Store(setDone, "+FLAGS", "\\DELETED"))
		if err != nil {
			log.Println(err)
			break searchLoop
		}
		_, err = imap.Wait(cl.Expunge(nil))
		if err != nil {
			log.Println(err)
			break searchLoop
		}
	}
}
Beispiel #10
0
// SearchAndStore will check check if each message in the source inbox
// exists in the destinations. If it doesn't exist in a destination, the message info will
// be pulled and stored into the destination.
func SearchAndStore(src []*imap.Client, dsts map[string][]*imap.Client, dbFile string, quickSyncCount int) (err error) {
	var cmd *imap.Command
	cmd, err = GetAllMessages(src[0])
	if err != nil {
		log.Printf("Unable to get all messages!")
		return
	}

	// connect to cache
	cache, err := NewCache(dbFile)
	if err != nil {
		log.Printf("problems initiating cache - %s", err.Error())
		return
	}
	defer cache.Close()

	// setup message fetchers to pull from the source/memcache
	fetchRequests := make(chan fetchRequest)
	for _, srcConn := range src {
		go fetchEmails(srcConn, fetchRequests, cache)
	}

	var appendRequests []chan WorkRequest
	var storers sync.WaitGroup
	// setup storers for each destination
	for _, dst := range dsts {
		storeRequests := make(chan WorkRequest)
		for _, dstConn := range dst {
			storers.Add(1)
			go CheckAndAppendMessages(dstConn, storeRequests, fetchRequests, &storers)
		}
		appendRequests = append(appendRequests, storeRequests)
	}

	// build the requests and send them
	log.Printf("store processing for %d messages from the source inbox", len(cmd.Data))
	var rsp *imap.Response
	var indx int
	startTime := time.Now()
	syncStart := 0
	// consider quick sync
	if quickSyncCount != 0 {
		syncStart = len(cmd.Data) - quickSyncCount
		log.Printf("found quick sync count. will only sync messages %d through %d", syncStart, len(cmd.Data))
	}
	for indx, rsp = range cmd.Data[syncStart:] {
		header := imap.AsBytes(rsp.MessageInfo().Attrs["RFC822.HEADER"])
		if msg, _ := mail.ReadMessage(bytes.NewReader(header)); msg != nil {
			header := "Message-Id"
			value := msg.Header.Get(header)

			// create the store request and pass it to each dst's storers
			storeRequest := WorkRequest{Value: value, Header: header, UID: rsp.MessageInfo().UID}
			for _, storeRequests := range appendRequests {
				storeRequests <- storeRequest
			}

			if ((indx % 100) == 0) && (indx > 0) {
				since := time.Since(startTime)
				rate := 100 / since.Seconds()
				startTime = time.Now()
				log.Printf("Completed store processing for %d messages from the source inbox. Rate: %f msg/s", indx, rate)
			}
		}
	}

	// after everything is on the channel, close them...
	for _, storeRequests := range appendRequests {
		close(storeRequests)
	}
	// ... and wait for our workers to finish up.
	storers.Wait()

	// once the storers are complete we can close the fetch channel
	close(fetchRequests)

	log.Printf("search and store processes complete")
	return nil
}
Beispiel #11
0
func GetMessage(folder, uid string, client *imap.Client) (messag *Message, e error) {

	cmd, err := client.Select(folder, true)
	if err != nil {
		return nil, err
	}

	uidlist, _ := imap.NewSeqSet(uid)
	//uidlist.Add(uid)

	fmt.Println("get_mess", folder, uid)
	mess := new(Message)
	mess.Folder = folder

	cmd, err = imap.Wait(client.UIDFetch(uidlist, "FLAGS", "INTERNALDATE", "RFC822.SIZE", "RFC822")) //  "RFC822.HEADER",  "BODY.PEEK[TEXT]") )
	if err != nil {
		return mess, err
	}
	fmt.Println(len(cmd.Data), cmd.Data)
	rsp := cmd.Data[0]
	minfo := rsp.MessageInfo()

	mess.Uid = minfo.UID

	msg, _ := mail.ReadMessage(bytes.NewReader(imap.AsBytes(minfo.Attrs["RFC822"])))
	mime, mime_err := enmime.ParseMIMEBody(msg)

	for flag, boo := range minfo.Flags {
		if flag == "\\Seen" && boo {
			mess.Seen = true
		}
		if flag == "\\Flagged" && boo {
			mess.Flagged = true
		}
	}
	/*
		bites := imap.AsBytes(minfo.Attrs["RFC822"])
		msg, msg_err := mail.ReadMessage(bytes.NewReader(bites))
		if msg_err != nil {
			return mess, msg_err
		}
	*/

	//fmt.Println(msg.Header.Get("Content-type"))
	//fmt.Println(msg.Header.Get("To"))
	//fmt.Println(msg.Header.Get("Delivered-To"))

	// From
	from, fro_err := mail.ParseAddress(msg.Header.Get("From"))
	if fro_err != nil {
		fmt.Println("address ettot")
	} else {
		mess.FromName = from.Name
		mess.FromEmail = from.Address
	}

	//for i, m := range minfo.Attrs {

	//fmt.Println(i,m)
	//}
	// Date
	dat := imap.AsDateTime(minfo.Attrs["INTERNALDATE"])
	mess.Date = dat.Format("2006-01-02 15:04:05")

	mess.Subject = msg.Header.Get("Subject")
	mess.ContentType = msg.Header.Get("Content-Type")
	//fmt.Println("body=", cmd.Data[0].String)

	//bodyb := imap.AsBytes(minfo.Attrs["BODY[TEXT]"])
	//bb := 	bytes.NewReader(bytes.NewReader(header + bodyb))

	//fmt.Println("bodyb=", string(msg.Body))

	//fmt.Printf("----\n%v\n", mime.Html == nil)
	//mess.Body = mime.Text
	if mime_err != nil {
		fmt.Println("err=", mime_err, mime)
	}
	//*/
	//fmt.Println("body=", body)

	mess.BodyText = mime.Text
	mess.BodyHtml = mime.Html //imap.AsString(minfo.Attrs["RFC822"])

	return mess, nil

}
Beispiel #12
0
// gets all the messages on the server since the last message in the list
func (m *Mailbox) Update() (newMail []*Email, err error) {
	c, err := m.server.Connect()
	if err != nil {
		return nil, err
	}

	// sync imap command to select the mailbox for actions
	c.Select(m.Name, true)

	lastHad := m.latestMessage

	// retrieve items
	wanted := fmt.Sprintf("%d:*", lastHad)
	set, err := imap.NewSeqSet(wanted)
	if err != nil {
		return nil, err
	}
	cmd, err := c.UIDFetch(set, "RFC822.HEADER UID")
	if err != nil {
		return nil, err
	}

	// result
	newMail = make([]*Email, 0, 5)

	for cmd.InProgress() {
		// Wait for the next response (no timeout)
		c.Recv(-1)

		// Process command data

		// retrieve message UID
		// construct local Message structure from given header
		// store message in map
		// append UID to newMessages list
		for _, rsp := range cmd.Data {
			info := rsp.MessageInfo()
			if info.Attrs["UID"] != nil {
				// construct message
				header := imap.AsBytes(info.Attrs["RFC822.HEADER"])
				// TODO: catch this error
				if msg, _ := mail.ReadMessage(bytes.NewReader(header)); msg != nil {
					// we could read the message and retrieve the UID
					// so this is valid to push into our storage system
					m.latestMessage = info.UID

					my_msg := &MessageNode{
						Header:      msg.Header,
						ContentType: msg.Header.Get(ContentType),
					}

					email := &Email{
						server:  m.server,
						mailbox: m,
						UID:     info.UID,
						Message: my_msg,
					}

					// store
					newMail = append(newMail, email)
					m.Mail[info.UID] = email
				} else {
					fmt.Printf("mail.ReadMessage failed on UID %d\n", info.UID)
				}
			} else {
				fmt.Printf("Message %v had no UID. Skipped.\n", info)
			}
		}

		// clear data
		cmd.Data = nil
	}

	return newMail, nil
}
Beispiel #13
0
func ExampleClient() {
	//
	// Note: most of error handling code is omitted for brevity
	//
	var (
		c   *imap.Client
		cmd *imap.Command
		rsp *imap.Response
	)

	// Connect to the server
	c, _ = imap.Dial("imap.example.com")

	// Remember to log out and close the connection when finished
	defer c.Logout(30 * time.Second)

	// Print server greeting (first response in the unilateral server data queue)
	fmt.Println("Server says hello:", c.Data[0].Info)
	c.Data = nil

	// Enable encryption, if supported by the server
	if c.Caps["STARTTLS"] {
		c.StartTLS(nil)
	}

	// Authenticate
	if c.State() == imap.Login {
		c.Login("*****@*****.**", "mysupersecretpassword")
	}

	// List all top-level mailboxes, wait for the command to finish
	cmd, _ = imap.Wait(c.List("", "%"))

	// Print mailbox information
	fmt.Println("\nTop-level mailboxes:")
	for _, rsp = range cmd.Data {
		fmt.Println("|--", rsp.MailboxInfo())
	}

	// Check for new unilateral server data responses
	for _, rsp = range c.Data {
		fmt.Println("Server data:", rsp)
	}
	c.Data = nil

	// Open a mailbox (synchronous command - no need for imap.Wait)
	c.Select("INBOX", true)
	fmt.Print("\nMailbox status:\n", c.Mailbox)

	// Fetch the headers of the 10 most recent messages
	set, _ := imap.NewSeqSet("")
	if c.Mailbox.Messages >= 10 {
		set.AddRange(c.Mailbox.Messages-9, c.Mailbox.Messages)
	} else {
		set.Add("1:*")
	}
	cmd, _ = c.Fetch(set, "RFC822.HEADER")

	// Process responses while the command is running
	fmt.Println("\nMost recent messages:")
	for cmd.InProgress() {
		// Wait for the next response (no timeout)
		c.Recv(-1)

		// Process command data
		for _, rsp = range cmd.Data {
			header := imap.AsBytes(rsp.MessageInfo().Attrs["RFC822.HEADER"])
			if msg, _ := mail.ReadMessage(bytes.NewReader(header)); msg != nil {
				fmt.Println("|--", msg.Header.Get("Subject"))
			}
		}
		cmd.Data = nil

		// Process unilateral server data
		for _, rsp = range c.Data {
			fmt.Println("Server data:", rsp)
		}
		c.Data = nil
	}

	// Check command completion status
	if rsp, err := cmd.Result(imap.OK); err != nil {
		if err == imap.ErrAborted {
			fmt.Println("Fetch command aborted")
		} else {
			fmt.Println("Fetch error:", rsp.Info)
		}
	}
}
Beispiel #14
0
// Get a Message out of a MessageInfo attribute.
func messageAttr(message *imap.MessageInfo, attrName string) *mail.Message {
	content := imap.AsBytes(message.Attrs[attrName])
	msg, _ := mail.ReadMessage(bytes.NewReader(content))
	//	panicMaybe(err)
	return msg
}