From 6e2cb00008cbf09e556b00f87603797fcaa47e09 Mon Sep 17 00:00:00 2001 From: Christopher Speller Date: Mon, 16 Apr 2018 05:37:14 -0700 Subject: Depenancy upgrades and movign to dep. (#8630) --- .../mattermost/rsc/google/acme/Chat/main.go | 575 --------- vendor/github.com/mattermost/rsc/google/chat.go | 39 - .../mattermost/rsc/google/gmail/gmail.go | 1241 -------------------- .../mattermost/rsc/google/gmailsend/send.go | 370 ------ .../mattermost/rsc/google/googleserver/chat.go | 80 -- .../mattermost/rsc/google/googleserver/main.go | 139 --- vendor/github.com/mattermost/rsc/google/main.go | 181 --- 7 files changed, 2625 deletions(-) delete mode 100644 vendor/github.com/mattermost/rsc/google/acme/Chat/main.go delete mode 100644 vendor/github.com/mattermost/rsc/google/chat.go delete mode 100644 vendor/github.com/mattermost/rsc/google/gmail/gmail.go delete mode 100644 vendor/github.com/mattermost/rsc/google/gmailsend/send.go delete mode 100644 vendor/github.com/mattermost/rsc/google/googleserver/chat.go delete mode 100644 vendor/github.com/mattermost/rsc/google/googleserver/main.go delete mode 100644 vendor/github.com/mattermost/rsc/google/main.go (limited to 'vendor/github.com/mattermost/rsc/google') diff --git a/vendor/github.com/mattermost/rsc/google/acme/Chat/main.go b/vendor/github.com/mattermost/rsc/google/acme/Chat/main.go deleted file mode 100644 index a161d8f10..000000000 --- a/vendor/github.com/mattermost/rsc/google/acme/Chat/main.go +++ /dev/null @@ -1,575 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package main - -/* -TODO: - - Del of main window should move to other window. - - Editing main window should update status on \n or something like that. - - Make use of full names from roster -*/ - -import ( - "bytes" - "flag" - "fmt" - "io/ioutil" - "log" - "os" - "regexp" - "strings" - "time" - - "code.google.com/p/goplan9/plan9/acme" - "github.com/mattermost/rsc/google" - "github.com/mattermost/rsc/xmpp" -) - -var acmeDebug = flag.Bool("acmedebug", false, "print acme debugging") - -type Window struct { - *acme.Win // acme window - *acme.Event // most recent event received - err error // error reading event - typ string // kind of window "main", "chat" - name string // acme window title - remote string // for typ=="chat", remote address - dirty bool // window is dirty - blinky bool // window's dirty box is blinking - - lastTime time.Time -} - -type Msg struct { - w *Window // window where message belongs - *xmpp.Chat // recently received chat - err error // error reading chat message -} - -var ( - client *xmpp.Client // current xmpp client (can reconnect) - acct google.Account // google acct info - statusCache = make(map[string][]*xmpp.Presence) - active = make(map[string]*Window) // active windows - acmeChan = make(chan *Window) // acme events - msgChan = make(chan *Msg) // chat events - mainWin *Window - status = xmpp.Available - statusMsg = "" - lastActivity time.Time -) - -const ( - awayTime = 10 * time.Minute - extendedAwayTime = 30 * time.Minute -) - -func usage() { - fmt.Fprintf(os.Stderr, "usage: Chat [-a acct] name...\n") - flag.PrintDefaults() - os.Exit(2) -} - -var acctName = flag.String("a", "", "account to use") - -func main() { - flag.Usage = usage - flag.Parse() - - acct = google.Acct(*acctName) - - aw, err := acme.New() - if err != nil { - log.Fatal(err) - } - aw.Name("Chat/" + acct.Nick + "/") - - client, err = xmpp.NewClient("talk.google.com:443", acct.Email, acct.Password) - if err != nil { - log.Fatal(err) - } - - w := &Window{Win: aw, typ: "main", name: "Chat/" + acct.Nick + "/"} - data, err := ioutil.ReadFile(google.Dir() + "/chat." + acct.Nick) - if err != nil { - log.Fatal(err) - } - if err == nil { - w.Write("body", data) - } - mainWin = w - active[w.name] = w - go w.readAcme() - client.Roster() - setStatus(status) - go w.readChat() - lastActivity = time.Now() - - tick := time.Tick(0.5e9) -Loop: - for len(active) > 0 { - select { - case w := <-acmeChan: - if w == nil { - // Sync with reader. - continue - } - if w.err != nil { - if active[w.name] == nil { - continue - } - log.Fatal(w.err) - } - if *acmeDebug { - fmt.Fprintf(os.Stderr, "%s %c%c %d,%d %q\n", w.name, w.C1, w.C2, w.Q0, w.Q1, w.Text) - } - if w.C1 == 'M' || w.C1 == 'K' { - lastActivity = time.Now() - if status != xmpp.Available { - setStatus(xmpp.Available) - } - } - if (w.C2 == 'x' || w.C2 == 'X') && string(w.Text) == "Del" { - // TODO: Hangup connection for w.typ == "acct"? - delete(active, w.name) - w.Del(true) - continue Loop - } - - switch w.typ { - case "main": - switch w.C2 { - case 'L': // Button 3 in body: load chat window for contact. - w.expand() - fallthrough - case 'l': // Button 3 in tag - arg := string(w.Text) - showContact(arg) - continue Loop - } - case "chat": - if w.C1 == 'F' && w.C2 == 'I' { - continue Loop - } - if w.C1 != 'M' && w.C1 != 'K' { - break - } - if w.blinky { - w.blinky = false - w.Fprintf("ctl", "dirty\n") - } - switch w.C2 { - case 'X', 'x': - if string(w.Text) == "Ack" { - w.Fprintf("ctl", "clean\n") - } - case 'I': - w.sendMsg() - continue Loop - } - } - w.WriteEvent(w.Event) - - case msg := <-msgChan: - w := msg.w - if msg.err != nil { - w.Fprintf("body", "ERROR: %s\n", msg.err) - continue Loop - } - you := msg.Remote - if i := strings.Index(you, "/"); i >= 0 { - you = you[:i] - } - switch msg.Type { - case "chat": - w := showContact(you) - text := strings.TrimSpace(msg.Text) - if text == "" { - // Probably a composing notification. - continue - } - w.message("> %s\n", text) - w.blinky = true - w.dirty = true - - case "presence": - pr := msg.Presence - pr, new := savePresence(pr, you) - if !new { - continue - } - w := lookContact(you) - if w != nil { - w.status(pr) - } - mainStatus(pr, you) - } - - case t := <-tick: - switch status { - case xmpp.Available: - if t.Sub(lastActivity) > awayTime { - setStatus(xmpp.Away) - } - case xmpp.Away: - if t.Sub(lastActivity) > extendedAwayTime { - setStatus(xmpp.ExtendedAway) - } - } - for _, w := range active { - if w.blinky { - w.dirty = !w.dirty - if w.dirty { - w.Fprintf("ctl", "dirty\n") - } else { - w.Fprintf("ctl", "clean\n") - } - } - } - } - } -} - -func setStatus(st xmpp.Status) { - status = st - client.Status(status, statusMsg) - mainWin.statusTag(status, statusMsg) -} - -func savePresence(pr *xmpp.Presence, you string) (pr1 *xmpp.Presence, new bool) { - old := cachedPresence(you) - - pr.StatusMsg = strings.TrimSpace(pr.StatusMsg) - c := statusCache[you] - for i, p := range c { - if p.Remote == pr.Remote { - c[i] = pr - c[0], c[i] = c[i], c[0] - goto Best - } - } - c = append(c, pr) - c[0], c[len(c)-1] = c[len(c)-1], c[0] - statusCache[you] = c - -Best: - best := cachedPresence(you) - return best, old == nil || old.Status != best.Status || old.StatusMsg != best.StatusMsg -} - -func cachedPresence(you string) *xmpp.Presence { - c := statusCache[you] - if len(c) == 0 { - return nil - } - best := c[0] - for _, p := range c { - if p.Status > best.Status { - best = p - } - } - return best -} - -func short(st xmpp.Status) string { - switch st { - case xmpp.Unavailable: - return "?" - case xmpp.ExtendedAway: - return "x" - case xmpp.Away: - return "-" - case xmpp.Available: - return "+" - case xmpp.DoNotDisturb: - return "!" - } - return st.String() -} - -func long(st xmpp.Status) string { - switch st { - case xmpp.Unavailable: - return "unavailable" - case xmpp.ExtendedAway: - return "offline" - case xmpp.Away: - return "away" - case xmpp.Available: - return "available" - case xmpp.DoNotDisturb: - return "busy" - } - return st.String() -} - -func (w *Window) time() string { - /* - Auto-date chat windows: - - Show date and time on first message. - Show time if minute is different from last message. - Show date if day is different from last message. - - Oct 10 12:01 > hi - 12:03 hello there - 12:05 > what's up? - - 12:10 [Away] - */ - now := time.Now() - m1, d1, y1 := w.lastTime.Date() - m2, d2, y2 := now.Date() - w.lastTime = now - - if m1 != m2 || d1 != d2 || y1 != y2 { - return now.Format("Jan 2 15:04 ") - } - return now.Format("15:04 ") -} - -func (w *Window) status(pr *xmpp.Presence) { - msg := "" - if pr.StatusMsg != "" { - msg = ": " + pr.StatusMsg - } - w.message("[%s%s]\n", long(pr.Status), msg) - - w.statusTag(pr.Status, pr.StatusMsg) -} - -func (w *Window) statusTag(status xmpp.Status, statusMsg string) { - data, err := w.ReadAll("tag") - if err != nil { - log.Printf("read tag: %v", err) - return - } - //log.Printf("tag1: %s\n", data) - i := bytes.IndexByte(data, '|') - if i >= 0 { - data = data[i+1:] - } else { - data = nil - } - //log.Printf("tag2: %s\n", data) - j := bytes.IndexByte(data, '|') - if j >= 0 { - data = data[j+1:] - } - //log.Printf("tag3: %s\n", data) - - msg := "" - if statusMsg != "" { - msg = " " + statusMsg - } - w.Ctl("cleartag\n") - w.Write("tag", []byte(" "+short(status)+msg+" |"+string(data))) -} - -func mainStatus(pr *xmpp.Presence, you string) { - w := mainWin - if err := w.Addr("#0/^(.[ \t]+)?" + regexp.QuoteMeta(you) + "([ \t]*|$)/"); err != nil { - return - } - q0, q1, err := w.ReadAddr() - if err != nil { - log.Printf("ReadAddr: %s\n", err) - return - } - if err := w.Addr("#%d/"+regexp.QuoteMeta(you)+"/", q0); err != nil { - log.Printf("Addr2: %s\n", err) - } - q2, q3, err := w.ReadAddr() - if err != nil { - log.Printf("ReadAddr2: %s\n", err) - return - } - - space := " " - if q1 > q3 || pr.StatusMsg == "" { // already have or don't need space - space = "" - } - if err := w.Addr("#%d/.*/", q1); err != nil { - log.Printf("Addr3: %s\n", err) - } - w.Fprintf("data", "%s%s", space, pr.StatusMsg) - - space = "" - if q0 == q2 { - w.Addr("#%d,#%d", q0, q0) - space = " " - } else { - w.Addr("#%d,#%d", q0, q0+1) - } - w.Fprintf("data", "%s%s", short(pr.Status), space) -} - -func (w *Window) expand() { - // Use selection if any. - w.Fprintf("ctl", "addr=dot\n") - q0, q1, err := w.ReadAddr() - if err == nil && q0 <= w.Q0 && w.Q0 <= q1 { - goto Read - } - if err = w.Addr("#%d-/[a-zA-Z0-9_@.\\-]*/,#%d+/[a-zA-Z0-9_@.\\-]*/", w.Q0, w.Q1); err != nil { - log.Printf("expand: %v", err) - return - } - q0, q1, err = w.ReadAddr() - if err != nil { - log.Printf("expand: %v", err) - return - } - -Read: - data, err := w.ReadAll("xdata") - if err != nil { - log.Printf("read: %v", err) - return - } - w.Text = data - w.Q0 = q0 - w.Q1 = q1 - return -} - -// Invariant: in chat windows, the acme addr corresponds to the -// empty string just before the input being typed. Text before addr -// is the chat history (usually ending in a blank line). - -func (w *Window) message(format string, args ...interface{}) { - if *acmeDebug { - q0, q1, _ := w.ReadAddr() - log.Printf("message; addr=%d,%d", q0, q1) - } - if err := w.Addr(".-/\\n?\\n?/"); err != nil && *acmeDebug { - log.Printf("set addr: %s", err) - } - q0, _, _ := w.ReadAddr() - nl := "" - if q0 > 0 { - nl = "\n" - } - if *acmeDebug { - q0, q1, _ := w.ReadAddr() - log.Printf("inserting; addr=%d,%d", q0, q1) - } - w.Fprintf("data", nl+w.time()+format+"\n", args...) - if *acmeDebug { - q0, q1, _ := w.ReadAddr() - log.Printf("wrote; addr=%d,%d", q0, q1) - } -} - -func (w *Window) sendMsg() { - if *acmeDebug { - q0, q1, _ := w.ReadAddr() - log.Printf("sendMsg; addr=%d,%d", q0, q1) - } - if err := w.Addr(`.,./(.|\n)*\n/`); err != nil { - if *acmeDebug { - q0, q1, _ := w.ReadAddr() - log.Printf("no text (%s); addr=%d,%d", err, q0, q1) - } - return - } - q0, q1, _ := w.ReadAddr() - if *acmeDebug { - log.Printf("found msg; addr=%d,%d", q0, q1) - } - line, _ := w.ReadAll("xdata") - trim := string(bytes.TrimSpace(line)) - if len(trim) > 0 { - err := client.Send(xmpp.Chat{Remote: w.remote, Type: "chat", Text: trim}) - - // Select blank line before input (if any) and input. - w.Addr("#%d-/\\n?\\n?/,#%d", q0, q1) - if *acmeDebug { - q0, q1, _ := w.ReadAddr() - log.Printf("selected text; addr=%d,%d", q0, q1) - } - q0, _, _ := w.ReadAddr() - - // Overwrite with \nmsg\n\n. - // Leaves addr after final \n, which is where we want it. - nl := "" - if q0 > 0 { - nl = "\n" - } - errstr := "" - if err != nil { - errstr = fmt.Sprintf("\n%s", errstr) - } - w.Fprintf("data", "%s%s%s%s\n\n", nl, w.time(), trim, errstr) - if *acmeDebug { - q0, q1, _ := w.ReadAddr() - log.Printf("wrote; addr=%d,%d", q0, q1) - } - w.Fprintf("ctl", "clean\n") - } -} - -func (w *Window) readAcme() { - for { - e, err := w.ReadEvent() - if err != nil { - w.err = err - acmeChan <- w - break - } - //fmt.Printf("%c%c %d,%d %d,%d %#x %#q %#q %#q\n", e.C1, e.C2, e.Q0, e.Q1, e.OrigQ0, e.OrigQ1, e.Flag, e.Text, e.Arg, e.Loc) - w.Event = e - acmeChan <- w - acmeChan <- nil - } -} - -func (w *Window) readChat() { - for { - msg, err := client.Recv() - if err != nil { - msgChan <- &Msg{w: w, err: err} - break - } - //fmt.Printf("%s\n", *msg) - msgChan <- &Msg{w: w, Chat: &msg} - } -} - -func lookContact(you string) *Window { - return active["Chat/"+acct.Nick+"/"+you] -} - -func showContact(you string) *Window { - w := lookContact(you) - if w != nil { - w.Ctl("show\n") - return w - } - - ww, err := acme.New() - if err != nil { - log.Fatal(err) - } - - name := "Chat/" + acct.Nick + "/" + you - ww.Name(name) - w = &Window{Win: ww, typ: "chat", name: name, remote: you} - w.Fprintf("body", "\n") - w.Addr("#1") - w.OpenEvent() - w.Fprintf("ctl", "cleartag\n") - w.Fprintf("tag", " Ack") - if p := cachedPresence(you); p != nil { - w.status(p) - } - active[name] = w - go w.readAcme() - return w -} - -func randid() string { - return fmt.Sprint(time.Now()) -} diff --git a/vendor/github.com/mattermost/rsc/google/chat.go b/vendor/github.com/mattermost/rsc/google/chat.go deleted file mode 100644 index 8e9ae1c50..000000000 --- a/vendor/github.com/mattermost/rsc/google/chat.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package google - -import "github.com/mattermost/rsc/xmpp" - -type ChatID struct { - ID string - Email string - Status xmpp.Status - StatusMsg string -} - -type ChatSend struct { - ID *ChatID - Msg xmpp.Chat -} - -func (g *Client) ChatRecv(cid *ChatID) (*xmpp.Chat, error) { - var msg xmpp.Chat - if err := g.client.Call("goog.ChatRecv", cid, &msg); err != nil { - return nil, err - } - return &msg, nil -} - -func (g *Client) ChatStatus(cid *ChatID) error { - return g.client.Call("goog.ChatRecv", cid, &Empty{}) -} - -func (g *Client) ChatSend(cid *ChatID, msg *xmpp.Chat) error { - return g.client.Call("goog.ChatSend", &ChatSend{cid, *msg}, &Empty{}) -} - -func (g *Client) ChatRoster(cid *ChatID) error { - return g.client.Call("goog.ChatRoster", cid, &Empty{}) -} diff --git a/vendor/github.com/mattermost/rsc/google/gmail/gmail.go b/vendor/github.com/mattermost/rsc/google/gmail/gmail.go deleted file mode 100644 index 1d4072ef7..000000000 --- a/vendor/github.com/mattermost/rsc/google/gmail/gmail.go +++ /dev/null @@ -1,1241 +0,0 @@ -package main - -import ( - "bufio" - "bytes" - "flag" - "fmt" - "io" - "log" - "os" - "os/exec" - "os/signal" - "regexp" - "sort" - "strings" - "time" - - "github.com/mattermost/rsc/google" - "github.com/mattermost/rsc/imap" -) - -var cmdtab = []struct { - Name string - Args int - F func(*Cmd, *imap.MsgPart) *imap.MsgPart - TF func(*Cmd, []*imap.Msg) *imap.MsgPart - Help string -}{ - {"+", 0, pluscmd, tpluscmd, "+ print the next message"}, - {"a", 1, rcmd, nil, "a reply to sender and recipients"}, - {"b", 0, bcmd, nil, "b print the next 10 headers"}, - {"d", 0, dcmd, tdcmd, "d mark for deletion"}, - {"f", 1, fcmd, tfcmd, "f forward message"}, - {"h", 0, hcmd, nil, "h print elided message summary (,h for all)"}, - {"help", 0, nil, nil, "help print this info"}, - {"i", 0, icmd, nil, "i incorporate new mail"}, - {"m", 0, mcmd, tmcmd, "m mute and delete thread (gmail only)"}, - {"mime", 0, mimecmd, nil, "mime print message's MIME structure "}, - {"p", 0, pcmd, nil, "p print the processed message"}, - // { "p+", 0, pcmd, nil, "p print the processed message, showing all quoted text" }, - {"P", 0, Pcmd, nil, "P print the raw message"}, - {`"`, 0, quotecmd, nil, `" print a quoted version of msg`}, - {"q", 0, qcmd, nil, "q exit and remove all deleted mail"}, - {"r", 1, rcmd, nil, "r [addr] reply to sender plus any addrs specified"}, - {"s", 1, scmd, tscmd, "s name copy message to named mailbox (label for gmail)"}, - {"u", 0, ucmd, nil, "u remove deletion mark"}, - // { "w", 1, wcmd, nil, "w file store message contents as file" }, - {"W", 0, Wcmd, nil, "W open in web browser"}, - {"x", 0, xcmd, nil, "x exit without flushing deleted messages"}, - {"y", 0, ycmd, nil, "y synchronize with mail box"}, - {"=", 1, eqcmd, nil, "= print current message number"}, - {"|", 1, pipecmd, nil, "|cmd pipe message body to a command"}, - // { "||", 1, rpipecmd, nil, "||cmd pipe raw message to a command" }, - {"!", 1, bangcmd, nil, "!cmd run a command"}, -} - -func init() { - // Have to insert helpcmd by hand because it refers to cmdtab, - // so it would cause an init loop above. - for i := range cmdtab { - if cmdtab[i].Name == "help" { - cmdtab[i].F = helpcmd - } - } -} - -type Cmd struct { - Name string - Args []string - Line string // Args[0:] original text - ArgLine string // Args[1:] original text - F func(*Cmd, *imap.MsgPart) *imap.MsgPart - TF func(*Cmd, []*imap.Msg) *imap.MsgPart - Delete bool - Thread bool - Targ *imap.MsgPart - Targs []*imap.Msg - A1, A2 int -} - -var ( - bin = bufio.NewReader(os.Stdin) - bout = bufio.NewWriter(os.Stdout) - - acctName = flag.String("a", "", "account to use") - - dot *imap.MsgPart // Selected messages - - inbox *imap.Box - msgs []*imap.Msg - msgNum = make(map[*imap.Msg]int) - deleted = make(map[*imap.Msg]bool) - isGmail = false - acct google.Account - threaded bool - interrupted bool - - maxfrom int - subjlen int -) - -func nextMsg(m *imap.Msg) *imap.Msg { - i := msgNum[m] - i++ - if i >= len(msgs) { - return nil - } - return msgs[i] -} - -func main() { - flag.BoolVar(&imap.Debug, "imapdebug", false, "imap debugging trace") - flag.Parse() - - acct = google.Acct(*acctName) - - if args := flag.Args(); len(args) > 0 { - for i := range args { - args[i] = "-to=" + args[i] - } - cmd := exec.Command("gmailsend", append([]string{"-a", acct.Email, "-i"}, args...)...) - cmd.Stdin = os.Stdin - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - if err := cmd.Run(); err != nil { - fmt.Fprintf(os.Stderr, "!%s\n", err) - os.Exit(1) - } - return - } - - c, err := imap.NewClient(imap.TLS, "imap.gmail.com", acct.Email, acct.Password, "") - if err != nil { - log.Fatal(err) - } - isGmail = c.IsGmail() - threaded = isGmail - - inbox = c.Inbox() - if err := inbox.Check(); err != nil { - log.Fatal(err) - } - - msgs = inbox.Msgs() - maxfrom = 12 - for i, m := range msgs { - msgNum[m] = i - if n := len(from(m.Hdr)); n > maxfrom { - maxfrom = n - } - } - if maxfrom > 20 { - maxfrom = 20 - } - subjlen = 80 - maxfrom - - rethread() - - go func() { - for sig := range signal.Incoming { - if sig == os.SIGINT { - fmt.Fprintf(os.Stderr, "!interrupt\n") - interrupted = true - continue - } - if sig == os.SIGCHLD || sig == os.SIGWINCH { - continue - } - fmt.Fprintf(os.Stderr, "!%s\n", sig) - } - }() - - for { - if dot != nil { - fmt.Fprintf(bout, "%d", msgNum[dot.Msg]+1) - if dot != &dot.Msg.Root { - fmt.Fprintf(bout, ".%s", dot.ID) - } - } - fmt.Fprintf(bout, ": ") - bout.Flush() - - line, err := bin.ReadString('\n') - if err != nil { - break - } - - cmd, err := parsecmd(line) - if err != nil { - fmt.Fprintf(bout, "!%s\n", err) - continue - } - - if cmd.Targ != nil || cmd.Targs == nil && cmd.A2 == 0 { - x := cmd.F(cmd, cmd.Targ) - if x != nil { - dot = x - } - } else { - targs := cmd.Targs - if targs == nil { - delta := +1 - if cmd.A1 > cmd.A2 { - delta = -1 - } - for i := cmd.A1; i <= cmd.A2; i += delta { - if i < 1 || i > len(msgs) { - continue - } - targs = append(targs, msgs[i-1]) - } - } - if cmd.Thread { - if !isGmail { - fmt.Fprintf(bout, "!need gmail for threaded command\n") - continue - } - byThread := make(map[uint64][]*imap.Msg) - for _, m := range msgs { - t := m.GmailThread - byThread[t] = append(byThread[t], m) - } - for _, m := range targs { - t := m.GmailThread - if byThread[t] != nil { - if cmd.TF != nil { - if x := cmd.TF(cmd, byThread[t]); x != nil { - dot = x - } - } else { - for _, mm := range byThread[t] { - x := cmd.F(cmd, &mm.Root) - if x != nil { - dot = x - } - } - } - } - delete(byThread, t) - } - continue - } - for _, m := range targs { - if cmd.Delete { - dcmd(cmd, &m.Root) - if cmd.Name == "p" { - // dp is a special case: it advances to the next message before the p. - next := nextMsg(m) - if next == nil { - fmt.Fprintf(bout, "!address\n") - dot = &m.Root - break - } - m = next - } - } - x := cmd.F(cmd, &m.Root) - if x != nil { - dot = x - } - // TODO: Break loop on interrupt. - } - } - } - qcmd(nil, nil) -} - -func parsecmd(line string) (cmd *Cmd, err error) { - cmd = &Cmd{} - line = strings.TrimSpace(line) - if line == "" { - // Empty command is a special case: advance and print. - cmd.F = pcmd - if dot == nil { - cmd.A1 = 1 - cmd.A2 = 1 - } else { - n := msgNum[dot.Msg] + 2 - if n > len(msgs) { - return nil, fmt.Errorf("out of messages") - } - cmd.A1 = n - cmd.A2 = n - } - return cmd, nil - } - - // Global search? - if line[0] == 'g' { - line = line[1:] - if line == "" || line[0] != '/' { - // No search string means all messages. - cmd.A1 = 1 - cmd.A2 = len(msgs) - } else if line[0] == '/' { - re, rest, err := parsere(line) - if err != nil { - return nil, err - } - line = rest - // Find all messages matching this search string. - var targ []*imap.Msg - for _, m := range msgs { - if re.MatchString(header(m)) { - targ = append(targ, m) - } - } - if len(targ) == 0 { - return nil, fmt.Errorf("no matches") - } - cmd.Targs = targ - } - } else { - // Parse an address. - a1, targ, rest, err := parseaddr(line, 1) - if err != nil { - return nil, err - } - if targ != nil { - cmd.Targ = targ - line = rest - } else { - if a1 < 1 || a1 > len(msgs) { - return nil, fmt.Errorf("message number %d out of range", a1) - } - cmd.A1 = a1 - cmd.A2 = a1 - a2 := a1 - if rest != "" && rest[0] == ',' { - // This is an address range. - a2, targ, rest, err = parseaddr(rest[1:], len(msgs)) - if err != nil { - return nil, err - } - if a2 < 1 || a2 > len(msgs) { - return nil, fmt.Errorf("message number %d out of range", a2) - } - cmd.A2 = a2 - } else if rest == line { - // There was no address. - if dot == nil { - cmd.A1 = 1 - cmd.A2 = 0 - } else { - if dot != nil { - if dot == &dot.Msg.Root { - // If dot is a plain msg, use a range so that dp works. - cmd.A1 = msgNum[dot.Msg] + 1 - cmd.A2 = cmd.A1 - } else { - cmd.Targ = dot - } - } - } - } - line = rest - } - } - - cmd.Line = strings.TrimSpace(line) - - // Insert space after ! or | for tokenization. - switch { - case strings.HasPrefix(cmd.Line, "||"): - cmd.Line = cmd.Line[:2] + " " + cmd.Line[2:] - case strings.HasPrefix(cmd.Line, "!"), strings.HasPrefix(cmd.Line, "|"): - cmd.Line = cmd.Line[:1] + " " + cmd.Line[1:] - } - - av := strings.Fields(cmd.Line) - cmd.Args = av - if len(av) == 0 || av[0] == "" { - // Default is to print. - cmd.F = pcmd - return cmd, nil - } - - name := av[0] - cmd.ArgLine = strings.TrimSpace(cmd.Line[len(av[0]):]) - - // Hack to allow t prefix on all commands. - if len(name) >= 2 && name[0] == 't' { - cmd.Thread = true - name = name[1:] - } - - // Hack to allow d prefix on all commands. - if len(name) >= 2 && name[0] == 'd' { - cmd.Delete = true - name = name[1:] - } - cmd.Name = name - - // Search command table. - for _, ct := range cmdtab { - if ct.Name == name { - if ct.Args == 0 && len(av) > 1 { - return nil, fmt.Errorf("%s doesn't take an argument", name) - } - cmd.F = ct.F - cmd.TF = ct.TF - if name == "m" { - // mute applies to all thread no matter what - cmd.Thread = true - } - return cmd, nil - } - } - return nil, fmt.Errorf("unknown command %s", name) -} - -func parseaddr(addr string, deflt int) (n int, targ *imap.MsgPart, rest string, err error) { - dot := dot - n = deflt - for { - old := addr - n, targ, rest, err = parseaddr1(addr, n, dot) - if targ != nil || rest == old || err != nil { - break - } - if n < 1 || n > len(msgs) { - return 0, nil, "", fmt.Errorf("message number %d out of range", n) - } - dot = &msgs[n-1].Root - addr = rest - } - return -} - -func parseaddr1(addr string, deflt int, dot *imap.MsgPart) (n int, targ *imap.MsgPart, rest string, err error) { - base := 0 - if dot != nil { - base = msgNum[dot.Msg] + 1 - } - if addr == "" { - return deflt, nil, addr, nil - } - var i int - sign := 0 - switch c := addr[0]; c { - case '+': - sign = +1 - addr = addr[1:] - case '-': - sign = -1 - addr = addr[1:] - case '.': - if base == 0 { - return 0, nil, "", fmt.Errorf("no message selected") - } - n = base - i = 1 - goto HaveNumber - case '$': - if len(msgs) == 0 { - return 0, nil, "", fmt.Errorf("no messages") - } - n = len(msgs) - i = 1 - goto HaveNumber - case '/', '?': - var re *regexp.Regexp - re, addr, err = parsere(addr) - if err != nil { - return - } - var delta int - if c == '/' { - delta = +1 - } else { - delta = -1 - } - for j := base + delta; 1 <= j && j <= len(msgs); j += delta { - if re.MatchString(header(msgs[j-1])) { - n = j - i = 0 // already cut addr - goto HaveNumber - } - } - err = fmt.Errorf("search") - return - // TODO case '%' - } - for i = 0; i < len(addr) && '0' <= addr[i] && addr[i] <= '9'; i++ { - n = 10*n + int(addr[i]) - '0' - } - if sign != 0 { - if n == 0 { - n = 1 - } - n = base + n*sign - goto HaveNumber - } - if i == 0 { - return deflt, nil, addr, nil - } -HaveNumber: - rest = addr[i:] - if i < len(addr) && addr[i] == '.' { - if n < 1 || n > len(msgs) { - err = fmt.Errorf("message number %d out of range", n) - return - } - targ = &msgs[n-1].Root - for i < len(addr) && addr[i] == '.' { - i++ - var j int - n = 0 - for j = i; j < len(addr) && '0' <= addr[j] && addr[j] <= '9'; j++ { - n = 10*n + int(addr[j]) - '0' - } - if j == i { - err = fmt.Errorf("malformed message number %s", addr[:j]) - return - } - if n < 1 || n > len(targ.Child) { - err = fmt.Errorf("message number %s out of range", addr[:j]) - return - } - targ = targ.Child[n-1] - i = j - } - n = 0 - rest = addr[i:] - return - } - return -} - -func parsere(addr string) (re *regexp.Regexp, rest string, err error) { - prog, rest, err := parseprog(addr) - if err != nil { - return - } - re, err = regexp.Compile(prog) - return -} - -var lastProg string - -func parseprog(addr string) (prog string, rest string, err error) { - if len(addr) == 1 { - if lastProg != "" { - return lastProg, "", nil - } - err = fmt.Errorf("no search") - return - } - i := strings.Index(addr[1:], addr[:1]) - if i < 0 { - prog = addr[1:] - rest = "" - } else { - i += 1 // adjust for slice in IndexByte arg - prog, rest = addr[1:i], addr[i+1:] - } - lastProg = prog - return -} - -func bcmd(c *Cmd, dot *imap.MsgPart) *imap.MsgPart { - var m *imap.Msg - if dot == nil { - if len(msgs) == 0 { - return nil - } - m = msgs[0] - } else { - m = dot.Msg - } - for i := 0; i < 10; i++ { - hcmd(c, &m.Root) - next := nextMsg(m) - if next == nil { - break - } - m = next - } - return &m.Root -} - -func dcmd(c *Cmd, dot *imap.MsgPart) *imap.MsgPart { - if dot == nil { - fmt.Fprintf(bout, "!address\n") - return nil - } - deleted[dot.Msg] = true - return &dot.Msg.Root -} - -func tdcmd(c *Cmd, msgs []*imap.Msg) *imap.MsgPart { - if len(msgs) == 0 { - fmt.Fprintf(bout, "!address\n") - return nil - } - for _, m := range msgs { - deleted[m] = true - } - return &msgs[len(msgs)-1].Root -} - -func ucmd(c *Cmd, dot *imap.MsgPart) *imap.MsgPart { - if dot == nil { - fmt.Fprintf(bout, "!address\n") - return nil - } - delete(deleted, dot.Msg) - return &dot.Msg.Root -} - -func eqcmd(c *Cmd, dot *imap.MsgPart) *imap.MsgPart { - if dot == nil { - fmt.Fprintf(bout, "0") - } else { - fmt.Fprintf(bout, "%d", msgNum[dot.Msg]+1) - if dot != &dot.Msg.Root { - fmt.Fprintf(bout, ".%s", dot.ID) - } - } - fmt.Fprintf(bout, "\n") - return nil -} - -func from(h *imap.MsgHdr) string { - if len(h.From) < 1 { - return "?" - } - if name := h.From[0].Name; name != "" { - return name - } - return h.From[0].Email -} - -func header(m *imap.Msg) string { - var t string - if time.Now().Sub(m.Date) > 365*24*time.Hour { - t = m.Date.Format("01/02 15:04") - } else { - t = m.Date.Format("01/02 2006 ") - } - ch := ' ' - if len(m.Root.Child) > 1 || len(m.Root.Child) == 1 && len(m.Root.Child[0].Child) > 0 { - ch = 'H' - } - del := ' ' - if deleted[m] { - del = 'd' - } - return fmt.Sprintf("%-3d %c%c %s %-*.*s %.*s", - msgNum[m]+1, ch, del, t, - maxfrom, maxfrom, from(m.Hdr), - subjlen, m.Hdr.Subject) -} - -func hcmd(c *Cmd, dot *imap.MsgPart) *imap.MsgPart { - if dot != nil { - fmt.Fprintf(bout, "%s\n", header(dot.Msg)) - } - return nil -} - -func helpcmd(c *Cmd, dot *imap.MsgPart) *imap.MsgPart { - fmt.Fprint(bout, "Commands are of the form [] [args]\n") - fmt.Fprint(bout, " := | ','| 'g'\n") - fmt.Fprint(bout, " := '.' | '$' | '^' | | | '+' | '-'\n") - fmt.Fprint(bout, " := '/''/' | '?''?'\n") - fmt.Fprint(bout, " :=\n") - for _, ct := range cmdtab { - fmt.Fprintf(bout, "%s\n", ct.Help) - } - return dot -} - -func mimecmd(c *Cmd, dot *imap.MsgPart) *imap.MsgPart { - if dot != nil { - mimeH(fmt.Sprint(msgNum[dot.Msg]+1), dot) - } - return nil -} - -func mimeH(id string, p *imap.MsgPart) { - if p.ID != "" { - id = id + "." + p.ID - } - fmt.Fprintf(bout, "%s %s %s %#q %d\n", id, p.Type, p.Encoding+"/"+p.Charset, p.Name, p.Bytes) - for _, child := range p.Child { - mimeH(id, child) - } -} - -func icmd(c *Cmd, dot *imap.MsgPart) *imap.MsgPart { - sync(false) - return nil -} - -func ycmd(c *Cmd, dot *imap.MsgPart) *imap.MsgPart { - sync(true) - return nil -} - -func tpluscmd(c *Cmd, msgs []*imap.Msg) *imap.MsgPart { - if len(msgs) == 0 { - return nil - } - m := nextMsg(msgs[len(msgs)-1]) - if m == nil { - fmt.Fprintf(bout, "!no more messages\n") - return nil - } - return pcmd(c, &m.Root) -} - -func pluscmd(c *Cmd, dot *imap.MsgPart) *imap.MsgPart { - if dot == nil { - return nil - } - m := nextMsg(dot.Msg) - if m == nil { - fmt.Fprintf(bout, "!no more messages\n") - return nil - } - return pcmd(c, &m.Root) -} - -func addrlist(x []imap.Addr) string { - var b bytes.Buffer - for i, a := range x { - if i > 0 { - b.WriteString(", ") - } - b.WriteString(a.String()) - } - return b.String() -} - -func wpcmd(w io.Writer, c *Cmd, dot *imap.MsgPart) *imap.MsgPart { - if dot == nil { - return nil - } - if dot == &dot.Msg.Root { - h := dot.Msg.Hdr - if len(h.From) > 0 { - fmt.Fprintf(w, "From: %s\n", addrlist(h.From)) - } - fmt.Fprintf(w, "Date: %s\n", dot.Msg.Date) - if len(h.From) > 0 { - fmt.Fprintf(w, "To: %s\n", addrlist(h.To)) - } - if len(h.CC) > 0 { - fmt.Fprintf(w, "CC: %s\n", addrlist(h.CC)) - } - if len(h.BCC) > 0 { - fmt.Fprintf(w, "BCC: %s\n", addrlist(h.BCC)) - } - if len(h.Subject) > 0 { - fmt.Fprintf(w, "Subject: %s\n", h.Subject) - } - fmt.Fprintf(w, "\n") - } - printMIME(w, dot, true) - fmt.Fprintf(w, "\n") - return dot -} - -func pcmd(c *Cmd, dot *imap.MsgPart) *imap.MsgPart { - defer bout.Flush() - return wpcmd(bout, c, dot) -} - -func pipecmd(c *Cmd, dot *imap.MsgPart) *imap.MsgPart { - args := c.Args[1:] - if len(args) == 0 { - fmt.Fprintf(bout, "!no command\n") - return dot - } - bout.Flush() - cmd := exec.Command(args[0], args[1:]...) - w, err := cmd.StdinPipe() - if err != nil { - fmt.Fprintf(bout, "!%s\n", err) - return dot - } - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - if err := cmd.Start(); err != nil { - fmt.Fprintf(bout, "!%s\n", err) - return dot - } - wpcmd(w, c, dot) - w.Close() - if err := cmd.Wait(); err != nil { - fmt.Fprintf(bout, "!%s\n", err) - } - return dot -} - -func bangcmd(c *Cmd, dot *imap.MsgPart) *imap.MsgPart { - args := c.Args[1:] - if len(args) == 0 { - fmt.Fprintf(bout, "!no command\n") - return dot - } - bout.Flush() - cmd := exec.Command(args[0], args[1:]...) - cmd.Stdin = os.Stdin - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - if err := cmd.Run(); err != nil { - fmt.Fprintf(bout, "!%s\n", err) - } - return nil -} - -func unixfrom(h *imap.MsgHdr) string { - if len(h.From) == 0 { - return "" - } - return h.From[0].Email -} - -func unixtime(m *imap.Msg) string { - return dot.Msg.Date.Format("Mon Jan _2 15:04:05 MST 2006") -} - -func Pcmd(c *Cmd, dot *imap.MsgPart) *imap.MsgPart { - if dot == nil { - return nil - } - if dot == &dot.Msg.Root { - fmt.Fprintf(bout, "From %s %s\n", - unixfrom(dot.Msg.Hdr), - unixtime(dot.Msg)) - } - bout.Write(dot.Raw()) - return dot -} - -func printMIME(w io.Writer, p *imap.MsgPart, top bool) { - switch { - case top && strings.HasPrefix(p.Type, "text/"): - text := p.ShortText() - if p.Type == "text/html" { - cmd := exec.Command("htmlfmt") - cmd.Stdin = bytes.NewBuffer(text) - if w == bout { - bout.Flush() - cmd.Stdout = os.Stdout - } else { - cmd.Stdout = w - } - if err := cmd.Run(); err != nil { - fmt.Fprintf(w, "%d.%s !%s\n", msgNum[p.Msg]+1, p.ID, err) - } - return - } - w.Write(text) - case p.Type == "text/plain": - if top { - panic("printMIME loop") - } - printMIME(w, p, true) - case p.Type == "multipart/alternative": - for _, pp := range p.Child { - if pp.Type == "text/plain" { - printMIME(w, pp, false) - return - } - } - if len(p.Child) > 0 { - printMIME(w, p.Child[0], false) - } - case strings.HasPrefix(p.Type, "multipart/"): - for _, pp := range p.Child { - printMIME(w, pp, false) - } - default: - fmt.Fprintf(w, "%d.%s !%s %s %s\n", msgNum[p.Msg]+1, p.ID, p.Type, p.Desc, p.Name) - } -} - -func qcmd(c *Cmd, dot *imap.MsgPart) *imap.MsgPart { - flushDeleted() - xcmd(c, dot) - panic("not reached") -} - -type quoter struct { - bol bool - w io.Writer -} - -func (q *quoter) Write(b []byte) (n int, err error) { - n = len(b) - err = nil - for len(b) > 0 { - if q.bol { - q.w.Write([]byte("> ")) - q.bol = false - } - i := bytes.IndexByte(b, '\n') - if i < 0 { - i = len(b) - } else { - q.bol = true - i++ - } - q.w.Write(b[:i]) - b = b[i:] - } - return -} - -func quotecmd(c *Cmd, dot *imap.MsgPart) *imap.MsgPart { - if dot == nil { - return nil - } - m := dot.Msg - if len(m.Hdr.From) != 0 { - a := m.Hdr.From[0] - name := a.Name - if name == "" { - name = a.Email - } - date := m.Date.Format("Jan 2, 2006 at 15:04") - fmt.Fprintf(bout, "On %s, %s wrote:\n", date, name) - } - printMIME("er{true, bout}, dot, true) - return dot -} - -func addre(s string) string { - if len(s) < 4 || !strings.EqualFold(s[:4], "re: ") { - return "Re: " + s - } - return s -} - -func rcmd(c *Cmd, dot *imap.MsgPart) *imap.MsgPart { - if dot == nil || dot.Msg.Hdr == nil { - fmt.Fprintf(bout, "!nothing to reply to\n") - return nil - } - - h := dot.Msg.Hdr - replyTo := h.ReplyTo - have := make(map[string]bool) - if len(replyTo) == 0 { - replyTo = h.From - } - if c.Name[0] == 'a' { - for _, a := range replyTo { - have[a.Email] = true - } - for _, a := range append(append(append([]imap.Addr(nil), h.From...), h.To...), h.CC...) { - if !have[a.Email] { - have[a.Email] = true - replyTo = append(replyTo, a) - } - } - } - if len(replyTo) == 0 { - fmt.Fprintf(bout, "!no one to reply to\n") - return dot - } - - args := []string{"-a", acct.Email, "-s", addre(h.Subject), "-in-reply-to", h.MessageID} - fmt.Fprintf(bout, "replying to:") - for _, a := range replyTo { - fmt.Fprintf(bout, " %s", a.Email) - args = append(args, "-to", a.String()) - } - for _, arg := range c.Args[1:] { - fmt.Fprintf(bout, " %s", arg) - args = append(args, "-to", arg) - } - fmt.Fprintf(bout, "\n") - bout.Flush() - cmd := exec.Command("gmailsend", args...) - cmd.Stdin = os.Stdin - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - err := cmd.Run() - if err != nil { - fmt.Fprintf(bout, "!%s\n", err) - } - return dot -} - -func fcmd(c *Cmd, dot *imap.MsgPart) *imap.MsgPart { - if dot == nil { - fmt.Fprintf(bout, "!nothing to forward\n") - return nil - } - - return fwd(c, dot, nil) -} - -func tfcmd(c *Cmd, msgs []*imap.Msg) *imap.MsgPart { - if len(msgs) == 0 { - fmt.Fprintf(bout, "!nothing to forward\n") - return nil - } - - return fwd(c, &msgs[len(msgs)-1].Root, msgs) -} - -func fwd(c *Cmd, dot *imap.MsgPart, msgs []*imap.Msg) *imap.MsgPart { - addrs := c.Args[1:] - if len(addrs) == 0 { - fmt.Fprintf(bout, "!f command requires address to forward to\n") - return dot - } - - h := dot.Msg.Hdr - args := []string{"-a", acct.Email, "-s", "Fwd: " + h.Subject, "-append", "/dev/fd/3"} - fmt.Fprintf(bout, "forwarding to:") - for _, arg := range addrs { - fmt.Fprintf(bout, " %s", arg) - args = append(args, "-to", arg) - } - fmt.Fprintf(bout, "\n") - bout.Flush() - - cmd := exec.Command("gmailsend", args...) - r, w, err := os.Pipe() - if err != nil { - fmt.Fprintf(bout, "!%s\n", err) - return dot - } - cmd.Stdin = os.Stdin - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - cmd.ExtraFiles = []*os.File{r} - if err := cmd.Start(); err != nil { - r.Close() - fmt.Fprintf(bout, "!%s\n", err) - return dot - } - r.Close() - what := "message" - if len(msgs) > 1 { - what = "conversation" - } - fmt.Fprintf(w, "\n\n--- Forwarded %s ---\n", what) - if msgs == nil { - wpcmd(w, c, dot) - } else { - for _, m := range msgs { - wpcmd(w, c, &m.Root) - fmt.Fprintf(w, "\n\n") - } - } - w.Close() - if err := cmd.Wait(); err != nil { - fmt.Fprintf(bout, "!%s\n", err) - } - return dot -} - -func rethread() { - if !threaded { - sort.Sort(byUIDRev(msgs)) - } else { - byThread := make(map[uint64][]*imap.Msg) - for _, m := range msgs { - t := m.GmailThread - byThread[t] = append(byThread[t], m) - } - - var threadList [][]*imap.Msg - for _, t := range byThread { - sort.Sort(byUID(t)) - threadList = append(threadList, t) - } - sort.Sort(byUIDList(threadList)) - - msgs = msgs[:0] - for _, t := range threadList { - msgs = append(msgs, t...) - } - } - for i, m := range msgs { - msgNum[m] = i - } -} - -type byUID []*imap.Msg - -func (l byUID) Less(i, j int) bool { return l[i].UID < l[j].UID } -func (l byUID) Len() int { return len(l) } -func (l byUID) Swap(i, j int) { l[i], l[j] = l[j], l[i] } - -type byUIDRev []*imap.Msg - -func (l byUIDRev) Less(i, j int) bool { return l[i].UID > l[j].UID } -func (l byUIDRev) Len() int { return len(l) } -func (l byUIDRev) Swap(i, j int) { l[i], l[j] = l[j], l[i] } - -type byUIDList [][]*imap.Msg - -func (l byUIDList) Less(i, j int) bool { return l[i][len(l[i])-1].UID > l[j][len(l[j])-1].UID } -func (l byUIDList) Len() int { return len(l) } -func (l byUIDList) Swap(i, j int) { l[i], l[j] = l[j], l[i] } - -func subj(m *imap.Msg) string { - s := m.Hdr.Subject - for strings.HasPrefix(s, "Re: ") || strings.HasPrefix(s, "RE: ") { - s = s[4:] - } - return s -} - -func mcmd(c *Cmd, dot *imap.MsgPart) *imap.MsgPart { - c.ArgLine = "Muted" - scmd(c, dot) - return dcmd(c, dot) -} - -func tmcmd(c *Cmd, msgs []*imap.Msg) *imap.MsgPart { - c.ArgLine = "Muted" - tscmd(c, msgs) - return tdcmd(c, msgs) -} - -func scmd(c *Cmd, dot *imap.MsgPart) *imap.MsgPart { - if dot == nil { - return nil - } - return tscmd(c, []*imap.Msg{dot.Msg}) -} - -func tscmd(c *Cmd, msgs []*imap.Msg) *imap.MsgPart { - if len(msgs) == 0 { - return nil - } - arg := c.ArgLine - dot := &msgs[len(msgs)-1].Root - if arg == "" { - fmt.Fprintf(bout, "!s needs mailbox (label) name as argument\n") - return dot - } - if strings.EqualFold(arg, "Muted") { - if err := dot.Msg.Box.Mute(msgs); err != nil { - fmt.Fprintf(bout, "!mute: %s\n", err) - } - } else { - dst := dot.Msg.Box.Client.Box(arg) - if dst == nil { - fmt.Fprintf(bout, "!unknown mailbox %#q", arg) - return dot - } - if err := dst.Copy(msgs); err != nil { - fmt.Fprintf(bout, "!s %#q: %s\n", arg, err) - } - } - return dot -} - -func Wcmd(c *Cmd, dot *imap.MsgPart) *imap.MsgPart { - if dot == nil { - return nil - } - if !isGmail { - fmt.Fprintf(bout, "!cmd W requires gmail\n") - return dot - } - url := fmt.Sprintf("https://mail.google.com/mail/b/%s/?shva=1#inbox/%x", acct.Email, dot.Msg.GmailThread) - if err := exec.Command("open", url).Run(); err != nil { - fmt.Fprintf(bout, "!%s\n", err) - } - return dot -} - -func xcmd(c *Cmd, dot *imap.MsgPart) *imap.MsgPart { - // TODO: remove saved attachments? - os.Exit(0) - panic("not reached") -} - -func flushDeleted() { - var toDelete []*imap.Msg - for m := range deleted { - toDelete = append(toDelete, m) - } - if len(toDelete) == 0 { - return - } - fmt.Fprintf(os.Stderr, "!deleting %d\n", len(toDelete)) - err := inbox.Delete(toDelete) - if err != nil { - fmt.Fprintf(os.Stderr, "!deleting: %s\n", err) - } -} - -func loadNew() { - if err := inbox.Check(); err != nil { - fmt.Fprintf(os.Stderr, "!inbox: %s\n", err) - } - - old := make(map[*imap.Msg]bool) - for _, m := range msgs { - old[m] = true - } - - nnew := 0 - new := inbox.Msgs() - for _, m := range new { - if old[m] { - delete(old, m) - } else { - msgs = append(msgs, m) - nnew++ - } - } - if nnew > 0 { - fmt.Fprintf(os.Stderr, "!%d new messages\n", nnew) - } - for m := range old { - // Deleted - m.Flags |= imap.FlagDeleted - delete(deleted, m) - } -} - -func sync(delete bool) { - if delete { - flushDeleted() - } - loadNew() - if delete { - w := 0 - for _, m := range msgs { - if !m.Deleted() { - msgs[w] = m - w++ - } - } - msgs = msgs[:w] - } - rethread() -} diff --git a/vendor/github.com/mattermost/rsc/google/gmailsend/send.go b/vendor/github.com/mattermost/rsc/google/gmailsend/send.go deleted file mode 100644 index ace6eb12b..000000000 --- a/vendor/github.com/mattermost/rsc/google/gmailsend/send.go +++ /dev/null @@ -1,370 +0,0 @@ -package main - -import ( - "bufio" - "bytes" - "encoding/base64" - "flag" - "fmt" - "io" - "net/smtp" - "os" - "regexp" - "strings" - - "github.com/mattermost/rsc/google" -) - -func enc(s string) string { - // TODO =? .. ?= - return s -} - -type Addr struct { - Name string - Email string -} - -func (a Addr) enc() string { - if a.Name == "" { - return "<" + a.Email + ">" - } - if a.Email == "" { - return enc(a.Name) + ":;" - } - return enc(a.Name) + " <" + a.Email + ">" -} - -type Addrs []Addr - -func (a *Addrs) String() string { - return "[addrlist]" -} - -func (a Addrs) has(s string) bool { - for _, aa := range a { - if aa.Email == s { - return true - } - } - return false -} - -func (a *Addrs) Set(s string) bool { - s = strings.TrimSpace(s) - if strings.HasSuffix(s, ">") { - j := strings.LastIndex(s, "<") - if j >= 0 { - *a = append(*a, Addr{strings.TrimSpace(s[:j]), s[j+1 : len(s)-1]}) - return true - } - } - - if strings.Contains(s, " ") { - fmt.Fprintf(os.Stderr, "invalid address: %s", s) - os.Exit(2) - } - *a = append(*a, Addr{"", s}) - return true -} - -func (a *Addrs) parseLine(s string) { - for _, f := range strings.Split(s, ",") { - f = strings.TrimSpace(f) - if f != "" { - a.Set(f) - } - } -} - -func (a Addrs) fixDomain() { - i := strings.Index(acct.Email, "@") - if i < 0 { - return - } - dom := acct.Email[i:] - for i := range a { - if a[i].Email != "" && !strings.Contains(a[i].Email, "@") { - a[i].Email += dom - } - } -} - -var from, to, cc, bcc, replyTo Addrs -var inReplyTo, subject string -var appendFile = flag.String("append", "", "file to append to end of body") - -var acct google.Account -var acctName = flag.String("a", "", "account to use") -var inputHeader = flag.Bool("i", false, "read additional header lines from stdin") - -func holdmode() { - if os.Getenv("TERM") == "9term" { - // forgive me - os.Stdout.WriteString("\x1B];*9term-hold+\x07") - } -} - -func match(line, prefix string, arg *string) bool { - if len(line) < len(prefix) || !strings.EqualFold(line[:len(prefix)], prefix) { - return false - } - *arg = strings.TrimSpace(line[len(prefix):]) - return true -} - -func main() { - flag.StringVar(&inReplyTo, "in-reply-to", "", "In-Reply-To") - flag.StringVar(&subject, "s", "", "Subject") - flag.Var(&from, "from", "From (can repeat)") - flag.Var(&to, "to", "To (can repeat)") - flag.Var(&cc, "cc", "CC (can repeat)") - flag.Var(&bcc, "bcc", "BCC (can repeat)") - flag.Var(&replyTo, "replyTo", "Reply-To (can repeat)") - - flag.Parse() - if flag.NArg() != 0 && !*inputHeader { - flag.Usage() - } - - var body bytes.Buffer - input := bufio.NewReader(os.Stdin) - if *inputHeader { - holdmode() - Loop: - for { - s, err := input.ReadString('\n') - if err != nil { - if err == io.EOF { - break Loop - } - fmt.Fprintf(os.Stderr, "reading stdin: %s\n", err) - os.Exit(2) - } - var arg string - switch { - default: - if ok, _ := regexp.MatchString(`^\S+:`, s); ok { - fmt.Fprintf(os.Stderr, "unknown header line: %s", s) - os.Exit(2) - } - body.WriteString(s) - break Loop - case match(s, "from:", &arg): - from.parseLine(arg) - case match(s, "to:", &arg): - to.parseLine(arg) - case match(s, "cc:", &arg): - cc.parseLine(arg) - case match(s, "bcc:", &arg): - bcc.parseLine(arg) - case match(s, "reply-to:", &arg): - replyTo.parseLine(arg) - case match(s, "subject:", &arg): - subject = arg - case match(s, "in-reply-to:", &arg): - inReplyTo = arg - } - } - } - - acct = google.Acct(*acctName) - from.fixDomain() - to.fixDomain() - cc.fixDomain() - bcc.fixDomain() - replyTo.fixDomain() - - smtpTo := append(append(to, cc...), bcc...) - - if len(from) == 0 { - // TODO: Much better - name := "" - email := acct.Email - if email == "rsc@swtch.com" || email == "rsc@google.com" { - name = "Russ Cox" - } - if email == "rsc@google.com" && (smtpTo.has("go@googlecode.com") || smtpTo.has("golang-dev@googlegroups.com") || smtpTo.has("golang-nuts@googlegroups.com")) { - from = append(from, Addr{name, "rsc@golang.org"}) - } else { - from = append(from, Addr{name, email}) - } - } - - if len(from) > 1 { - fmt.Fprintf(os.Stderr, "missing -from\n") - os.Exit(2) - } - - if len(to)+len(cc)+len(bcc) == 0 { - fmt.Fprintf(os.Stderr, "missing destinations\n") - os.Exit(2) - } - - if !*inputHeader { - holdmode() - } - _, err := io.Copy(&body, input) - if err != nil { - fmt.Fprintf(os.Stderr, "reading stdin: %s\n", err) - os.Exit(2) - } - - if *appendFile != "" { - f, err := os.Open(*appendFile) - if err != nil { - fmt.Fprintf(os.Stderr, "append: %s\n", err) - os.Exit(2) - } - _, err = io.Copy(&body, f) - f.Close() - if err != nil { - fmt.Fprintf(os.Stderr, "append: %s\n", err) - os.Exit(2) - } - } - - var msg bytes.Buffer - fmt.Fprintf(&msg, "MIME-Version: 1.0\n") - if len(from) > 0 { - fmt.Fprintf(&msg, "From: ") - for i, a := range from { - if i > 0 { - fmt.Fprintf(&msg, ", ") - } - fmt.Fprintf(&msg, "%s", a.enc()) - } - fmt.Fprintf(&msg, "\n") - } - if len(to) > 0 { - fmt.Fprintf(&msg, "To: ") - for i, a := range to { - if i > 0 { - fmt.Fprintf(&msg, ", ") - } - fmt.Fprintf(&msg, "%s", a.enc()) - } - fmt.Fprintf(&msg, "\n") - } - if len(cc) > 0 { - fmt.Fprintf(&msg, "CC: ") - for i, a := range cc { - if i > 0 { - fmt.Fprintf(&msg, ", ") - } - fmt.Fprintf(&msg, "%s", a.enc()) - } - fmt.Fprintf(&msg, "\n") - } - if len(replyTo) > 0 { - fmt.Fprintf(&msg, "Reply-To: ") - for i, a := range replyTo { - if i > 0 { - fmt.Fprintf(&msg, ", ") - } - fmt.Fprintf(&msg, "%s", a.enc()) - } - fmt.Fprintf(&msg, "\n") - } - if inReplyTo != "" { - fmt.Fprintf(&msg, "In-Reply-To: %s\n", inReplyTo) - } - if subject != "" { - fmt.Fprintf(&msg, "Subject: %s\n", enc(subject)) - } - fmt.Fprintf(&msg, "Date: xxx\n") - fmt.Fprintf(&msg, "Content-Type: text/plain; charset=\"utf-8\"\n") - fmt.Fprintf(&msg, "Content-Transfer-Encoding: base64\n") - fmt.Fprintf(&msg, "\n") - enc64 := base64.StdEncoding.EncodeToString(body.Bytes()) - for len(enc64) > 72 { - fmt.Fprintf(&msg, "%s\n", enc64[:72]) - enc64 = enc64[72:] - } - fmt.Fprintf(&msg, "%s\n\n", enc64) - - auth := smtp.PlainAuth( - "", - acct.Email, - acct.Password, - "smtp.gmail.com", - ) - var smtpToEmail []string - for _, a := range smtpTo { - if a.Email != "" { - smtpToEmail = append(smtpToEmail, a.Email) - } - } - - if err := sendMail("smtp.gmail.com:587", auth, from[0].Email, smtpToEmail, msg.Bytes()); err != nil { - fmt.Fprintf(os.Stderr, "sending mail: %s\n", err) - os.Exit(2) - } -} - -/* - MIME-Version: 1.0 -Subject: commit/plan9port: rsc: 9term: hold mode back door -From: Bitbucket -To: plan9port-dev@googlegroups.com -Date: Tue, 11 Oct 2011 13:34:30 -0000 -Message-ID: <20111011133430.31146.55070@bitbucket13.managed.contegix.com> -Reply-To: commits-noreply@bitbucket.org -Content-Type: text/plain; charset="utf-8" -Content-Transfer-Encoding: quoted-printable - -1 new changeset in plan9port: - -http://bitbucket.org/rsc/plan9port/changeset/8735d7708a1b/ -changeset: 8735d7708a1b -user: rsc -date: 2011-10-11 15:34:25 -summary: 9term: hold mode back door - -R=3Drsc -http://codereview.appspot.com/5248056 -affected #: 2 files (-1 bytes) - -Repository URL: https://bitbucket.org/rsc/plan9port/ - --- - -This is a commit notification from bitbucket.org. You are receiving -this because you have the service enabled, addressing the recipient of -this email. - -*/ - -func sendMail(addr string, a smtp.Auth, from string, to []string, msg []byte) error { - c, err := smtp.Dial(addr) - if err != nil { - return err - } - if err = c.StartTLS(nil); err != nil { - return err - } - if err = c.Auth(a); err != nil { - return err - } - if err = c.Mail(from); err != nil { - return err - } - for _, addr := range to { - if err = c.Rcpt(addr); err != nil { - return err - } - } - w, err := c.Data() - if err != nil { - return err - } - _, err = w.Write(msg) - if err != nil { - return err - } - err = w.Close() - if err != nil { - return err - } - return c.Quit() -} diff --git a/vendor/github.com/mattermost/rsc/google/googleserver/chat.go b/vendor/github.com/mattermost/rsc/google/googleserver/chat.go deleted file mode 100644 index 8b064dc92..000000000 --- a/vendor/github.com/mattermost/rsc/google/googleserver/chat.go +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// TODO: Add ChatHangup. -// TODO: Auto-hangup chats that are gone. - -package main - -import ( - "fmt" - - "github.com/mattermost/rsc/google" - "github.com/mattermost/rsc/xmpp" -) - -type chatClient struct { - email string - id string - xmpp *xmpp.Client -} - -var chatClients = map[string]*chatClient{} - -func (*Server) chatClient(cid *google.ChatID) (*chatClient, error) { - id := cid.ID - cc := chatClients[cid.ID] - if cc == nil { - a := google.Cfg.AccountByEmail(cid.Email) - if a == nil { - return nil, fmt.Errorf("unknown account %s", cid.Email) - } - // New client. - cli, err := xmpp.NewClient("talk.google.com:443", a.Email, a.Password) - if err != nil { - return nil, err - } - cc = &chatClient{email: a.Email, id: id, xmpp: cli} - cc.xmpp.Status(cid.Status, cid.StatusMsg) - chatClients[id] = cc - } - return cc, nil -} - -func (srv *Server) ChatRecv(cid *google.ChatID, msg *xmpp.Chat) error { - cc, err := srv.chatClient(cid) - if err != nil { - return err - } - chat, err := cc.xmpp.Recv() - if err != nil { - return err - } - *msg = chat - return nil -} - -func (srv *Server) ChatStatus(cid *google.ChatID, _ *Empty) error { - cc, err := srv.chatClient(cid) - if err != nil { - return err - } - return cc.xmpp.Status(cid.Status, cid.StatusMsg) -} - -func (srv *Server) ChatSend(arg *google.ChatSend, _ *Empty) error { - cc, err := srv.chatClient(arg.ID) - if err != nil { - return err - } - return cc.xmpp.Send(arg.Msg) -} - -func (srv *Server) ChatRoster(cid *google.ChatID, _ *Empty) error { - cc, err := srv.chatClient(cid) - if err != nil { - return err - } - return cc.xmpp.Roster() -} diff --git a/vendor/github.com/mattermost/rsc/google/googleserver/main.go b/vendor/github.com/mattermost/rsc/google/googleserver/main.go deleted file mode 100644 index 2cd022446..000000000 --- a/vendor/github.com/mattermost/rsc/google/googleserver/main.go +++ /dev/null @@ -1,139 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package main - -import ( - // "flag" - "bufio" - "fmt" - "log" - "net" - "net/rpc" - "os" - "strings" - "syscall" - - "github.com/mattermost/rsc/google" - "github.com/mattermost/rsc/xmpp" -) - -func main() { - google.ReadConfig() - switch os.Args[1] { - case "add": - google.Cfg.Account = append(google.Cfg.Account, &google.Account{Email: os.Args[2], Password: os.Args[3]}) - google.WriteConfig() - case "serve": - serve() - case "accounts": - c, err := google.Dial() - if err != nil { - log.Fatal(err) - } - out, err := c.Accounts() - if err != nil { - log.Fatal(err) - } - for _, email := range out { - fmt.Printf("%s\n", email) - } - case "ping": - c, err := google.Dial() - if err != nil { - log.Fatal(err) - } - if err := c.Ping(); err != nil { - log.Fatal(err) - } - case "chat": - c, err := google.Dial() - if err != nil { - log.Fatal(err) - } - cid := &google.ChatID{ID: "1", Email: os.Args[2], Status: xmpp.Available, StatusMsg: ""} - go chatRecv(c, cid) - c.ChatRoster(cid) - b := bufio.NewReader(os.Stdin) - for { - line, err := b.ReadString('\n') - if err != nil { - log.Fatal(err) - } - line = line[:len(line)-1] - i := strings.Index(line, ": ") - if i < 0 { - log.Printf(": , please") - continue - } - who, msg := line[:i], line[i+2:] - if err := c.ChatSend(cid, &xmpp.Chat{Remote: who, Type: "chat", Text: msg}); err != nil { - log.Fatal(err) - } - } - } -} - -func chatRecv(c *google.Client, cid *google.ChatID) { - for { - msg, err := c.ChatRecv(cid) - if err != nil { - log.Fatal(err) - } - switch msg.Type { - case "roster": - for _, contact := range msg.Roster { - fmt.Printf("%v\n", contact) - } - case "presence": - fmt.Printf("%v\n", msg.Presence) - case "chat": - fmt.Printf("%s: %s\n", msg.Remote, msg.Text) - default: - fmt.Printf("<%s>\n", msg.Type) - } - } -} - -func listen() net.Listener { - socket := google.Dir() + "/socket" - os.Remove(socket) - l, err := net.Listen("unix", socket) - if err != nil { - log.Fatal(err) - } - return l -} - -func serve() { - f, err := os.OpenFile(google.Dir()+"/log", os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0600) - if err != nil { - log.Fatal(err) - } - log.SetOutput(f) - syscall.Dup2(f.Fd(), 2) - os.Stdout = f - os.Stderr = f - l := listen() - rpc.RegisterName("goog", &Server{}) - rpc.Accept(l) - log.Fatal("rpc.Accept finished: server exiting") -} - -type Server struct{} - -type Empty google.Empty - -func (*Server) Ping(*Empty, *Empty) error { - return nil -} - -func (*Server) Accounts(_ *Empty, out *[]string) error { - var email []string - for _, a := range google.Cfg.Account { - email = append(email, a.Email) - } - *out = email - return nil -} diff --git a/vendor/github.com/mattermost/rsc/google/main.go b/vendor/github.com/mattermost/rsc/google/main.go deleted file mode 100644 index b11a6eefb..000000000 --- a/vendor/github.com/mattermost/rsc/google/main.go +++ /dev/null @@ -1,181 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// TODO: Something about redialing. - -package google - -import ( - // "flag" - "encoding/json" - "fmt" - "io/ioutil" - "log" - "net" - "net/rpc" - "os" - "os/exec" - "syscall" - "time" -) - -func Dir() string { - dir := os.Getenv("HOME") + "/.goog" - st, err := os.Stat(dir) - if err != nil { - if err := os.Mkdir(dir, 0700); err != nil { - log.Fatal(err) - } - st, err = os.Stat(dir) - if err != nil { - log.Fatal(err) - } - } - if !st.IsDir() { - log.Fatalf("%s exists but is not a directory", dir) - } - if st.Mode()&0077 != 0 { - log.Fatalf("%s exists but allows group or other permissions: %#o", dir, st.Mode()&0777) - } - return dir -} - -func Dial() (*Client, error) { - socket := Dir() + "/socket" - c, err := net.Dial("unix", socket) - if err == nil { - return &Client{rpc.NewClient(c)}, nil - } - log.Print("starting server") - os.Remove(socket) - runServer() - for i := 0; i < 50; i++ { - c, err = net.Dial("unix", socket) - if err == nil { - return &Client{rpc.NewClient(c)}, nil - } - time.Sleep(200e6) - if i == 0 { - log.Print("waiting for server...") - } - } - return nil, err -} - -type Client struct { - client *rpc.Client -} - -type Empty struct{} - -func (g *Client) Ping() error { - return g.client.Call("goog.Ping", &Empty{}, &Empty{}) -} - -func (g *Client) Accounts() ([]string, error) { - var out []string - if err := g.client.Call("goog.Accounts", &Empty{}, &out); err != nil { - return nil, err - } - return out, nil -} - -func runServer() { - cmd := exec.Command("googleserver", "serve") - cmd.SysProcAttr = &syscall.SysProcAttr{} - if err := cmd.Start(); err != nil { - log.Fatal(err) - } -} - -type Config struct { - Account []*Account -} - -type Account struct { - Email string - Password string - Nick string -} - -func (cfg *Config) AccountByEmail(email string) *Account { - for _, a := range cfg.Account { - if a.Email == email { - return a - } - } - return nil -} - -var Cfg Config - -func ReadConfig() { - file := Dir() + "/config" - st, err := os.Stat(file) - if err != nil { - return - } - if st.Mode()&0077 != 0 { - log.Fatalf("%s exists but allows group or other permissions: %#o", file, st.Mode()&0777) - } - data, err := ioutil.ReadFile(file) - if err != nil { - log.Fatal(err) - } - Cfg = Config{} - if err := json.Unmarshal(data, &Cfg); err != nil { - log.Fatal(err) - } -} - -func WriteConfig() { - file := Dir() + "/config" - st, err := os.Stat(file) - if err != nil { - if err := ioutil.WriteFile(file, nil, 0600); err != nil { - log.Fatal(err) - } - st, err = os.Stat(file) - if err != nil { - log.Fatal(err) - } - } - if st.Mode()&0077 != 0 { - log.Fatalf("%s exists but allows group or other permissions: %#o", file, st.Mode()&0777) - } - data, err := json.MarshalIndent(&Cfg, "", "\t") - if err != nil { - log.Fatal(err) - } - if err := ioutil.WriteFile(file, data, 0600); err != nil { - log.Fatal(err) - } - st, err = os.Stat(file) - if err != nil { - log.Fatal(err) - } - if st.Mode()&0077 != 0 { - log.Fatalf("%s allows group or other permissions after writing: %#o", file, st.Mode()&0777) - } -} - -func Acct(name string) Account { - ReadConfig() - if name == "" { - if len(Cfg.Account) == 0 { - fmt.Fprintf(os.Stderr, "no accounts configured\n") - os.Exit(2) - } - return *Cfg.Account[0] - } - - for _, a := range Cfg.Account { - if a.Email == name || a.Nick == name { - return *a - } - } - fmt.Fprintf(os.Stderr, "cannot find account %#q", name) - os.Exit(2) - panic("not reached") -} -- cgit v1.2.3-1-g7c22