summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/mattermost/rsc/google
diff options
context:
space:
mode:
authorChristopher Speller <crspeller@gmail.com>2018-04-16 05:37:14 -0700
committerJoram Wilander <jwawilander@gmail.com>2018-04-16 08:37:14 -0400
commit6e2cb00008cbf09e556b00f87603797fcaa47e09 (patch)
tree3c0eb55ff4226a3f024aad373140d1fb860a6404 /vendor/github.com/mattermost/rsc/google
parentbf24f51c4e1cc6286885460672f7f449e8c6f5ef (diff)
downloadchat-6e2cb00008cbf09e556b00f87603797fcaa47e09.tar.gz
chat-6e2cb00008cbf09e556b00f87603797fcaa47e09.tar.bz2
chat-6e2cb00008cbf09e556b00f87603797fcaa47e09.zip
Depenancy upgrades and movign to dep. (#8630)
Diffstat (limited to 'vendor/github.com/mattermost/rsc/google')
-rw-r--r--vendor/github.com/mattermost/rsc/google/acme/Chat/main.go575
-rw-r--r--vendor/github.com/mattermost/rsc/google/chat.go39
-rw-r--r--vendor/github.com/mattermost/rsc/google/gmail/gmail.go1241
-rw-r--r--vendor/github.com/mattermost/rsc/google/gmailsend/send.go370
-rw-r--r--vendor/github.com/mattermost/rsc/google/googleserver/chat.go80
-rw-r--r--vendor/github.com/mattermost/rsc/google/googleserver/main.go139
-rw-r--r--vendor/github.com/mattermost/rsc/google/main.go181
7 files changed, 0 insertions, 2625 deletions
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 [<range>] <command> [args]\n")
- fmt.Fprint(bout, "<range> := <addr> | <addr>','<addr>| 'g'<search>\n")
- fmt.Fprint(bout, "<addr> := '.' | '$' | '^' | <number> | <search> | <addr>'+'<addr> | <addr>'-'<addr>\n")
- fmt.Fprint(bout, "<search> := '/'<gmail search>'/' | '?'<gmail search>'?'\n")
- fmt.Fprint(bout, "<command> :=\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(&quoter{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 <commits-noreply@bitbucket.org>
-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("<who>: <msg>, 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")
-}