1// Copyright 2014 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package main
6
7import (
8	"bufio"
9	"fmt"
10	"log"
11	"net/http"
12	"os"
13	"sort"
14	"strings"
15
16	gmail "google.golang.org/api/gmail/v1"
17)
18
19func init() {
20	registerDemo("gmail", gmail.MailGoogleComScope, gmailMain)
21}
22
23type message struct {
24	size    int64
25	gmailID string
26	date    string // retrieved from message header
27	snippet string
28}
29
30// gmailMain is an example that demonstrates calling the Gmail API.
31// It iterates over all messages of a user that are larger
32// than 5MB, sorts them by size, and then interactively asks the user to
33// choose either to Delete, Skip, or Quit for each message.
34//
35// Example usage:
36//   go build -o go-api-demo *.go
37//   go-api-demo -clientid="my-clientid" -secret="my-secret" gmail
38func gmailMain(client *http.Client, argv []string) {
39	if len(argv) != 0 {
40		fmt.Fprintln(os.Stderr, "Usage: gmail")
41		return
42	}
43
44	svc, err := gmail.New(client)
45	if err != nil {
46		log.Fatalf("Unable to create Gmail service: %v", err)
47	}
48
49	var total int64
50	msgs := []message{}
51	pageToken := ""
52	for {
53		req := svc.Users.Messages.List("me").Q("larger:5M")
54		if pageToken != "" {
55			req.PageToken(pageToken)
56		}
57		r, err := req.Do()
58		if err != nil {
59			log.Fatalf("Unable to retrieve messages: %v", err)
60		}
61
62		log.Printf("Processing %v messages...\n", len(r.Messages))
63		for _, m := range r.Messages {
64			msg, err := svc.Users.Messages.Get("me", m.Id).Do()
65			if err != nil {
66				log.Fatalf("Unable to retrieve message %v: %v", m.Id, err)
67			}
68			total += msg.SizeEstimate
69			date := ""
70			for _, h := range msg.Payload.Headers {
71				if h.Name == "Date" {
72					date = h.Value
73					break
74				}
75			}
76			msgs = append(msgs, message{
77				size:    msg.SizeEstimate,
78				gmailID: msg.Id,
79				date:    date,
80				snippet: msg.Snippet,
81			})
82		}
83
84		if r.NextPageToken == "" {
85			break
86		}
87		pageToken = r.NextPageToken
88	}
89	log.Printf("total: %v\n", total)
90
91	sortBySize(msgs)
92	reader := bufio.NewReader(os.Stdin)
93	count, deleted := 0, 0
94	for _, m := range msgs {
95		count++
96		fmt.Printf("\nMessage URL: https://mail.google.com/mail/u/0/#all/%v\n", m.gmailID)
97		fmt.Printf("Size: %v, Date: %v, Snippet: %q\n", m.size, m.date, m.snippet)
98		fmt.Printf("Options: (d)elete, (s)kip, (q)uit: [s] ")
99		val := ""
100		if val, err = reader.ReadString('\n'); err != nil {
101			log.Fatalf("unable to scan input: %v", err)
102		}
103		val = strings.TrimSpace(val)
104		switch val {
105		case "d": // delete message
106			if err := svc.Users.Messages.Delete("me", m.gmailID).Do(); err != nil {
107				log.Fatalf("unable to delete message %v: %v", m.gmailID, err)
108			}
109			log.Printf("Deleted message %v.\n", m.gmailID)
110			deleted++
111		case "q": // quit
112			log.Printf("Done.  %v messages processed, %v deleted\n", count, deleted)
113			os.Exit(0)
114		default:
115		}
116	}
117}
118
119type messageSorter struct {
120	msg  []message
121	less func(i, j message) bool
122}
123
124func sortBySize(msg []message) {
125	sort.Sort(messageSorter{msg, func(i, j message) bool {
126		return i.size > j.size
127	}})
128}
129
130func (s messageSorter) Len() int {
131	return len(s.msg)
132}
133
134func (s messageSorter) Swap(i, j int) {
135	s.msg[i], s.msg[j] = s.msg[j], s.msg[i]
136}
137
138func (s messageSorter) Less(i, j int) bool {
139	return s.less(s.msg[i], s.msg[j])
140}
141