Этот коммит содержится в:
Christopher Speller
2016-05-12 23:56:07 -04:00
родитель 84d2482ddb
Коммит 38ee83e45b
1099 изменённых файлов: 277713 добавлений и 4019 удалений

575
vendor/github.com/mattermost/rsc/google/acme/Chat/main.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,575 @@
// 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())
}

39
vendor/github.com/mattermost/rsc/google/chat.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,39 @@
// 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{})
}

1241
vendor/github.com/mattermost/rsc/google/gmail/gmail.go сгенерированный поставляемый Обычный файл

Разница между файлами не показана из-за своего большого размера Загрузить разницу

370
vendor/github.com/mattermost/rsc/google/gmailsend/send.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,370 @@
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()
}

80
vendor/github.com/mattermost/rsc/google/googleserver/chat.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,80 @@
// 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()
}

139
vendor/github.com/mattermost/rsc/google/googleserver/main.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,139 @@
// 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
}

181
vendor/github.com/mattermost/rsc/google/main.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,181 @@
// 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")
}