<commit_before>package cmd

import (
	"fmt"
	"io/ioutil"

	"github.com/mobingi/mobingi-cli/pkg/cli"
	"github.com/mobingi/mobingi-cli/pkg/cli/confmap"
	"github.com/mobingilabs/mobingi-sdk-go/mobingi/alm"
	"github.com/mobingilabs/mobingi-sdk-go/pkg/cmdline"
	d "github.com/mobingilabs/mobingi-sdk-go/pkg/debug"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

func StackGetPemCmd() *cobra.Command {
	cmd := &cobra.Command{
		Use:   "pem",
		Short: "print stack pem file",
		Long: `Print your stack's pem file, if available.

Examples:

  $ ` + cmdline.Args0() + ` stack list
  $ ` + cmdline.Args0() + ` stack list --fmt=json --verbose
  $ ` + cmdline.Args0() + ` stack list --fmt=raw --out=/home/foo/tmp.txt`,
		Run: getpem,
	}

	cmd.Flags().StringP("id", "i", "", "stack id")
	return cmd
}

func getpem(cmd *cobra.Command, args []string) {
	verbose := viper.GetBool(confmap.ConfigKey("verbose"))
	sess, err := clisession()
	d.ErrorExit(err, 1)

	svc := alm.New(sess)
	in := &alm.GetPemInput{
		StackId: cli.GetCliStringFlag(cmd, "id"),
	}

	resp, body, pem, err := svc.GetPem(in)
	exitOn401(resp)
	if err != nil {
		d.Error(err)
		if verbose {
			d.Error("req payload:")
			fmt.Println(string(body))
			d.Error("pem payload:")
			fmt.Println(string(pem))
		}

		return
	}

	if verbose {
		d.Info("req payload:")
		fmt.Println(string(body))
	}

	d.Info("payload:")
	fmt.Println(string(pem))

	// write to file if requested
	out := cli.GetCliStringFlag(cmd, "out")
	if out != "" {
		err = ioutil.WriteFile(out, pem, 0644)
		d.ErrorExit(err, 1)
	}
}
<commit_msg>Update help in pem.<commit_after>package cmd

import (
	"fmt"
	"io/ioutil"

	"github.com/mobingi/mobingi-cli/pkg/cli"
	"github.com/mobingi/mobingi-cli/pkg/cli/confmap"
	"github.com/mobingilabs/mobingi-sdk-go/mobingi/alm"
	"github.com/mobingilabs/mobingi-sdk-go/pkg/cmdline"
	d "github.com/mobingilabs/mobingi-sdk-go/pkg/debug"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

func StackGetPemCmd() *cobra.Command {
	cmd := &cobra.Command{
		Use:   "pem",
		Short: "print stack pem file",
		Long: `Print your stack's pem file, if available.

Example:

  $ ` + cmdline.Args0() + ` stack pem --id foo`,
		Run: getpem,
	}

	cmd.Flags().StringP("id", "i", "", "stack id")
	return cmd
}

func getpem(cmd *cobra.Command, args []string) {
	verbose := viper.GetBool(confmap.ConfigKey("verbose"))
	sess, err := clisession()
	d.ErrorExit(err, 1)

	svc := alm.New(sess)
	in := &alm.GetPemInput{
		StackId: cli.GetCliStringFlag(cmd, "id"),
	}

	resp, body, pem, err := svc.GetPem(in)
	exitOn401(resp)
	if err != nil {
		d.Error(err)
		if verbose {
			d.Error("req payload:")
			fmt.Println(string(body))
			d.Error("pem payload:")
			fmt.Println(string(pem))
		}

		return
	}

	if verbose {
		d.Info("req payload:")
		fmt.Println(string(body))
	}

	d.Info("payload:")
	fmt.Println(string(pem))

	// write to file if requested
	out := cli.GetCliStringFlag(cmd, "out")
	if out != "" {
		err = ioutil.WriteFile(out, pem, 0644)
		d.ErrorExit(err, 1)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/codegangsta/cli"
	"github.com/keybase/go-jsonw"
	"github.com/keybase/go-libkb"
	"io"
	"os"
	"regexp"
	"strings"
)

type CmdSigsList struct {
	filter  string
	revoked bool
	json    bool
	verbose bool
	allKeys bool
	headers bool
	types   map[string]bool

	username string

	user *libkb.User
	sigs []libkb.TypedChainLink
}

func (s *CmdSigsList) ParseTypes(ctx *cli.Context) error {
	tmp := ctx.String("type")
	if len(tmp) == 0 {
		return nil
	}

	types := map[string]bool{
		"track":          true,
		"proof":          true,
		"cryptocurrency": true,
		"self":           true,
	}

	ret := make(map[string]bool)
	v := strings.Split(tmp, ",")
	for _, i := range v {
		ok, found := types[i]
		if !ok || !found {
			return fmt.Errorf("unknown signature type: %s", i)
		} else {
			ret[i] = true
		}
	}
	s.types = ret
	return nil
}

func (s *CmdSigsList) ParseArgv(ctx *cli.Context) error {
	nargs := len(ctx.Args())
	var err error

	s.revoked = ctx.Bool("revoked")
	s.json = ctx.Bool("json")
	s.verbose = ctx.Bool("verbose")
	s.allKeys = ctx.Bool("all-keys")
	s.headers = ctx.Bool("headers")
	s.filter = ctx.String("filter")

	if err = s.ParseTypes(ctx); err != nil {
		return err
	}

	if nargs == 1 {
		s.username = ctx.Args()[0]
	} else if nargs > 1 {
		err = fmt.Errorf("list takes at most 1 arg, a username")
	}

	return err
}

func (s *CmdSigsList) filterSigs(f func(libkb.TypedChainLink) bool) {
	sigs := make([]libkb.TypedChainLink, 0, 0)
	for _, link := range s.sigs {
		if f(link) {
			sigs = append(sigs, link)
		}
	}
	s.sigs = sigs
}

func (s *CmdSigsList) SelectSigs() error {
	if s.types != nil {
		s.filterSigs(func(l libkb.TypedChainLink) bool {
			ok, found := s.types[l.Type()]
			return ok && found
		})
	}
	return nil
}

func (s *CmdSigsList) FilterRxx() error {
	if len(s.filter) == 0 {
		return nil
	}
	rxx, err := regexp.Compile(s.filter)
	if err != nil {
		return err
	}
	s.filterSigs(func(l libkb.TypedChainLink) bool {
		return rxx.MatchString(l.ToDisplayString())
	})
	return nil
}

func (s *CmdSigsList) ProcessSigs() (err error) {
	if err = s.SelectSigs(); err != nil {
		return
	}
	if err = s.FilterRxx(); err != nil {
		return
	}
	return
}

func (s *CmdSigsList) skipLink(link libkb.TypedChainLink) bool {
	return ((!s.revoked && (link.IsRevoked() || link.IsRevocationIsh())) ||
		(!s.allKeys && !link.IsActiveKey()))
}

func (s *CmdSigsList) DisplayTable() (err error) {

	var cols []string

	if s.headers {
		cols = []string{
			"#",
			"SigId",
			"Type",
			"Date",
		}
		if s.revoked {
			cols = append(cols, "Revoked")
		}
		if s.allKeys {
			cols = append(cols, "Active", "Key")
		}
		cols = append(cols, "Body")
	}

	i := 0
	idtab := s.sigs

	rowfunc := func() []string {
		var row []string
		for ; i < len(idtab) && row == nil; i++ {
			link := idtab[i]

			if s.skipLink(link) {
				continue
			}

			row = []string{
				fmt.Sprintf("%d", int(link.GetSeqno())),
				link.GetSigId().ToDisplayString(s.verbose),
				link.Type(),
				libkb.FormatTime(link.GetCTime()),
			}
			if s.revoked {
				var ch string
				if link.IsRevoked() {
					ch = "R"
				} else {
					ch = "."
				}
				row = append(row, ch)
			}
			if s.allKeys {
				var ch string
				if link.IsActiveKey() {
					ch = "+"
				} else {
					ch = "-"
				}
				key := link.GetPgpFingerprint().ToDisplayString(s.verbose)
				row = append(row, ch, key)
			}
			row = append(row, link.ToDisplayString())
		}
		return row
	}

	libkb.Tablify(os.Stdout, cols, rowfunc)

	return
}

func (s *CmdSigsList) DisplayJson() (err error) {
	tmp := make([]*jsonw.Wrapper, 0, len(s.sigs))
	for _, link := range s.sigs {
		if s.skipLink(link) {
			continue
		}
		obj := jsonw.NewDictionary()
		obj.SetKey("seqno", jsonw.NewInt(int(link.GetSeqno())))
		obj.SetKey("sig_id", jsonw.NewString(link.GetSigId().ToDisplayString(true)))
		obj.SetKey("type", jsonw.NewString(link.Type()))
		obj.SetKey("ctime", jsonw.NewInt64(link.GetCTime().Unix()))
		if s.revoked {
			obj.SetKey("revoked", jsonw.NewBool(link.IsRevoked()))
		}
		if s.allKeys {
			obj.SetKey("key_fingerprint", jsonw.NewString(link.GetPgpFingerprint().ToDisplayString(true)))
		}
		obj.SetKey("statement", jsonw.NewString(link.ToDisplayString()))
		tmp = append(tmp, obj)
	}
	ret := jsonw.NewArray(len(tmp))
	for i, obj := range tmp {
		ret.SetIndex(i, obj)
	}
	_, err = io.WriteString(os.Stdout, ret.MarshalPretty()+"\n")
	return
}

func (s *CmdSigsList) Display() (err error) {
	if s.json {
		err = s.DisplayJson()
	} else {
		err = s.DisplayTable()
	}
	return
}

func (s *CmdSigsList) Run() (err error) {

	// XXX maybe do some sort of debug dump with the user that
	// we loaded from the server (or storage).

	arg := libkb.LoadUserArg{AllKeys: s.allKeys}
	if len(s.username) != 0 {
		arg.Name = s.username
	} else {
		arg.Self = true
	}

	s.user, err = libkb.LoadUser(arg)

	if err != nil {
		return
	}

	s.sigs = s.user.IdTable.Order

	if err = s.ProcessSigs(); err != nil {
		return
	}

	if err = s.Display(); err != nil {
		return
	}

	return
}

func NewCmdSigsList(cl *CommandLine) cli.Command {
	return cli.Command{
		Name:  "list",
		Usage: "keybase sigs list [filter]",
		Action: func(c *cli.Context) {
			cl.ChooseCommand(&CmdSigsList{}, "list", c)
		},
		Flags: []cli.Flag{
			cli.BoolFlag{
				Name:  "r, revoked",
				Usage: "Show revoked signatures",
			},
			cli.BoolFlag{
				Name:  "j, json",
				Usage: "output in json format; default is text",
			},
			cli.BoolFlag{
				Name:  "v, verbose",
				Usage: "a full dump, with more gory detail",
			},
			cli.StringFlag{
				Name: "t, type",
				Usage: "type of sig to output; choose from {track" +
					", proof, cryptocurrency, self}; all by default",
			},
			cli.BoolFlag{
				Name:  "a, all-keys",
				Usage: "show signatures from all (replaced) keys",
			},
			cli.BoolFlag{
				Name:  "H, headers",
				Usage: "show column headers",
			},
			cli.StringFlag{
				Name:  "f, filter",
				Usage: "provide a regex filter",
			},
		},
	}
}

func NewCmdSigs(cl *CommandLine) cli.Command {
	return cli.Command{
		Name:        "sigs",
		Usage:       "keybase sigs [subcommands...]",
		Description: "List, revoke signatures",
		Subcommands: []cli.Command{
			NewCmdSigsList(cl),
		},
	}
}

func (v *CmdSigsList) GetUsage() libkb.Usage {
	return libkb.Usage{
		Config: true,
		API:    true,
	}
}
<commit_msg>Refactor for keybase/go-libkb#61<commit_after>package main

import (
	"fmt"
	"github.com/codegangsta/cli"
	"github.com/keybase/go-jsonw"
	"github.com/keybase/go-libkb"
	"io"
	"os"
	"regexp"
	"strings"
)

type CmdSigsList struct {
	filter  string
	revoked bool
	json    bool
	verbose bool
	allKeys bool
	headers bool
	types   map[string]bool

	username string

	user *libkb.User
	sigs []libkb.TypedChainLink
}

func (s *CmdSigsList) ParseTypes(ctx *cli.Context) error {
	tmp := ctx.String("type")
	if len(tmp) == 0 {
		return nil
	}

	types := map[string]bool{
		"track":          true,
		"proof":          true,
		"cryptocurrency": true,
		"self":           true,
	}

	ret := make(map[string]bool)
	v := strings.Split(tmp, ",")
	for _, i := range v {
		ok, found := types[i]
		if !ok || !found {
			return fmt.Errorf("unknown signature type: %s", i)
		} else {
			ret[i] = true
		}
	}
	s.types = ret
	return nil
}

func (s *CmdSigsList) ParseArgv(ctx *cli.Context) error {
	nargs := len(ctx.Args())
	var err error

	s.revoked = ctx.Bool("revoked")
	s.json = ctx.Bool("json")
	s.verbose = ctx.Bool("verbose")
	s.allKeys = ctx.Bool("all-keys")
	s.headers = ctx.Bool("headers")
	s.filter = ctx.String("filter")

	if err = s.ParseTypes(ctx); err != nil {
		return err
	}

	if nargs == 1 {
		s.username = ctx.Args()[0]
	} else if nargs > 1 {
		err = fmt.Errorf("list takes at most 1 arg, a username")
	}

	return err
}

func (s *CmdSigsList) filterSigs(f func(libkb.TypedChainLink) bool) {
	sigs := make([]libkb.TypedChainLink, 0, 0)
	for _, link := range s.sigs {
		if f(link) {
			sigs = append(sigs, link)
		}
	}
	s.sigs = sigs
}

func (s *CmdSigsList) SelectSigs() error {
	if s.types != nil {
		s.filterSigs(func(l libkb.TypedChainLink) bool {
			ok, found := s.types[l.Type()]
			return ok && found
		})
	}
	return nil
}

func (s *CmdSigsList) FilterRxx() error {
	if len(s.filter) == 0 {
		return nil
	}
	rxx, err := regexp.Compile(s.filter)
	if err != nil {
		return err
	}
	s.filterSigs(func(l libkb.TypedChainLink) bool {
		return rxx.MatchString(l.ToDisplayString())
	})
	return nil
}

func (s *CmdSigsList) ProcessSigs() (err error) {
	if err = s.SelectSigs(); err != nil {
		return
	}
	if err = s.FilterRxx(); err != nil {
		return
	}
	return
}

func (s *CmdSigsList) skipLink(link libkb.TypedChainLink) bool {
	return ((!s.revoked && (link.IsRevoked() || link.IsRevocationIsh())) ||
		(!s.allKeys && !s.IsActiveKey(link)))
}

func (s *CmdSigsList) IsActiveKey(link libkb.TypedChainLink) bool {
	fp1, _ := s.user.GetActivePgpFingerprint()
	if fp1 == nil {
		return false
	}
	fp2 := link.GetPgpFingerprint()
	return fp1.Eq(fp2)
}

func (s *CmdSigsList) DisplayTable() (err error) {

	var cols []string

	if s.headers {
		cols = []string{
			"#",
			"SigId",
			"Type",
			"Date",
		}
		if s.revoked {
			cols = append(cols, "Revoked")
		}
		if s.allKeys {
			cols = append(cols, "Active", "Key")
		}
		cols = append(cols, "Body")
	}

	i := 0
	idtab := s.sigs

	rowfunc := func() []string {
		var row []string
		for ; i < len(idtab) && row == nil; i++ {
			link := idtab[i]

			if s.skipLink(link) {
				continue
			}

			row = []string{
				fmt.Sprintf("%d", int(link.GetSeqno())),
				link.GetSigId().ToDisplayString(s.verbose),
				link.Type(),
				libkb.FormatTime(link.GetCTime()),
			}
			if s.revoked {
				var ch string
				if link.IsRevoked() {
					ch = "R"
				} else {
					ch = "."
				}
				row = append(row, ch)
			}
			if s.allKeys {
				var ch string
				if s.IsActiveKey(link) {
					ch = "+"
				} else {
					ch = "-"
				}
				key := link.GetPgpFingerprint().ToDisplayString(s.verbose)
				row = append(row, ch, key)
			}
			row = append(row, link.ToDisplayString())
		}
		return row
	}

	libkb.Tablify(os.Stdout, cols, rowfunc)

	return
}

func (s *CmdSigsList) DisplayJson() (err error) {
	tmp := make([]*jsonw.Wrapper, 0, len(s.sigs))
	for _, link := range s.sigs {
		if s.skipLink(link) {
			continue
		}
		obj := jsonw.NewDictionary()
		obj.SetKey("seqno", jsonw.NewInt(int(link.GetSeqno())))
		obj.SetKey("sig_id", jsonw.NewString(link.GetSigId().ToDisplayString(true)))
		obj.SetKey("type", jsonw.NewString(link.Type()))
		obj.SetKey("ctime", jsonw.NewInt64(link.GetCTime().Unix()))
		if s.revoked {
			obj.SetKey("revoked", jsonw.NewBool(link.IsRevoked()))
		}
		if s.allKeys {
			obj.SetKey("key_fingerprint", jsonw.NewString(link.GetPgpFingerprint().ToDisplayString(true)))
		}
		obj.SetKey("statement", jsonw.NewString(link.ToDisplayString()))
		tmp = append(tmp, obj)
	}
	ret := jsonw.NewArray(len(tmp))
	for i, obj := range tmp {
		ret.SetIndex(i, obj)
	}
	_, err = io.WriteString(os.Stdout, ret.MarshalPretty()+"\n")
	return
}

func (s *CmdSigsList) Display() (err error) {
	if s.json {
		err = s.DisplayJson()
	} else {
		err = s.DisplayTable()
	}
	return
}

func (s *CmdSigsList) Run() (err error) {

	// XXX maybe do some sort of debug dump with the user that
	// we loaded from the server (or storage).

	arg := libkb.LoadUserArg{AllKeys: s.allKeys}
	if len(s.username) != 0 {
		arg.Name = s.username
	} else {
		arg.Self = true
	}

	s.user, err = libkb.LoadUser(arg)

	if err != nil {
		return
	}

	s.sigs = s.user.IdTable.Order

	if err = s.ProcessSigs(); err != nil {
		return
	}

	if err = s.Display(); err != nil {
		return
	}

	return
}

func NewCmdSigsList(cl *CommandLine) cli.Command {
	return cli.Command{
		Name:  "list",
		Usage: "keybase sigs list [filter]",
		Action: func(c *cli.Context) {
			cl.ChooseCommand(&CmdSigsList{}, "list", c)
		},
		Flags: []cli.Flag{
			cli.BoolFlag{
				Name:  "r, revoked",
				Usage: "Show revoked signatures",
			},
			cli.BoolFlag{
				Name:  "j, json",
				Usage: "output in json format; default is text",
			},
			cli.BoolFlag{
				Name:  "v, verbose",
				Usage: "a full dump, with more gory detail",
			},
			cli.StringFlag{
				Name: "t, type",
				Usage: "type of sig to output; choose from {track" +
					", proof, cryptocurrency, self}; all by default",
			},
			cli.BoolFlag{
				Name:  "a, all-keys",
				Usage: "show signatures from all (replaced) keys",
			},
			cli.BoolFlag{
				Name:  "H, headers",
				Usage: "show column headers",
			},
			cli.StringFlag{
				Name:  "f, filter",
				Usage: "provide a regex filter",
			},
		},
	}
}

func NewCmdSigs(cl *CommandLine) cli.Command {
	return cli.Command{
		Name:        "sigs",
		Usage:       "keybase sigs [subcommands...]",
		Description: "List, revoke signatures",
		Subcommands: []cli.Command{
			NewCmdSigsList(cl),
		},
	}
}

func (v *CmdSigsList) GetUsage() libkb.Usage {
	return libkb.Usage{
		Config: true,
		API:    true,
	}
}
<|endoftext|>


<commit_before>// Copyright 2013 Matthew Baird
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//     http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package gochimp

import (
	"encoding/json"
	"errors"
	"fmt"
	"time"
)

// see https://mandrillapp.com/api/docs/messages.html
const messages_send_endpoint string = "/messages/send.json"                   // Send a new transactional message through Mandrill
const messages_send_template_endpoint string = "/messages/send-template.json" // Send a new transactional message through Mandrill using a template
const messages_search_endpoint string = "/messages/search.json"               // Search the content of recently sent messages and optionally narrow by date range, tags and senders
const messages_parse_endpoint string = "/messages/parse.json"                 // Parse the full MIME document for an email message, returning the content of the message broken into its constituent pieces
const messages_send_raw_endpoint string = "/messages/send-raw.json"           // Take a raw MIME document for a message, and send it exactly as if it were sent over the SMTP protocol

func (a *MandrillAPI) MessageSend(message Message, async bool) ([]SendResponse, error) {
	var response []SendResponse
	var params map[string]interface{} = make(map[string]interface{})
	params["message"] = message
	params["async"] = async
	err := parseMandrillJson(a, messages_send_endpoint, params, &response)
	return response, err
}

func (a *MandrillAPI) MessageSendTemplate(templateName string, templateContent []Var, message Message, async bool) ([]SendResponse, error) {
	var response []SendResponse
	if templateName == "" {
		return response, errors.New("templateName cannot be blank")
	}
	var params map[string]interface{} = make(map[string]interface{})
	params["message"] = message
	params["template_name"] = templateName
	params["async"] = async
	params["template_content"] = templateContent
	err := parseMandrillJson(a, messages_send_template_endpoint, params, &response)
	for _, r := range response {
		if r.Status == "rejected" {
			msg := "email was rejected"
			if r.RejectedReason != "" {
				msg = r.RejectedReason
			}
			return nil, fmt.Errorf("Unable to send message %s, %s", r.Id, msg)
		}
	}
	return response, err
}

func (a *MandrillAPI) MessageSearch(searchRequest SearchRequest) ([]SearchResponse, error) {
	var response []SearchResponse
	var params map[string]interface{} = make(map[string]interface{})
	//todo remove this hack
	params["query"] = searchRequest.Query
	params["date_from"] = searchRequest.DateFrom
	params["date_to"] = searchRequest.DateTo
	params["tags"] = searchRequest.Tags
	params["senders"] = searchRequest.Senders
	params["limit"] = searchRequest.Limit
	err := parseMandrillJson(a, messages_search_endpoint, params, &response)
	return response, err
}

func (a *MandrillAPI) MessageParse(rawMessage string, async bool) (Message, error) {
	var response Message
	if rawMessage == "" {
		return response, errors.New("rawMessage cannot be blank")
	}
	var params map[string]interface{} = make(map[string]interface{})
	params["raw_message"] = rawMessage
	err := parseMandrillJson(a, messages_parse_endpoint, params, &response)
	return response, err
}

// Can return oneof Invalid_Key, ValidationError or GeneralError
func (a *MandrillAPI) MessageSendRaw(rawMessage string, to []string, from Recipient, async bool) ([]SendResponse, error) {
	var response []SendResponse
	if rawMessage == "" {
		return response, errors.New("rawMessage cannot be blank")
	}
	if len(to) <= 0 {
		return response, errors.New("You need at least one recipient in the To array")
	}

	var params map[string]interface{} = make(map[string]interface{})
	params["raw_message"] = rawMessage
	params["from_email"] = from.Email
	params["from_name"] = from.Name
	params["to"] = to
	params["async"] = async
	err := parseMandrillJson(a, messages_send_raw_endpoint, params, &response)
	return response, err
}

type SearchResponse struct {
	Timestamp time.Duration       `json:"ts"`
	Id        string              `json:"_id"`
	Sender    string              `json:"sender"`
	Subject   string              `json:"subject"`
	Email     string              `json:"email"`
	Tags      []string            `json:"tags"`
	Opens     int                 `json:"opens"`
	Clicks    int                 `json:"clicks"`
	State     string              `json:"state"`
	Metadata  []map[string]string `json:"metadata"`
}

type SearchRequest struct {
	Query    string    `json:"query"`
	DateFrom time.Time `json:"date_from"`
	DateTo   time.Time `json:"date_to"`
	Tags     []string  `json:"tags"`
	Senders  []string  `json:"senders"`
	Limit    int       `json:"limit"`
}

type Message struct {
	Html                    string              `json:"html,omitempty"`
	Text                    string              `json:"text,omitempty"`
	Subject                 string              `json:"subject"`
	FromEmail               string              `json:"from_email"`
	FromName                string              `json:"from_name"`
	To                      []Recipient         `json:"to"`
	Headers                 map[string]string   `json:"headers,omitempty"`
	TrackOpens              bool                `json:"track_opens"`
	TrackClicks             bool                `json:"track_clicks"`
	ViewContentLink         bool                `json:"view_content_link,omitempty"`
	AutoText                bool                `json:"auto_text,omitempty"`
	AutoHtml                bool                `json:"auto_html,omitempty"`
	UrlStripQS              bool                `json:"url_strip_qs,omitempty"`
	InlineCss               bool                `json:"inline_css,omitempty"`
	PreserveRecipients      bool                `json:"preserve_recipients,omitempty"`
	Important               bool                `json:"important,omitempty"`
	BCCAddress              string              `json:"bcc_address,omitempty"`
	TrackingDomain          string              `json:"tracking_domain,omitempty"`
	SigningDomain           string              `json:"signing_domain,omitempty"`
	ReturnPathDomain        string              `json:"return_path_domain,omitempty"`
	Merge                   bool                `json:"merge,omitempty"`
	GlobalMergeVars         []Var               `json:"global_merge_vars,omitempty"`
	MergeVars               []MergeVars         `json:"merge_vars,omitempty"`
	Tags                    []string            `json:"tags,omitempty"`
	Subaccount              string              `json:"subaccount,omitempty"`
	GoogleAnalyticsDomains  []string            `json:"google_analytics_domains,omitempty"`
	GoogleAnalyticsCampaign []string            `json:"google_analytics_campaign,omitempty"`
	Metadata                map[string]string   `json:"metadata,omitempty"`
	RecipientMetadata       []RecipientMetaData `json:"recipient_metadata,omitempty"`
	Attachments             []Attachment        `json:"attachments,omitempty"`
}

func (m *Message) String() string {
	b, _ := json.Marshal(m)
	return string(b)
}

func (m *Message) AddHeader(key, value string) {
	if m.Headers == nil {
		m.Headers = make(map[string]string)
	}
	m.Headers[key] = value
}

func (m *Message) AddRecipients(r ...Recipient) {
	m.To = append(m.To, r...)
}

func (m *Message) AddGlobalMergeVar(globalvars ...Var) {
	m.GlobalMergeVars = append(m.GlobalMergeVars, globalvars...)
}

func (m *Message) AddMergeVar(vars ...MergeVars) {
	m.MergeVars = append(m.MergeVars, vars...)
}

func (m *Message) AddTag(tags ...string) {
	m.Tags = append(m.Tags, tags...)
}

func (m *Message) AddGoogleAnalyticsDomains(domains ...string) {
	m.GoogleAnalyticsDomains = append(m.GoogleAnalyticsDomains, domains...)
}

func (m *Message) AddGoogleAnalyticsCampaign(campaigns ...string) {
	m.GoogleAnalyticsCampaign = append(m.GoogleAnalyticsCampaign, campaigns...)
}

func (m *Message) AddMetadata(key, value string) {
	if m.Metadata == nil {
		m.Metadata = make(map[string]string)
	}
	m.Metadata[key] = value
}

func (m *Message) AddRecipientMetadata(metadata ...RecipientMetaData) {
	m.RecipientMetadata = append(m.RecipientMetadata, metadata...)
}

func (m *Message) AddAttachments(attachement ...Attachment) {
	m.Attachments = append(m.Attachments, attachement...)
}

type Attachment struct {
	Type    string `json:"type"`
	Name    string `json:"name"`
	Content string `json:"content"`
}
type RecipientMetaData struct {
	Recipient string            `json:"rcpt"`
	Vars      map[string]string `json:"values"`
}

type MergeVars struct {
	Recipient string `json:"rcpt"`
	Vars      []Var  `json:"vars"`
}

type Var struct {
	Name    string `json:"name"`
	Content string `json:"content"`
}

func NewVar(name string, content string) *Var {
	return &Var{Name: name, Content: content}
}

type Recipient struct {
	Email string `json:"email"`
	Name  string `json:"name"`
	Type  string `json:"type"`
}

type SendResponse struct {
	Email          string `json:"email"`
	Status         string `json:"status"`
	Id             string `json:"_id"`
	RejectedReason string `json:"reject_reason"`
}
<commit_msg>Revert "merge from azoff - Report Rejections as Errors"<commit_after>// Copyright 2013 Matthew Baird
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//     http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package gochimp

import (
	"encoding/json"
	"errors"
	"time"
)

// see https://mandrillapp.com/api/docs/messages.html
const messages_send_endpoint string = "/messages/send.json"                   // Send a new transactional message through Mandrill
const messages_send_template_endpoint string = "/messages/send-template.json" // Send a new transactional message through Mandrill using a template
const messages_search_endpoint string = "/messages/search.json"               // Search the content of recently sent messages and optionally narrow by date range, tags and senders
const messages_parse_endpoint string = "/messages/parse.json"                 // Parse the full MIME document for an email message, returning the content of the message broken into its constituent pieces
const messages_send_raw_endpoint string = "/messages/send-raw.json"           // Take a raw MIME document for a message, and send it exactly as if it were sent over the SMTP protocol

func (a *MandrillAPI) MessageSend(message Message, async bool) ([]SendResponse, error) {
	var response []SendResponse
	var params map[string]interface{} = make(map[string]interface{})
	params["message"] = message
	params["async"] = async
	err := parseMandrillJson(a, messages_send_endpoint, params, &response)
	return response, err
}

func (a *MandrillAPI) MessageSendTemplate(templateName string, templateContent []Var, message Message, async bool) ([]SendResponse, error) {
	var response []SendResponse
	if templateName == "" {
		return response, errors.New("templateName cannot be blank")
	}
	var params map[string]interface{} = make(map[string]interface{})
	params["message"] = message
	params["template_name"] = templateName
	params["async"] = async
	params["template_content"] = templateContent
	err := parseMandrillJson(a, messages_send_template_endpoint, params, &response)
	return response, err
}

func (a *MandrillAPI) MessageSearch(searchRequest SearchRequest) ([]SearchResponse, error) {
	var response []SearchResponse
	var params map[string]interface{} = make(map[string]interface{})
	//todo remove this hack
	params["query"] = searchRequest.Query
	params["date_from"] = searchRequest.DateFrom
	params["date_to"] = searchRequest.DateTo
	params["tags"] = searchRequest.Tags
	params["senders"] = searchRequest.Senders
	params["limit"] = searchRequest.Limit
	err := parseMandrillJson(a, messages_search_endpoint, params, &response)
	return response, err
}

func (a *MandrillAPI) MessageParse(rawMessage string, async bool) (Message, error) {
	var response Message
	if rawMessage == "" {
		return response, errors.New("rawMessage cannot be blank")
	}
	var params map[string]interface{} = make(map[string]interface{})
	params["raw_message"] = rawMessage
	err := parseMandrillJson(a, messages_parse_endpoint, params, &response)
	return response, err
}

// Can return oneof Invalid_Key, ValidationError or GeneralError
func (a *MandrillAPI) MessageSendRaw(rawMessage string, to []string, from Recipient, async bool) ([]SendResponse, error) {
	var response []SendResponse
	if rawMessage == "" {
		return response, errors.New("rawMessage cannot be blank")
	}
	if len(to) <= 0 {
		return response, errors.New("You need at least one recipient in the To array")
	}

	var params map[string]interface{} = make(map[string]interface{})
	params["raw_message"] = rawMessage
	params["from_email"] = from.Email
	params["from_name"] = from.Name
	params["to"] = to
	params["async"] = async
	err := parseMandrillJson(a, messages_send_raw_endpoint, params, &response)
	return response, err
}

type SearchResponse struct {
	Timestamp time.Duration       `json:"ts"`
	Id        string              `json:"_id"`
	Sender    string              `json:"sender"`
	Subject   string              `json:"subject"`
	Email     string              `json:"email"`
	Tags      []string            `json:"tags"`
	Opens     int                 `json:"opens"`
	Clicks    int                 `json:"clicks"`
	State     string              `json:"state"`
	Metadata  []map[string]string `json:"metadata"`
}

type SearchRequest struct {
	Query    string    `json:"query"`
	DateFrom time.Time `json:"date_from"`
	DateTo   time.Time `json:"date_to"`
	Tags     []string  `json:"tags"`
	Senders  []string  `json:"senders"`
	Limit    int       `json:"limit"`
}

type Message struct {
	Html                    string              `json:"html,omitempty"`
	Text                    string              `json:"text,omitempty"`
	Subject                 string              `json:"subject"`
	FromEmail               string              `json:"from_email"`
	FromName                string              `json:"from_name"`
	To                      []Recipient         `json:"to"`
	Headers                 map[string]string   `json:"headers,omitempty"`
	TrackOpens              bool                `json:"track_opens"`
	TrackClicks             bool                `json:"track_clicks"`
	ViewContentLink         bool                `json:"view_content_link,omitempty"`
	AutoText                bool                `json:"auto_text,omitempty"`
	AutoHtml                bool                `json:"auto_html,omitempty"`
	UrlStripQS              bool                `json:"url_strip_qs,omitempty"`
	InlineCss               bool                `json:"inline_css,omitempty"`
	PreserveRecipients      bool                `json:"preserve_recipients,omitempty"`
	Important               bool                `json:"important,omitempty"`
	BCCAddress              string              `json:"bcc_address,omitempty"`
	TrackingDomain          string              `json:"tracking_domain,omitempty"`
	SigningDomain           string              `json:"signing_domain,omitempty"`
	ReturnPathDomain        string              `json:"return_path_domain,omitempty"`
	Merge                   bool                `json:"merge,omitempty"`
	GlobalMergeVars         []Var               `json:"global_merge_vars,omitempty"`
	MergeVars               []MergeVars         `json:"merge_vars,omitempty"`
	Tags                    []string            `json:"tags,omitempty"`
	Subaccount              string              `json:"subaccount,omitempty"`
	GoogleAnalyticsDomains  []string            `json:"google_analytics_domains,omitempty"`
	GoogleAnalyticsCampaign []string            `json:"google_analytics_campaign,omitempty"`
	Metadata                map[string]string   `json:"metadata,omitempty"`
	RecipientMetadata       []RecipientMetaData `json:"recipient_metadata,omitempty"`
	Attachments             []Attachment        `json:"attachments,omitempty"`
}

func (m *Message) String() string {
	b, _ := json.Marshal(m)
	return string(b)
}

func (m *Message) AddHeader(key, value string) {
	if m.Headers == nil {
		m.Headers = make(map[string]string)
	}
	m.Headers[key] = value
}

func (m *Message) AddRecipients(r ...Recipient) {
	m.To = append(m.To, r...)
}

func (m *Message) AddGlobalMergeVar(globalvars ...Var) {
	m.GlobalMergeVars = append(m.GlobalMergeVars, globalvars...)
}

func (m *Message) AddMergeVar(vars ...MergeVars) {
	m.MergeVars = append(m.MergeVars, vars...)
}

func (m *Message) AddTag(tags ...string) {
	m.Tags = append(m.Tags, tags...)
}

func (m *Message) AddGoogleAnalyticsDomains(domains ...string) {
	m.GoogleAnalyticsDomains = append(m.GoogleAnalyticsDomains, domains...)
}

func (m *Message) AddGoogleAnalyticsCampaign(campaigns ...string) {
	m.GoogleAnalyticsCampaign = append(m.GoogleAnalyticsCampaign, campaigns...)
}

func (m *Message) AddMetadata(key, value string) {
	if m.Metadata == nil {
		m.Metadata = make(map[string]string)
	}
	m.Metadata[key] = value
}

func (m *Message) AddRecipientMetadata(metadata ...RecipientMetaData) {
	m.RecipientMetadata = append(m.RecipientMetadata, metadata...)
}

func (m *Message) AddAttachments(attachement ...Attachment) {
	m.Attachments = append(m.Attachments, attachement...)
}

type Attachment struct {
	Type    string `json:"type"`
	Name    string `json:"name"`
	Content string `json:"content"`
}
type RecipientMetaData struct {
	Recipient string            `json:"rcpt"`
	Vars      map[string]string `json:"values"`
}

type MergeVars struct {
	Recipient string `json:"rcpt"`
	Vars      []Var  `json:"vars"`
}

type Var struct {
	Name    string `json:"name"`
	Content string `json:"content"`
}

func NewVar(name string, content string) *Var {
	return &Var{Name: name, Content: content}
}

type Recipient struct {
	Email string `json:"email"`
	Name  string `json:"name"`
	Type  string `json:"type"`
}

type SendResponse struct {
	Email          string `json:"email"`
	Status         string `json:"status"`
	Id             string `json:"_id"`
	RejectedReason string `json:"rejected_reason"`
}
<|endoftext|>


<commit_before>package json

import (
	"encoding/json"
	"io/ioutil"
	"strings"
)

// Client provides a shell for the json client
type Client struct {
	data map[string]interface{}
}

// NewJsonClient returns a new client
func NewJsonClient(filePath string) (*Client, error) {
	var allJsonVars map[string]interface{}

	fileContents, err := ioutil.ReadFile(filePath)
	if err != nil {
		return &Client{allJsonVars}, err
	}

	err = json.Unmarshal(fileContents, &allJsonVars)
	if err != nil {
		return &Client{allJsonVars}, err
	}

	return &Client{allJsonVars}, nil
}

// GetValues queries the json for keys
func (c *Client) GetValues(keys []string) (map[string]string, error) {

	vars := make(map[string]string)

	for _, key := range keys {
		jsonWalk(c.data, key, vars)
	}

	return vars, nil
}

// iterate over a json interface searching for key and add key/value to vars
func jsonWalk(json map[string]interface{}, key string, vars map[string]string) {
	keyPath := strings.Split(strings.TrimPrefix(key, "/"), "/")

	for index, component := range keyPath {
		if val, ok := json[component]; ok {
			// last component of key path
			if index == len(keyPath)-1 {
				if str, ok := val.(string); ok {
					// we have matched the key
					vars[key] = str
				} else {
					// we've hit the end of the key to match
					// but still have more object to traverse
					jsonAddAll(
						vars,
						strings.TrimPrefix(key, "/"),
						val.(map[string]interface{}))
				}
			} else {
				json = val.(map[string]interface{})
			}
		}
	}
}

// iterate over a json interface adding all data and adding to vars
func jsonAddAll(vars map[string]string, keyPrefix string, json map[string]interface{}) {

	for objkey, objvalue := range json {

		if str, ok := objvalue.(string); ok {
			// stop at strings and add a new entry to vars
			vars[keyPrefix+"/"+objkey] = str
		} else {
			// recurse
			jsonAddAll(
				vars,
				keyPrefix+"/"+objkey,
				objvalue.(map[string]interface{}))
		}
	}
}

func (c *Client) WatchPrefix(prefix string, keys []string, waitIndex uint64, stopChan chan bool) (uint64, error) {
	<-stopChan
	return 0, nil
}
<commit_msg>Revert "json-backend: cleanup"<commit_after>package json

import (
	"encoding/json"
	"io/ioutil"
	"strings"
)

// Client provides a shell for the json client
type Client struct {
	data map[string]interface{}
}

// NewJsonClient returns a new client
func NewJsonClient(filePath string) (*Client, error) {
	var allJsonVars map[string]interface{}

	fileContents, err := ioutil.ReadFile(filePath)
	if err != nil {
		return &Client{allJsonVars}, err
	}

	err = json.Unmarshal(fileContents, &allJsonVars)
	if err != nil {
		return &Client{allJsonVars}, err
	}

	return &Client{allJsonVars}, nil
}

// GetValues queries the json for keys
func (c *Client) GetValues(keys []string) (map[string]string, error) {

	vars := make(map[string]string)

	for _, key := range keys {
		jsonWalk(c.data, key, vars)
	}

	return vars, nil
}

// iterate over a json interface searching for key and add key/value to vars
func jsonWalk(json map[string]interface{}, key string, vars map[string]string) {
	keyPath := strings.Split(strings.TrimPrefix(key, "/"), "/")

	for index, level := range keyPath {
		if val, ok := json[level]; ok {
			if index == len(keyPath)-1 {
				if str, ok := val.(string); ok {
					vars[key] = str
				} else {
					jsonAddAll(
						vars,
						strings.TrimPrefix(key, "/"),
						val.(map[string]interface{}))
				}
			} else {
				json = val.(map[string]interface{})
			}
		}
	}
}

// iterate over a json interface adding all data and adding to vars
func jsonAddAll(vars map[string]string, keyPrefix string, json map[string]interface{}) {
	for objkey, objvalue := range json {
		if str, ok := objvalue.(string); ok {
			vars[keyPrefix+"/"+objkey] = str
		} else {
			jsonAddAll(
				vars,
				keyPrefix+"/"+objkey,
				objvalue.(map[string]interface{}))
		}
	}
}

func (c *Client) WatchPrefix(prefix string, keys []string, waitIndex uint64, stopChan chan bool) (uint64, error) {
	<-stopChan
	return 0, nil
}
<|endoftext|>


<commit_before>package commands

import (
	"os"
	"os/exec"
	"strconv"
	"strings"

	"github.com/craigmj/gototp"
)

func GetCode(name string) {
	keychainName := "mmfa_" + name
	secret, err := secret(keychainName)
	if err != nil {
		os.Stderr.Write([]byte("Error getting secret: " + err.Error() + "\n" + secret))
		os.Exit(1)
	}

	otp, err := gototp.New(secret)
	if err != nil {
		os.Stderr.Write([]byte("Error calculating code: " + err.Error()))
		os.Exit(1)
	}

	code := strconv.Itoa(int(otp.Now()))
	copyToClipboard(strings.Repeat("0", 6-len(code)) + code)
	os.Stdout.Write([]byte(strings.Repeat("0", 6-len(code)) + code + "\n"))
}

func secret(name string) (string, error) {
	command, args := getSecretCommand(name)
	cmd := exec.Command(command, args...)
	output, err := cmd.CombinedOutput()
	if err != nil {
		return string(output), err
	}

	return strings.TrimSpace(string(output)), nil
}

func getSecretCommand(name string) (string, []string) {
	args := []string{
		"find-generic-password",
		"-a",
		name,
		"-s",
		name,
		"-w",
	}
	return "security", args
}

func copyToClipboard(code string) {
	echo := exec.Command("echo", code)
	pbcopy := exec.Command("pbcopy")
	_, err := pipedCommands(echo, pbcopy)
	if err != nil {
		print(err)
	}
}
<commit_msg>drying up code<commit_after>package commands

import (
	"os"
	"os/exec"
	"strconv"
	"strings"

	"github.com/craigmj/gototp"
)

func GetCode(name string) {
	keychainName := "mmfa_" + name
	secret, err := secret(keychainName)
	if err != nil {
		os.Stderr.Write([]byte("Error getting secret: " + err.Error() + "\n" + secret))
		os.Exit(1)
	}

	otp, err := gototp.New(secret)
	if err != nil {
		os.Stderr.Write([]byte("Error calculating code: " + err.Error()))
		os.Exit(1)
	}

	code := sanitizedCode(strconv.Itoa(int(otp.Now())))
	copyToClipboard(code)
	os.Stdout.Write([]byte(code + "\n"))
}

func sanitizedCode(otp string) string {
	return strings.Repeat("0", 6-len(otp)) + otp
}

func secret(name string) (string, error) {
	command, args := getSecretCommand(name)
	cmd := exec.Command(command, args...)
	output, err := cmd.CombinedOutput()
	if err != nil {
		return string(output), err
	}

	return strings.TrimSpace(string(output)), nil
}

func getSecretCommand(name string) (string, []string) {
	args := []string{
		"find-generic-password",
		"-a",
		name,
		"-s",
		name,
		"-w",
	}
	return "security", args
}

func copyToClipboard(code string) {
	echo := exec.Command("echo", code)
	pbcopy := exec.Command("pbcopy")
	_, err := pipedCommands(echo, pbcopy)
	if err != nil {
		print(err)
	}
}
<|endoftext|>


<commit_before>package connection

import (
	"encoding/binary"
	"io"
	"net"
)

type Connection interface {
	Read() ([]byte, error)
	Write(msg []byte) error
	Close() error
}

type SocketConn struct {
	sock net.Conn
}

func NewSocketConn(sock net.Conn) *SocketConn {
	return &SocketConn{sock: sock}
}

func (c *SocketConn) Read() ([]byte, error) {
	// the 32 bit initial message dictates the size of the message
	sizeBuf := make([]byte, 4)
	_, err := io.ReadFull(c.sock, sizeBuf)
	if err != nil {
		return nil, err
	}
	size, _ := binary.Uvarint(sizeBuf)
	msgBuf := make([]byte, size)
	_, err = io.ReadFull(c.sock, msgBuf)
	return msgBuf, err
}

func (c *SocketConn) Write(msg []byte) error {
	lenBuf := make([]byte, 4)
	msgLen := len(msg)
	binary.PutUvarint(lenBuf, uint64(msgLen))
	err := c.fullWrite(lenBuf)
	if err != nil {
		return err
	}
	return c.fullWrite(msg)
}

func (c *SocketConn) fullWrite(msg []byte) error {
	msgLen := len(msg)
	n, err := c.sock.Write(msg)
	for num_sent := 0; num_sent < msgLen; n, err = c.sock.Write(msg) {
		num_sent += n
		msg = msg[n:]
		if err != nil && err != io.ErrShortWrite {
			return err
		}
	}
	return err
}

func (c *SocketConn) Close() error {
	return c.sock.Close()
}
<commit_msg>Use proper Endian conversion tools from encoding/binary<commit_after>package connection

import (
	"encoding/binary"
	"io"
	"net"
)

type Connection interface {
	Read() ([]byte, error)
	Write(msg []byte) error
	Close() error
}

type SocketConn struct {
	sock net.Conn
}

func NewSocketConn(sock net.Conn) *SocketConn {
	return &SocketConn{sock: sock}
}

func (c *SocketConn) Read() ([]byte, error) {
	// the 32 bit initial message dictates the size of the message
	sizeBuf := make([]byte, 4)
	_, err := io.ReadFull(c.sock, sizeBuf)
	if err != nil {
		return nil, err
	}
	size := binary.LittleEndian.Uint32(sizeBuf)
	msgBuf := make([]byte, size)
	_, err = io.ReadFull(c.sock, msgBuf)
	return msgBuf, err
}

func (c *SocketConn) Write(msg []byte) error {
	lenBuf := make([]byte, 4)
	msgLen := len(msg)
	binary.LittleEndian.PutUint32(lenBuf, uint32(msgLen))
	err := c.fullWrite(lenBuf)
	if err != nil {
		return err
	}
	return c.fullWrite(msg)
}

func (c *SocketConn) fullWrite(msg []byte) error {
	msgLen := len(msg)
	n, err := c.sock.Write(msg)
	for num_sent := 0; num_sent < msgLen; n, err = c.sock.Write(msg) {
		num_sent += n
		msg = msg[n:]
		if err != nil && err != io.ErrShortWrite {
			return err
		}
	}
	return err
}

func (c *SocketConn) Close() error {
	return c.sock.Close()
}
<|endoftext|>


<commit_before>package slack

/* util has most of the struct, type, and const definitions, as well as
most of the internal methods. */

import (
	"fmt"
	"log"
	"regexp"
	"strings"
	"sync"
	"time"

	"github.com/nlopes/slack"
	"github.com/parsley42/gobot/bot"
)

const optimeout = 1 * time.Minute

type slackConnector struct {
	api          *slack.Client
	conn         *slack.RTM
	botName      string            // human-readable name of bot
	botID        string            // slack internal bot ID
	bot.Handler                    // bot interface for handling messages
	sync.RWMutex                   // shared mutex for locking connector data structures
	channelToID  map[string]string // map from channel names to channel IDs
	idToChannel  map[string]string // map from channel ID to channel name
	userToID     map[string]string // map from user names to user IDs
	idToUser     map[string]string // map from user name to user ID
	userIDToIM   map[string]string // map from user ID to IM channel ID
	imToUser     map[string]string // map from IM channel ID to user name
	level        bot.LogLevel      // current log level
}

func (s *slackConnector) addMessageMentions(msg string) string {
	re := regexp.MustCompile(`@[0-9a-z]{1,21}\b`)
	mentions := re.FindAllString(msg, -1)
	if len(mentions) == 0 {
		return msg
	}
	mset := make(map[string]bool)
	for _, mention := range mentions {
		mset[mention] = true
	}
	for mention, _ := range mset {
		userName := mention[1:]
		replace, ok := s.userID(userName)
		if !ok {
			// it's ok to have @notactuallyauser
			continue
		}
		msg = strings.Replace(msg, mention, "<@"+replace+">", -1)
	}
	return msg
}

// Examine incoming messages and route them to the appropriate bot
// method.
func (s *slackConnector) processMessage(msg *slack.MessageEvent) {
	s.log(bot.Trace, fmt.Sprintf("Message received: %v\n", msg))
	re := regexp.MustCompile(`<@U[A-Z0-9]{8}>`) // match a @user mention
	text := msg.Msg.Text
	chanID := msg.Msg.Channel
	mentions := re.FindAllString(text, -1)
	if len(mentions) != 0 {
		mset := make(map[string]bool)
		for _, mention := range mentions {
			mset[mention] = true
		}
		for mention, _ := range mset {
			mID := mention[2:11]
			replace, ok := s.userName(mID)
			if !ok {
				s.log(bot.Warn, "Couldn't find username for mentioned", mID)
				continue
			}
			text = strings.Replace(text, mention, "@"+replace, -1)
		}
	}
	switch chanID[:1] {
	case "D":
		userName, ok := s.imUser(chanID)
		if !ok {
			s.log(bot.Warn, "Couldn't find user name for IM", chanID)
			s.DirectMsg(chanID, text)
			return
		}
		s.DirectMsg(userName, text)
	case "C":
		channelName, ok := s.channelName(chanID)
		if !ok {
			s.log(bot.Warn, "Coudln't find channel name for ID", chanID)
			s.ChannelMsg(chanID, text)
			return
		}
		s.ChannelMsg(channelName, text)
	}
}

// log logs messages whenever the connector log level is
// less than the given level
func (s *slackConnector) log(l bot.LogLevel, v ...interface{}) {
	if l >= s.level {
		var prefix string
		switch l {
		case bot.Trace:
			prefix = "Trace:"
		case bot.Debug:
			prefix = "Debug:"
		case bot.Info:
			prefix = "Info"
		case bot.Warn:
			prefix = "Warning:"
		case bot.Error:
			prefix = "Error"
		}
		log.Println(prefix, v)
	}
}

// update maps is called whenever there are any changes
// to users or channels, so that plugins can use
// human-readable names for users and channels.
func (s *slackConnector) updateMaps() {
	s.log(bot.Trace, "Updating maps")
	deadline := time.Now().Add(optimeout)
	var (
		err        error
		userlist   []slack.User
		userIMlist []slack.IM
		chanlist   []slack.Channel
	)

	for tries := uint(0); time.Now().Before(deadline); tries++ {
		userlist, err = s.api.GetUsers()
		if err == nil {
			break
		}
	}
	if err != nil {
		log.Fatalf("Protocol timeout updating users: %v\n", err)
	}
	userMap := make(map[string]string)
	userIDMap := make(map[string]string)
	for _, user := range userlist {
		s.log(bot.Trace, "Mapping user name", user.Name, "to", user.ID)
		userMap[user.Name] = user.ID
		userIDMap[user.ID] = user.Name
	}

	for tries := uint(0); time.Now().Before(deadline); tries++ {
		userIMlist, err = s.api.GetIMChannels()
		if err == nil {
			break
		}
	}
	if err != nil {
		log.Fatalf("Protocol timeout updating IMchannels: %v\n", err)
	}
	userIMMap := make(map[string]string)
	userNameMap := make(map[string]string)
	for _, userIM := range userIMlist {
		s.log(bot.Trace, "Mapping user ID", userIM.User, "to IM channel", userIM.ID)
		userIMMap[userIM.User] = userIM.ID
		s.log(bot.Trace, "Mapping IM channel", userIM.ID, "to user name", userIDMap[userIM.User])
		userNameMap[userIM.ID] = userIDMap[userIM.User]
	}

	for tries := uint(0); time.Now().Before(deadline); tries++ {
		chanlist, err = s.api.GetChannels(true)
		if err == nil {
			break
		}
	}
	if err != nil {
		log.Fatalf("Protocol timeout updating channels: %v\n", err)
	}
	chanMap := make(map[string]string)
	chanIDMap := make(map[string]string)
	for _, channel := range chanlist {
		s.log(bot.Trace, "Mapping channel name", channel.Name, "to", channel.ID)
		chanMap[channel.Name] = channel.ID
		chanIDMap[channel.ID] = channel.Name
	}

	s.Lock()
	s.userToID = userMap
	s.idToUser = userIDMap
	s.userIDToIM = userIMMap
	s.channelToID = chanMap
	s.idToChannel = chanIDMap
	s.imToUser = userNameMap
	s.Unlock()
	s.log(bot.Info, "Users updated")
}

func (s *slackConnector) userID(u string) (i string, ok bool) {
	s.RLock()
	i, ok = s.userToID[u]
	s.RUnlock()
	return i, ok
}

func (s *slackConnector) userName(i string) (u string, ok bool) {
	s.RLock()
	u, ok = s.idToUser[i]
	s.RUnlock()
	return u, ok
}

func (s *slackConnector) userIMID(u string) (i string, ok bool) {
	s.RLock()
	i, ok = s.userIDToIM[u]
	s.RUnlock()
	return i, ok
}

func (s *slackConnector) chanID(c string) (i string, ok bool) {
	s.RLock()
	i, ok = s.channelToID[c]
	s.RUnlock()
	return i, ok
}

func (s *slackConnector) channelName(i string) (c string, ok bool) {
	s.RLock()
	c, ok = s.idToChannel[i]
	s.RUnlock()
	return c, ok
}

func (s *slackConnector) imUser(c string) (u string, ok bool) {
	s.RLock()
	u, ok = s.imToUser[c]
	s.RUnlock()
	return u, ok
}
<commit_msg>Regexp, 2nd try<commit_after>package slack

/* util has most of the struct, type, and const definitions, as well as
most of the internal methods. */

import (
	"fmt"
	"log"
	"regexp"
	"strings"
	"sync"
	"time"

	"github.com/nlopes/slack"
	"github.com/parsley42/gobot/bot"
)

const optimeout = 1 * time.Minute

type slackConnector struct {
	api          *slack.Client
	conn         *slack.RTM
	botName      string            // human-readable name of bot
	botID        string            // slack internal bot ID
	bot.Handler                    // bot interface for handling messages
	sync.RWMutex                   // shared mutex for locking connector data structures
	channelToID  map[string]string // map from channel names to channel IDs
	idToChannel  map[string]string // map from channel ID to channel name
	userToID     map[string]string // map from user names to user IDs
	idToUser     map[string]string // map from user name to user ID
	userIDToIM   map[string]string // map from user ID to IM channel ID
	imToUser     map[string]string // map from IM channel ID to user name
	level        bot.LogLevel      // current log level
}

func (s *slackConnector) addMessageMentions(msg string) string {
	re := regexp.MustCompile(`(?:^| )(@[0-9a-z]{1,21})\b`)
	mentions := re.FindAllStringSubmatch(msg, -1)
	if len(mentions) == 0 {
		return msg
	}
	mset := make(map[string]bool)
	for _, mention := range mentions {
		mset[mention[1]] = true
	}
	for mention, _ := range mset {
		userName := mention[1:]
		replace, ok := s.userID(userName)
		if !ok {
			// it's ok to have @notactuallyauser
			continue
		}
		msg = strings.Replace(msg, mention, "<@"+replace+">", -1)
	}
	return msg
}

// Examine incoming messages and route them to the appropriate bot
// method.
func (s *slackConnector) processMessage(msg *slack.MessageEvent) {
	s.log(bot.Trace, fmt.Sprintf("Message received: %v\n", msg))
	re := regexp.MustCompile(`<@U[A-Z0-9]{8}>`) // match a @user mention
	text := msg.Msg.Text
	chanID := msg.Msg.Channel
	mentions := re.FindAllString(text, -1)
	if len(mentions) != 0 {
		mset := make(map[string]bool)
		for _, mention := range mentions {
			mset[mention] = true
		}
		for mention, _ := range mset {
			mID := mention[2:11]
			replace, ok := s.userName(mID)
			if !ok {
				s.log(bot.Warn, "Couldn't find username for mentioned", mID)
				continue
			}
			text = strings.Replace(text, mention, "@"+replace, -1)
		}
	}
	switch chanID[:1] {
	case "D":
		userName, ok := s.imUser(chanID)
		if !ok {
			s.log(bot.Warn, "Couldn't find user name for IM", chanID)
			s.DirectMsg(chanID, text)
			return
		}
		s.DirectMsg(userName, text)
	case "C":
		channelName, ok := s.channelName(chanID)
		if !ok {
			s.log(bot.Warn, "Coudln't find channel name for ID", chanID)
			s.ChannelMsg(chanID, text)
			return
		}
		s.ChannelMsg(channelName, text)
	}
}

// log logs messages whenever the connector log level is
// less than the given level
func (s *slackConnector) log(l bot.LogLevel, v ...interface{}) {
	if l >= s.level {
		var prefix string
		switch l {
		case bot.Trace:
			prefix = "Trace:"
		case bot.Debug:
			prefix = "Debug:"
		case bot.Info:
			prefix = "Info"
		case bot.Warn:
			prefix = "Warning:"
		case bot.Error:
			prefix = "Error"
		}
		log.Println(prefix, v)
	}
}

// update maps is called whenever there are any changes
// to users or channels, so that plugins can use
// human-readable names for users and channels.
func (s *slackConnector) updateMaps() {
	s.log(bot.Trace, "Updating maps")
	deadline := time.Now().Add(optimeout)
	var (
		err        error
		userlist   []slack.User
		userIMlist []slack.IM
		chanlist   []slack.Channel
	)

	for tries := uint(0); time.Now().Before(deadline); tries++ {
		userlist, err = s.api.GetUsers()
		if err == nil {
			break
		}
	}
	if err != nil {
		log.Fatalf("Protocol timeout updating users: %v\n", err)
	}
	userMap := make(map[string]string)
	userIDMap := make(map[string]string)
	for _, user := range userlist {
		s.log(bot.Trace, "Mapping user name", user.Name, "to", user.ID)
		userMap[user.Name] = user.ID
		userIDMap[user.ID] = user.Name
	}

	for tries := uint(0); time.Now().Before(deadline); tries++ {
		userIMlist, err = s.api.GetIMChannels()
		if err == nil {
			break
		}
	}
	if err != nil {
		log.Fatalf("Protocol timeout updating IMchannels: %v\n", err)
	}
	userIMMap := make(map[string]string)
	userNameMap := make(map[string]string)
	for _, userIM := range userIMlist {
		s.log(bot.Trace, "Mapping user ID", userIM.User, "to IM channel", userIM.ID)
		userIMMap[userIM.User] = userIM.ID
		s.log(bot.Trace, "Mapping IM channel", userIM.ID, "to user name", userIDMap[userIM.User])
		userNameMap[userIM.ID] = userIDMap[userIM.User]
	}

	for tries := uint(0); time.Now().Before(deadline); tries++ {
		chanlist, err = s.api.GetChannels(true)
		if err == nil {
			break
		}
	}
	if err != nil {
		log.Fatalf("Protocol timeout updating channels: %v\n", err)
	}
	chanMap := make(map[string]string)
	chanIDMap := make(map[string]string)
	for _, channel := range chanlist {
		s.log(bot.Trace, "Mapping channel name", channel.Name, "to", channel.ID)
		chanMap[channel.Name] = channel.ID
		chanIDMap[channel.ID] = channel.Name
	}

	s.Lock()
	s.userToID = userMap
	s.idToUser = userIDMap
	s.userIDToIM = userIMMap
	s.channelToID = chanMap
	s.idToChannel = chanIDMap
	s.imToUser = userNameMap
	s.Unlock()
	s.log(bot.Info, "Users updated")
}

func (s *slackConnector) userID(u string) (i string, ok bool) {
	s.RLock()
	i, ok = s.userToID[u]
	s.RUnlock()
	return i, ok
}

func (s *slackConnector) userName(i string) (u string, ok bool) {
	s.RLock()
	u, ok = s.idToUser[i]
	s.RUnlock()
	return u, ok
}

func (s *slackConnector) userIMID(u string) (i string, ok bool) {
	s.RLock()
	i, ok = s.userIDToIM[u]
	s.RUnlock()
	return i, ok
}

func (s *slackConnector) chanID(c string) (i string, ok bool) {
	s.RLock()
	i, ok = s.channelToID[c]
	s.RUnlock()
	return i, ok
}

func (s *slackConnector) channelName(i string) (c string, ok bool) {
	s.RLock()
	c, ok = s.idToChannel[i]
	s.RUnlock()
	return c, ok
}

func (s *slackConnector) imUser(c string) (u string, ok bool) {
	s.RLock()
	u, ok = s.imToUser[c]
	s.RUnlock()
	return u, ok
}
<|endoftext|>


<commit_before>// Copyright 2013 The lime Authors.
// Use of this source code is governed by a 2-clause
// BSD-style license that can be found in the LICENSE file.

package backend

import (
	"io/ioutil"
	"lime/backend/loaders"
	"testing"
)

func TestLoadKeyBindings(t *testing.T) {
	tests := []string{
		"loaders/json/testdata/Default (OSX).sublime-keymap",
		// "/Users/quarnster/Library/Application Support/Sublime Text 3/Packages/Default/Default (Linux).sublime-keymap",
		// "/Users/quarnster/Library/Application Support/Sublime Text 3/Packages/Default/Default (OSX).sublime-keymap",
		// "/Users/quarnster/Library/Application Support/Sublime Text 3/Packages/Default/Default (Windows).sublime-keymap",
	}
	for i, fn := range tests {
		if d, err := ioutil.ReadFile(fn); err != nil {
			if i == 0 {
				t.Errorf("Couldn't load file %s: %s", fn, err)
			} else {
				t.Logf("Skipping: Couldn't load file %s: %s", fn, err)
			}
		} else {
			var bindings KeyBindings
			if err := loaders.LoadJSON(d, &bindings); err != nil {
				t.Error(err)
			}
		}
	}
}

func TestKeyFilter(t *testing.T) {
	fn := "loaders/json/testdata/Default (OSX).sublime-keymap"
	if d, err := ioutil.ReadFile(fn); err != nil {
		t.Errorf("Couldn't load file %s: %s", fn, err)
	} else {
		var bindings KeyBindings
		if err := loaders.LoadJSON(d, &bindings); err != nil {
			t.Error(err)
		}

		if b2 := bindings.Filter(KeyPress{Key: 'j', Ctrl: true}); b2.Len() != 3 {
			t.Errorf("Not of the expected length: %d, %s", 3, b2)
		} else if b3 := b2.Filter(KeyPress{Key: 's'}); b3.Len() != 1 {
			t.Errorf("Not of the expected length: %d, %s", 1, b3)
		}
	}
}

func TestKeyFilter2(t *testing.T) {
	ed := GetEditor()
	w := ed.NewWindow()
	v := w.NewFile()
	enable := "test1"
	OnQueryContext.Add(func(v *View, key string, operator Op, operand interface{}, match_all bool) QueryContextReturn {
		t.Log("Querying for", key)
		if key == enable {
			return True
		}
		return Unknown
	})
	fn := "testdata/Default.sublime-keymap"
	if d, err := ioutil.ReadFile(fn); err != nil {
		t.Errorf("Couldn't load file %s: %s", fn, err)
	} else {
		var bindings KeyBindings
		if err := loaders.LoadJSON(d, &bindings); err != nil {
			t.Error(err)
		}
		b2 := bindings.Filter(KeyPress{Key: 'i'})
		a := b2.Action(v)
		if a.Context[0].Key != enable {
			t.Error(b2, a)
		}
	}
}

func TestVintageous(t *testing.T) {
	fn := "testdata/Vintageous.sublime-keymap"
	ed := GetEditor()
	w := ed.NewWindow()
	v := w.NewFile()
	v.Settings().Set("command_mode", true)

	OnQueryContext.Add(func(v *View, key string, op Op, operand interface{}, match_all bool) QueryContextReturn {
		if key == "vi_has_action" {
			return True
		}
		return Unknown
	})

	if d, err := ioutil.ReadFile(fn); err != nil {
		t.Errorf("Couldn't load file %s: %s", fn, err)
	} else {
		var bindings KeyBindings
		if err := loaders.LoadJSON(d, &bindings); err != nil {
			t.Error(err)
		}

		b2 := bindings.Filter(KeyPress{Key: 'g'})
		if a := b2.Action(v); a == nil || a.Command != "set_action" {
			t.Error(a)
		}
		b2 = b2.Filter(KeyPress{Key: 'g'})
		if a := b2.Action(v); a == nil || a.Command != "set_motion" {
			t.Error(a)
		}
	}
}
<commit_msg>More cleanup of logs in tests that should not be called.<commit_after>// Copyright 2013 The lime Authors.
// Use of this source code is governed by a 2-clause
// BSD-style license that can be found in the LICENSE file.

package backend

import (
	"io/ioutil"
	"lime/backend/loaders"
	"testing"
)

func TestLoadKeyBindings(t *testing.T) {
	tests := []string{
		"loaders/json/testdata/Default (OSX).sublime-keymap",
	}
	for i, fn := range tests {
		if d, err := ioutil.ReadFile(fn); err != nil {
			if i == 0 {
				t.Errorf("Couldn't load file %s: %s", fn, err)
			}
		} else {
			var bindings KeyBindings
			if err := loaders.LoadJSON(d, &bindings); err != nil {
				t.Error(err)
			}
		}
	}
}

func TestKeyFilter(t *testing.T) {
	fn := "loaders/json/testdata/Default (OSX).sublime-keymap"
	if d, err := ioutil.ReadFile(fn); err != nil {
		t.Errorf("Couldn't load file %s: %s", fn, err)
	} else {
		var bindings KeyBindings
		if err := loaders.LoadJSON(d, &bindings); err != nil {
			t.Error(err)
		}

		if b2 := bindings.Filter(KeyPress{Key: 'j', Ctrl: true}); b2.Len() != 3 {
			t.Errorf("Not of the expected length: %d, %s", 3, b2)
		} else if b3 := b2.Filter(KeyPress{Key: 's'}); b3.Len() != 1 {
			t.Errorf("Not of the expected length: %d, %s", 1, b3)
		}
	}
}

func TestKeyFilter2(t *testing.T) {
	ed := GetEditor()
	w := ed.NewWindow()
	v := w.NewFile()
	enable := "test1"
	OnQueryContext.Add(func(v *View, key string, operator Op, operand interface{}, match_all bool) QueryContextReturn {
		if key == enable {
			return True
		}
		return Unknown
	})
	fn := "testdata/Default.sublime-keymap"
	if d, err := ioutil.ReadFile(fn); err != nil {
		t.Errorf("Couldn't load file %s: %s", fn, err)
	} else {
		var bindings KeyBindings
		if err := loaders.LoadJSON(d, &bindings); err != nil {
			t.Error(err)
		}
		b2 := bindings.Filter(KeyPress{Key: 'i'})
		a := b2.Action(v)
		if a.Context[0].Key != enable {
			t.Error(b2, a)
		}
	}
}

func TestVintageous(t *testing.T) {
	fn := "testdata/Vintageous.sublime-keymap"
	ed := GetEditor()
	w := ed.NewWindow()
	v := w.NewFile()
	v.Settings().Set("command_mode", true)

	OnQueryContext.Add(func(v *View, key string, op Op, operand interface{}, match_all bool) QueryContextReturn {
		if key == "vi_has_action" {
			return True
		}
		return Unknown
	})

	if d, err := ioutil.ReadFile(fn); err != nil {
		t.Errorf("Couldn't load file %s: %s", fn, err)
	} else {
		var bindings KeyBindings
		if err := loaders.LoadJSON(d, &bindings); err != nil {
			t.Error(err)
		}

		b2 := bindings.Filter(KeyPress{Key: 'g'})
		if a := b2.Action(v); a == nil || a.Command != "set_action" {
			t.Error(a)
		}
		b2 = b2.Filter(KeyPress{Key: 'g'})
		if a := b2.Action(v); a == nil || a.Command != "set_motion" {
			t.Error(a)
		}
	}
}
<|endoftext|>


<commit_before>package backends

import (
	"encoding/json"
	"fmt"
	"github.com/docker/libswarm/beam"
	"github.com/dotcloud/docker/engine"
	"github.com/dotcloud/docker/utils"
	"io"
	"io/ioutil"
	"net"
	"net/http"
	"net/http/httputil"
	"net/url"
	"strings"
	"time"
)

func Forward() beam.Sender {
	backend := beam.NewServer()
	backend.OnSpawn(beam.Handler(func(ctx *beam.Message) error {
		if len(ctx.Args) != 1 {
			return fmt.Errorf("forward: spawn takes exactly 1 argument, got %d", len(ctx.Args))
		}
		client, err := newClient(ctx.Args[0], "v1.11")
		if err != nil {
			return fmt.Errorf("%v", err)
		}
		f := &forwarder{
			client: client,
			Server: beam.NewServer(),
		}
		f.Server.OnAttach(beam.Handler(f.attach))
		f.Server.OnStart(beam.Handler(f.start))
		f.Server.OnLs(beam.Handler(f.ls))
		f.Server.OnSpawn(beam.Handler(f.spawn))
		_, err = ctx.Ret.Send(&beam.Message{Verb: beam.Ack, Ret: f.Server})
		return err
	}))
	return backend
}

type forwarder struct {
	client *client
	*beam.Server
}

func (f *forwarder) attach(ctx *beam.Message) error {
	if ctx.Args[0] == "" {
		ctx.Ret.Send(&beam.Message{Verb: beam.Ack, Ret: f.Server})
		for {
			time.Sleep(1 * time.Second)
			(&beam.Object{ctx.Ret}).Log("forward: heartbeat")
		}
	} else {
		c := f.newContainer(ctx.Args[0])
		ctx.Ret.Send(&beam.Message{Verb: beam.Ack, Ret: c})
	}
	return nil
}

func (f *forwarder) start(ctx *beam.Message) error {
	ctx.Ret.Send(&beam.Message{Verb: beam.Ack})
	return nil
}

func (f *forwarder) ls(ctx *beam.Message) error {
	resp, err := f.client.call("GET", "/containers/json", "")
	if err != nil {
		return fmt.Errorf("%s: get: %v", f.client.URL.String(), err)
	}
	// FIXME: check for response error
	c := engine.NewTable("Created", 0)
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return fmt.Errorf("%s: read body: %v", f.client.URL.String(), err)
	}
	if _, err := c.ReadListFrom(body); err != nil {
		return fmt.Errorf("%s: readlist: %v", f.client.URL.String(), err)
	}
	names := []string{}
	for _, env := range c.Data {
		names = append(names, env.GetList("Names")[0][1:])
	}
	if _, err := ctx.Ret.Send(&beam.Message{Verb: beam.Set, Args: names}); err != nil {
		return fmt.Errorf("%s: send response: %v", f.client.URL.String(), err)
	}
	return nil
}

func (f *forwarder) spawn(ctx *beam.Message) error {
	if len(ctx.Args) != 1 {
		return fmt.Errorf("forward: spawn takes exactly 1 argument, got %d", len(ctx.Args))
	}
	resp, err := f.client.call("POST", "/containers/create", ctx.Args[0])
	if err != nil {
		return err
	}
	respBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}
	if resp.StatusCode != 201 {
		return fmt.Errorf("expected status code 201, got %d:\n%s", resp.StatusCode, respBody)
	}
	var respJson struct{ Id string }
	if err = json.Unmarshal(respBody, &respJson); err != nil {
		return err
	}
	c := f.newContainer(respJson.Id)
	if _, err = ctx.Ret.Send(&beam.Message{Verb: beam.Ack, Ret: c}); err != nil {
		return err
	}
	return nil
}

func (f *forwarder) newContainer(id string) beam.Sender {
	c := &container{forwarder: f, id: id}
	instance := beam.NewServer()
	instance.OnAttach(beam.Handler(c.attach))
	instance.OnStart(beam.Handler(c.start))
	instance.OnStop(beam.Handler(c.stop))
	instance.OnGet(beam.Handler(c.get))
	return instance
}

type container struct {
	forwarder *forwarder
	id        string
}

func (c *container) attach(ctx *beam.Message) error {
	if _, err := ctx.Ret.Send(&beam.Message{Verb: beam.Ack}); err != nil {
		return err
	}

	path := fmt.Sprintf("/containers/%s/attach?stdout=1&stderr=1&stream=1", c.id)

	stdoutR, stdoutW := io.Pipe()
	stderrR, stderrW := io.Pipe()
	go copyOutput(ctx.Ret, stdoutR, "stdout")
	go copyOutput(ctx.Ret, stderrR, "stderr")
	c.forwarder.client.hijack("POST", path, nil, stdoutW, stderrW)

	return nil
}

func copyOutput(sender beam.Sender, reader io.Reader, tag string) {
	chunk := make([]byte, 4096)
	for {
		n, err := reader.Read(chunk)
		if n > 0 {
			sender.Send(&beam.Message{Verb: beam.Log, Args: []string{tag, string(chunk[0:n])}})
		}
		if err != nil {
			message := fmt.Sprintf("Error reading from stream: %v", err)
			sender.Send(&beam.Message{Verb: beam.Error, Args: []string{message}})
			break
		}
	}
}

func (c *container) start(ctx *beam.Message) error {
	path := fmt.Sprintf("/containers/%s/start", c.id)
	resp, err := c.forwarder.client.call("POST", path, "{}")
	if err != nil {
		return err
	}
	respBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}
	if resp.StatusCode != 204 {
		return fmt.Errorf("expected status code 204, got %d:\n%s", resp.StatusCode, respBody)
	}
	if _, err := ctx.Ret.Send(&beam.Message{Verb: beam.Ack}); err != nil {
		return err
	}
	return nil
}

func (c *container) stop(ctx *beam.Message) error {
	path := fmt.Sprintf("/containers/%s/stop", c.id)
	resp, err := c.forwarder.client.call("POST", path, "{}")
	if err != nil {
		return err
	}
	respBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}
	if resp.StatusCode != 204 {
		return fmt.Errorf("expected status code 204, got %d:\n%s", resp.StatusCode, respBody)
	}
	if _, err := ctx.Ret.Send(&beam.Message{Verb: beam.Ack}); err != nil {
		return err
	}
	return nil
}

func (c *container) get(ctx *beam.Message) error {
	path := fmt.Sprintf("/containers/%s/json", c.id)
	resp, err := c.forwarder.client.call("GET", path, "")
	if err != nil {
		return err
	}
	respBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}
	if resp.StatusCode != 200 {
		return fmt.Errorf("%s", respBody)
	}
	if _, err := ctx.Ret.Send(&beam.Message{Verb: beam.Set, Args: []string{string(respBody)}}); err != nil {
		return err
	}
	return nil
}

type client struct {
	URL     *url.URL
	proto   string
	addr    string
	version string
}

func newClient(peer, version string) (*client, error) {
	u, err := url.Parse(peer)
	if err != nil {
		return nil, err
	}
	c := &client{
		URL:     u,
		version: version,
	}
	c.URL.Scheme = "http"
	return c, nil
}

func (c *client) call(method, path, body string) (*http.Response, error) {
	path = fmt.Sprintf("/%s%s", c.version, path)
	u, err := url.Parse(path)
	if err != nil {
		return nil, err
	}
	u.Host = c.URL.Host
	u.Scheme = c.URL.Scheme
	req, err := http.NewRequest(method, u.String(), strings.NewReader(body))
	if err != nil {
		return nil, err
	}
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return nil, err
	}
	return resp, nil
}

func (c *client) hijack(method, path string, in io.ReadCloser, stdout, stderr io.Writer) error {
	path = fmt.Sprintf("/%s%s", c.version, path)
	dial, err := net.Dial("tcp", c.URL.Host)
	if err != nil {
		return err
	}
	req, err := http.NewRequest(method, path, nil)
	if err != nil {
		return err
	}

	clientconn := httputil.NewClientConn(dial, nil)
	defer clientconn.Close()

	clientconn.Do(req)

	rwc, br := clientconn.Hijack()
	defer rwc.Close()

	receiveStdout := utils.Go(func() (err error) {
		defer func() {
			if in != nil {
				in.Close()
			}
		}()
		_, err = utils.StdCopy(stdout, stderr, br)
		utils.Debugf("[hijack] End of stdout")
		return err
	})
	sendStdin := utils.Go(func() error {
		if in != nil {
			io.Copy(rwc, in)
			utils.Debugf("[hijack] End of stdin")
		}
		if tcpc, ok := rwc.(*net.TCPConn); ok {
			if err := tcpc.CloseWrite(); err != nil {
				utils.Debugf("Couldn't send EOF: %s", err)
			}
		} else if unixc, ok := rwc.(*net.UnixConn); ok {
			if err := unixc.CloseWrite(); err != nil {
				utils.Debugf("Couldn't send EOF: %s", err)
			}
		}
		// Discard errors due to pipe interruption
		return nil
	})
	if err := <-receiveStdout; err != nil {
		utils.Debugf("Error receiveStdout: %s", err)
		return err
	}

	if err := <-sendStdin; err != nil {
		utils.Debugf("Error sendStdin: %s", err)
		return err
	}
	return nil
}
<commit_msg>Support unix:// URLs in forward<commit_after>package backends

import (
	"encoding/json"
	"fmt"
	"github.com/docker/libswarm/beam"
	"github.com/dotcloud/docker/engine"
	"github.com/dotcloud/docker/utils"
	"io"
	"io/ioutil"
	"net"
	"net/http"
	"net/http/httputil"
	"net/url"
	"strings"
	"time"
)

func Forward() beam.Sender {
	backend := beam.NewServer()
	backend.OnSpawn(beam.Handler(func(ctx *beam.Message) error {
		if len(ctx.Args) != 1 {
			return fmt.Errorf("forward: spawn takes exactly 1 argument, got %d", len(ctx.Args))
		}
		client, err := newClient(ctx.Args[0], "v1.11")
		if err != nil {
			return fmt.Errorf("%v", err)
		}
		f := &forwarder{
			client: client,
			Server: beam.NewServer(),
		}
		f.Server.OnAttach(beam.Handler(f.attach))
		f.Server.OnStart(beam.Handler(f.start))
		f.Server.OnLs(beam.Handler(f.ls))
		f.Server.OnSpawn(beam.Handler(f.spawn))
		_, err = ctx.Ret.Send(&beam.Message{Verb: beam.Ack, Ret: f.Server})
		return err
	}))
	return backend
}

type forwarder struct {
	client *client
	*beam.Server
}

func (f *forwarder) attach(ctx *beam.Message) error {
	if ctx.Args[0] == "" {
		ctx.Ret.Send(&beam.Message{Verb: beam.Ack, Ret: f.Server})
		for {
			time.Sleep(1 * time.Second)
			(&beam.Object{ctx.Ret}).Log("forward: heartbeat")
		}
	} else {
		c := f.newContainer(ctx.Args[0])
		ctx.Ret.Send(&beam.Message{Verb: beam.Ack, Ret: c})
	}
	return nil
}

func (f *forwarder) start(ctx *beam.Message) error {
	ctx.Ret.Send(&beam.Message{Verb: beam.Ack})
	return nil
}

func (f *forwarder) ls(ctx *beam.Message) error {
	resp, err := f.client.call("GET", "/containers/json", "")
	if err != nil {
		return fmt.Errorf("%s: get: %v", f.client.URL.String(), err)
	}
	// FIXME: check for response error
	c := engine.NewTable("Created", 0)
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return fmt.Errorf("%s: read body: %v", f.client.URL.String(), err)
	}
	if _, err := c.ReadListFrom(body); err != nil {
		return fmt.Errorf("%s: readlist: %v", f.client.URL.String(), err)
	}
	names := []string{}
	for _, env := range c.Data {
		names = append(names, env.GetList("Names")[0][1:])
	}
	if _, err := ctx.Ret.Send(&beam.Message{Verb: beam.Set, Args: names}); err != nil {
		return fmt.Errorf("%s: send response: %v", f.client.URL.String(), err)
	}
	return nil
}

func (f *forwarder) spawn(ctx *beam.Message) error {
	if len(ctx.Args) != 1 {
		return fmt.Errorf("forward: spawn takes exactly 1 argument, got %d", len(ctx.Args))
	}
	resp, err := f.client.call("POST", "/containers/create", ctx.Args[0])
	if err != nil {
		return err
	}
	respBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}
	if resp.StatusCode != 201 {
		return fmt.Errorf("expected status code 201, got %d:\n%s", resp.StatusCode, respBody)
	}
	var respJson struct{ Id string }
	if err = json.Unmarshal(respBody, &respJson); err != nil {
		return err
	}
	c := f.newContainer(respJson.Id)
	if _, err = ctx.Ret.Send(&beam.Message{Verb: beam.Ack, Ret: c}); err != nil {
		return err
	}
	return nil
}

func (f *forwarder) newContainer(id string) beam.Sender {
	c := &container{forwarder: f, id: id}
	instance := beam.NewServer()
	instance.OnAttach(beam.Handler(c.attach))
	instance.OnStart(beam.Handler(c.start))
	instance.OnStop(beam.Handler(c.stop))
	instance.OnGet(beam.Handler(c.get))
	return instance
}

type container struct {
	forwarder *forwarder
	id        string
}

func (c *container) attach(ctx *beam.Message) error {
	if _, err := ctx.Ret.Send(&beam.Message{Verb: beam.Ack}); err != nil {
		return err
	}

	path := fmt.Sprintf("/containers/%s/attach?stdout=1&stderr=1&stream=1", c.id)

	stdoutR, stdoutW := io.Pipe()
	stderrR, stderrW := io.Pipe()
	go copyOutput(ctx.Ret, stdoutR, "stdout")
	go copyOutput(ctx.Ret, stderrR, "stderr")
	c.forwarder.client.hijack("POST", path, nil, stdoutW, stderrW)

	return nil
}

func copyOutput(sender beam.Sender, reader io.Reader, tag string) {
	chunk := make([]byte, 4096)
	for {
		n, err := reader.Read(chunk)
		if n > 0 {
			sender.Send(&beam.Message{Verb: beam.Log, Args: []string{tag, string(chunk[0:n])}})
		}
		if err != nil {
			message := fmt.Sprintf("Error reading from stream: %v", err)
			sender.Send(&beam.Message{Verb: beam.Error, Args: []string{message}})
			break
		}
	}
}

func (c *container) start(ctx *beam.Message) error {
	path := fmt.Sprintf("/containers/%s/start", c.id)
	resp, err := c.forwarder.client.call("POST", path, "{}")
	if err != nil {
		return err
	}
	respBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}
	if resp.StatusCode != 204 {
		return fmt.Errorf("expected status code 204, got %d:\n%s", resp.StatusCode, respBody)
	}
	if _, err := ctx.Ret.Send(&beam.Message{Verb: beam.Ack}); err != nil {
		return err
	}
	return nil
}

func (c *container) stop(ctx *beam.Message) error {
	path := fmt.Sprintf("/containers/%s/stop", c.id)
	resp, err := c.forwarder.client.call("POST", path, "{}")
	if err != nil {
		return err
	}
	respBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}
	if resp.StatusCode != 204 {
		return fmt.Errorf("expected status code 204, got %d:\n%s", resp.StatusCode, respBody)
	}
	if _, err := ctx.Ret.Send(&beam.Message{Verb: beam.Ack}); err != nil {
		return err
	}
	return nil
}

func (c *container) get(ctx *beam.Message) error {
	path := fmt.Sprintf("/containers/%s/json", c.id)
	resp, err := c.forwarder.client.call("GET", path, "")
	if err != nil {
		return err
	}
	respBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}
	if resp.StatusCode != 200 {
		return fmt.Errorf("%s", respBody)
	}
	if _, err := ctx.Ret.Send(&beam.Message{Verb: beam.Set, Args: []string{string(respBody)}}); err != nil {
		return err
	}
	return nil
}

type client struct {
	URL     *url.URL
	proto   string
	addr    string
	version string
}

func newClient(peer, version string) (*client, error) {
	u, err := url.Parse(peer)
	if err != nil {
		return nil, err
	}
	protoAddrParts := strings.SplitN(peer, "://", 2)
	c := &client{
		URL:     u,
		proto:   protoAddrParts[0],
		addr:    protoAddrParts[1],
		version: version,
	}
	c.URL.Scheme = "http"
	return c, nil
}

func (c *client) dial() (net.Conn, error) {
	return net.Dial(c.proto, c.addr)
}

func (c *client) call(method, path, body string) (*http.Response, error) {
	path = fmt.Sprintf("/%s%s", c.version, path)
	u, err := url.Parse(path)
	if err != nil {
		return nil, err
	}
	u.Host = "dummy.host"
	u.Scheme = c.URL.Scheme
	req, err := http.NewRequest(method, u.String(), strings.NewReader(body))
	if err != nil {
		return nil, err
	}
	tr := &http.Transport{Dial: func(_, _ string) (net.Conn, error) { return c.dial() }}
	client := &http.Client{Transport: tr}
	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	return resp, nil
}

func (c *client) hijack(method, path string, in io.ReadCloser, stdout, stderr io.Writer) error {
	path = fmt.Sprintf("/%s%s", c.version, path)
	dial, err := c.dial()
	if err != nil {
		return err
	}
	req, err := http.NewRequest(method, path, nil)
	if err != nil {
		return err
	}

	clientconn := httputil.NewClientConn(dial, nil)
	defer clientconn.Close()

	clientconn.Do(req)

	rwc, br := clientconn.Hijack()
	defer rwc.Close()

	receiveStdout := utils.Go(func() (err error) {
		defer func() {
			if in != nil {
				in.Close()
			}
		}()
		_, err = utils.StdCopy(stdout, stderr, br)
		utils.Debugf("[hijack] End of stdout")
		return err
	})
	sendStdin := utils.Go(func() error {
		if in != nil {
			io.Copy(rwc, in)
			utils.Debugf("[hijack] End of stdin")
		}
		if tcpc, ok := rwc.(*net.TCPConn); ok {
			if err := tcpc.CloseWrite(); err != nil {
				utils.Debugf("Couldn't send EOF: %s", err)
			}
		} else if unixc, ok := rwc.(*net.UnixConn); ok {
			if err := unixc.CloseWrite(); err != nil {
				utils.Debugf("Couldn't send EOF: %s", err)
			}
		}
		// Discard errors due to pipe interruption
		return nil
	})
	if err := <-receiveStdout; err != nil {
		utils.Debugf("Error receiveStdout: %s", err)
		return err
	}

	if err := <-sendStdin; err != nil {
		utils.Debugf("Error sendStdin: %s", err)
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"os"

	"github.com/subutai-io/base/agent/agent"
	"github.com/subutai-io/base/agent/cli"
	"github.com/subutai-io/base/agent/config"
	"github.com/subutai-io/base/agent/log"

	"github.com/codegangsta/cli"
)

var TIMESTAMP string = "-unknown"

func init() {
	if os.Getuid() != 0 {
		log.Error("Please run as root")
	}
	os.Setenv("PATH", "/apps/subutai/current/bin:"+os.Getenv("PATH"))
	if len(os.Args) > 1 {
		if os.Args[1] == "-d" {
			log.Level(log.DebugLevel)
		}
	}
}

func main() {
	app := cli.NewApp()
	app.Name = "Subutai"
	app.Version = "v4.0.0-RC6" + TIMESTAMP
	app.Usage = "daemon and command line interface binary"

	app.Flags = []cli.Flag{cli.BoolFlag{
		Name:  "d",
		Usage: "debug mode"}}

	app.Commands = []cli.Command{{
		Name: "attach", Usage: "attach to container",
		Flags: []cli.Flag{
			cli.BoolFlag{Name: "c", Usage: "clear environment"},
			cli.BoolFlag{Name: "x", Usage: "use x86 personality"},
			cli.BoolFlag{Name: "r", Usage: "connect as regular user"}},
		Action: func(c *cli.Context) {
			lib.LxcAttach(c.Args().Get(0), c.Bool("c"), c.Bool("x"), c.Bool("r"))
		}}, {

		Name: "backup", Usage: "backup Subutai container",
		Flags: []cli.Flag{
			cli.BoolFlag{Name: "full", Usage: "make full backup"},
			cli.BoolFlag{Name: "stop", Usage: "stop container at the time of backup"}},
		Action: func(c *cli.Context) {
			lib.BackupContainer(c.Args().Get(0), c.Bool("full"), c.Bool("stop"))
		}}, {

		Name: "batch", Usage: "batch commands execution",
		Flags: []cli.Flag{
			cli.StringFlag{Name: "json", Usage: "JSON string with commands"}},
		Action: func(c *cli.Context) {
			lib.Batch(c.String("json"))
		}}, {

		Name: "clone", Usage: "clone Subutai container",
		Flags: []cli.Flag{
			cli.StringFlag{Name: "e", Usage: "set environment id for container"},
			cli.StringFlag{Name: "i", Usage: "set container IP address and VLAN"},
			cli.StringFlag{Name: "t", Usage: "token to verify with MH"}},
		Action: func(c *cli.Context) {
			lib.LxcClone(c.Args().Get(0), c.Args().Get(1), c.String("e"), c.String("i"), c.String("t"))
		}}, {

		Name: "cleanup", Usage: "clean Subutai environment",
		Action: func(c *cli.Context) {
			lib.Cleanup(c.Args().Get(0))
		}}, {

		Name: "config", Usage: "containerName add/del key value",
		Flags: []cli.Flag{
			cli.StringFlag{Name: "o", Usage: "add/del key value"},
			cli.StringFlag{Name: "k", Usage: "add/del key value"},
			cli.StringFlag{Name: "v", Usage: "add/del key value"},
		},
		Action: func(c *cli.Context) {
			lib.LxcConfig(c.Args().Get(0), c.String("o"), c.String("k"), c.String("v"))
		}}, {

		Name: "daemon", Usage: "start an agent",
		Action: func(c *cli.Context) {
			config.InitAgentDebug()
			agent.Start(c)
		}}, {

		Name: "demote", Usage: "demote Subutai container",
		Flags: []cli.Flag{
			cli.StringFlag{Name: "i", Usage: "network value ie 192.168.1.1/24"},
			cli.StringFlag{Name: "v", Usage: "vlan id"},
		},
		Action: func(c *cli.Context) {
			lib.LxcDemote(c.Args().Get(0), c.String("i"), c.String("v"))
		}}, {

		Name: "destroy", Usage: "destroy Subutai container",
		Action: func(c *cli.Context) {
			lib.LxcDestroy(c.Args().Get(0))
		}}, {

		Name: "export", Usage: "export Subutai container",
		Flags: []cli.Flag{
			cli.StringFlag{Name: "v", Usage: "template version"}},
		Action: func(c *cli.Context) {
			lib.LxcExport(c.Args().Get(0), c.String("v"))
		}}, {

		Name: "import", Usage: "import Subutai template",
		Flags: []cli.Flag{
			cli.StringFlag{Name: "v", Usage: "template version"},
			cli.StringFlag{Name: "t", Usage: "token to access kurjun repo"}},
		Action: func(c *cli.Context) {
			lib.LxcImport(c.Args().Get(0), c.String("v"), c.String("t"))
		}}, {

		Name: "list", Usage: "list Subutai container",
		Flags: []cli.Flag{
			cli.BoolFlag{Name: "c", Usage: "containers only"},
			cli.BoolFlag{Name: "t", Usage: "templates only"},
			cli.BoolFlag{Name: "r", Usage: "registered only"},
			cli.BoolFlag{Name: "i", Usage: "detailed container info"},
			cli.BoolFlag{Name: "a", Usage: "with ancestors"},
			cli.BoolFlag{Name: "f", Usage: "fancy mode"},
			cli.BoolFlag{Name: "p", Usage: "with parent"}},
		Action: func(c *cli.Context) {
			lib.LxcList(c.Args().Get(0), c.Bool("c"), c.Bool("t"), c.Bool("r"), c.Bool("i"), c.Bool("a"), c.Bool("f"), c.Bool("p"))
		}}, {

		Name: "management_network", Usage: "configure management network",
		Flags: []cli.Flag{
			cli.BoolFlag{Name: "listtunnel, l", Usage: "-l"},
			cli.StringFlag{Name: "createtunnel, c", Usage: "-c TUNNELPORTNAME TUNNELIPADDRESS TUNNELTYPE"},

			cli.BoolFlag{Name: "listvnimap, v", Usage: "-v"},
			cli.StringFlag{Name: "createvnimap, m", Usage: "-m TUNNELPORTNAME VNI VLANID ENV_ID"},
		},

		Subcommands: []cli.Command{{
			Name:  "tunnel",
			Usage: "tunnels operation",
			Flags: []cli.Flag{
				cli.StringFlag{Name: "create", Usage: "create tunnel (tunnel -c)"},
				cli.StringFlag{Name: "delete", Usage: "delete tunnel (tunnel -d)"},
				cli.BoolFlag{Name: "list", Usage: "list of tunnels (tunnel -l)"},

				cli.StringFlag{Name: "remoteip", Usage: "remote ip"},
				cli.StringFlag{Name: "vlan", Usage: "tunnel vlan"},
				cli.StringFlag{Name: "vni", Usage: "vni"},
			},
			Action: func(c *cli.Context) {
				lib.VxlanTunnel(c.String("create"), c.String("delete"), c.String("remoteip"), c.String("vlan"), c.String("vni"), c.Bool("list"))
			}}, {

			Name:  "p2p",
			Usage: "p2p network operation",
			Flags: []cli.Flag{
				cli.BoolFlag{Name: "c", Usage: "create p2p instance (p2p -c interfaceName hash key ttl localPeepIPAddr)"},
				cli.BoolFlag{Name: "d", Usage: "delete p2p instance (p2p -d hash)"},
				cli.BoolFlag{Name: "u", Usage: "update p2p instance encryption key (p2p -u hash newkey ttl)"},
				cli.BoolFlag{Name: "l", Usage: "list of p2p instances (p2p -l)"},
				cli.BoolFlag{Name: "p", Usage: "list of p2p participants (p2p -p hash)"}},
			Action: func(c *cli.Context) {
				lib.P2P(c.Bool("c"), c.Bool("d"), c.Bool("u"), c.Bool("l"), c.Bool("p"), os.Args)
			}}},

		Action: func(c *cli.Context) {
			lib.LxcManagementNetwork(os.Args)
		}}, {

		Name: "metrics", Usage: "list Subutai container",
		Flags: []cli.Flag{
			cli.StringFlag{Name: "s", Usage: "start time"},
			cli.StringFlag{Name: "e", Usage: "end time"}},
		Action: func(c *cli.Context) {
			lib.HostMetrics(c.Args().Get(0), c.String("s"), c.String("e"))
		}}, {

		Name: "network", Usage: "containerName set/remove/list network vlan id",
		Flags: []cli.Flag{
			cli.StringFlag{Name: "set, s", Usage: "IPADDRESS/NETMASK"},
			cli.StringFlag{Name: "vlan, v", Usage: "vlanid"},
			cli.BoolFlag{Name: "remove, r", Usage: ""},
			cli.BoolFlag{Name: "list, l", Usage: ""},
		},
		Action: func(c *cli.Context) {
			lib.LxcNetwork(c.Args().Get(0), c.String("s"), c.String("vlan"), c.Bool("r"), c.Bool("l"))
		}}, {

		Name: "promote", Usage: "promote Subutai container",
		Action: func(c *cli.Context) {
			lib.LxcPromote(c.Args().Get(0))
		}}, {

		Name: "proxy", Usage: "Subutai reverse proxy",
		Subcommands: []cli.Command{
			{
				Name:     "add",
				Usage:    "add reverse proxy component",
				HideHelp: true,
				Flags: []cli.Flag{
					cli.StringFlag{Name: "domain,d", Usage: "add domain to vlan"},
					cli.StringFlag{Name: "host, h", Usage: "add host to domain on vlan"},
					cli.StringFlag{Name: "policy, p", Usage: "set load balance policy (rr|lb|hash)"},
					cli.StringFlag{Name: "file, f", Usage: "specify pem certificate file"}},
				Action: func(c *cli.Context) {
					lib.ProxyAdd(c.Args().Get(0), c.String("d"), c.String("h"), c.String("p"), c.String("f"))
				},
			},
			{
				Name:     "del",
				Usage:    "del reverse proxy component",
				HideHelp: true,
				Flags: []cli.Flag{
					cli.BoolFlag{Name: "domain, d", Usage: "delete domain from vlan"},
					cli.StringFlag{Name: "host, h", Usage: "delete host from domain on vlan"}},
				Action: func(c *cli.Context) {
					lib.ProxyDel(c.Args().Get(0), c.String("h"), c.Bool("d"))
				},
			},
			{
				Name:     "check",
				Usage:    "check existing domain or host",
				HideHelp: true,
				Flags: []cli.Flag{
					cli.BoolFlag{Name: "domain, d", Usage: "check domains on vlan"},
					cli.StringFlag{Name: "host, h", Usage: "check hosts on vlan"}},
				Action: func(c *cli.Context) {
					lib.ProxyCheck(c.Args().Get(0), c.String("h"), c.Bool("d"))
				},
			},
		}}, {

		Name: "quota", Usage: "set quotas for Subutai container",
		Flags: []cli.Flag{
			cli.StringFlag{Name: "s", Usage: "set quota for the specified resource type"}},
		Action: func(c *cli.Context) {
			lib.LxcQuota(c.Args().Get(0), c.Args().Get(1), c.String("s"))
		}}, {

		Name: "register", Usage: "register Subutai container",
		Action: func(c *cli.Context) {
			lib.LxcRegister(c.Args().Get(0))
		}}, {

		Name: "rename", Usage: "rename Subutai container",
		Action: func(c *cli.Context) {
			lib.LxcRename(c.Args().Get(0), c.Args().Get(1))
		}}, {

		Name: "restore", Usage: "restore Subutai container",
		Flags: []cli.Flag{
			cli.StringFlag{Name: "d", Usage: "date of backup snapshot"},
			cli.StringFlag{Name: "c", Usage: "name of new container"}},
		Action: func(c *cli.Context) {
			lib.RestoreContainer(c.Args().Get(0), c.Args().Get(1), c.Args().Get(2))
		}}, {

		Name: "stats", Usage: "statistics from host",
		Action: func(c *cli.Context) {
			lib.Stats(c.Args().Get(0), c.Args().Get(1), c.Args().Get(2))
		}}, {

		Name: "start", Usage: "start Subutai container",
		Action: func(c *cli.Context) {
			lib.LxcStart(c.Args().Get(0))
		}}, {

		Name: "stop", Usage: "stop Subutai container",
		Action: func(c *cli.Context) {
			lib.LxcStop(c.Args().Get(0))
		}}, {

		Name: "tunnel", Usage: "create SSH tunnel",
		Flags: []cli.Flag{
			cli.BoolFlag{Name: "g", Usage: "global accessible tunnel"}},
		Action: func(c *cli.Context) {
			lib.Tunnel(c.Args().Get(0), c.Args().Get(1), c.Args().Get(2), c.Bool("g"))
		}}, {

		Name: "unregister", Usage: "unregister Subutai container",
		Action: func(c *cli.Context) {
			lib.LxcUnregister(c.Args().Get(0))
		}}, {

		Name: "update", Usage: "update Subutai management, container or Resource host",
		Flags: []cli.Flag{
			cli.BoolFlag{Name: "c", Usage: "check for updates without installation"}},
		Action: func(c *cli.Context) {
			lib.Update(c.Args().Get(0), c.Bool("c"))
		}},
	}

	app.Run(os.Args)
}
<commit_msg>Changed hardcoded version<commit_after>package main

import (
	"os"

	"github.com/subutai-io/base/agent/agent"
	"github.com/subutai-io/base/agent/cli"
	"github.com/subutai-io/base/agent/config"
	"github.com/subutai-io/base/agent/log"

	"github.com/codegangsta/cli"
)

var TIMESTAMP string = "-unknown"

func init() {
	if os.Getuid() != 0 {
		log.Error("Please run as root")
	}
	os.Setenv("PATH", "/apps/subutai/current/bin:"+os.Getenv("PATH"))
	if len(os.Args) > 1 {
		if os.Args[1] == "-d" {
			log.Level(log.DebugLevel)
		}
	}
}

func main() {
	app := cli.NewApp()
	app.Name = "Subutai"
	app.Version = "v4.0.0-RC7" + TIMESTAMP
	app.Usage = "daemon and command line interface binary"

	app.Flags = []cli.Flag{cli.BoolFlag{
		Name:  "d",
		Usage: "debug mode"}}

	app.Commands = []cli.Command{{
		Name: "attach", Usage: "attach to container",
		Flags: []cli.Flag{
			cli.BoolFlag{Name: "c", Usage: "clear environment"},
			cli.BoolFlag{Name: "x", Usage: "use x86 personality"},
			cli.BoolFlag{Name: "r", Usage: "connect as regular user"}},
		Action: func(c *cli.Context) {
			lib.LxcAttach(c.Args().Get(0), c.Bool("c"), c.Bool("x"), c.Bool("r"))
		}}, {

		Name: "backup", Usage: "backup Subutai container",
		Flags: []cli.Flag{
			cli.BoolFlag{Name: "full", Usage: "make full backup"},
			cli.BoolFlag{Name: "stop", Usage: "stop container at the time of backup"}},
		Action: func(c *cli.Context) {
			lib.BackupContainer(c.Args().Get(0), c.Bool("full"), c.Bool("stop"))
		}}, {

		Name: "batch", Usage: "batch commands execution",
		Flags: []cli.Flag{
			cli.StringFlag{Name: "json", Usage: "JSON string with commands"}},
		Action: func(c *cli.Context) {
			lib.Batch(c.String("json"))
		}}, {

		Name: "clone", Usage: "clone Subutai container",
		Flags: []cli.Flag{
			cli.StringFlag{Name: "e", Usage: "set environment id for container"},
			cli.StringFlag{Name: "i", Usage: "set container IP address and VLAN"},
			cli.StringFlag{Name: "t", Usage: "token to verify with MH"}},
		Action: func(c *cli.Context) {
			lib.LxcClone(c.Args().Get(0), c.Args().Get(1), c.String("e"), c.String("i"), c.String("t"))
		}}, {

		Name: "cleanup", Usage: "clean Subutai environment",
		Action: func(c *cli.Context) {
			lib.Cleanup(c.Args().Get(0))
		}}, {

		Name: "config", Usage: "containerName add/del key value",
		Flags: []cli.Flag{
			cli.StringFlag{Name: "o", Usage: "add/del key value"},
			cli.StringFlag{Name: "k", Usage: "add/del key value"},
			cli.StringFlag{Name: "v", Usage: "add/del key value"},
		},
		Action: func(c *cli.Context) {
			lib.LxcConfig(c.Args().Get(0), c.String("o"), c.String("k"), c.String("v"))
		}}, {

		Name: "daemon", Usage: "start an agent",
		Action: func(c *cli.Context) {
			config.InitAgentDebug()
			agent.Start(c)
		}}, {

		Name: "demote", Usage: "demote Subutai container",
		Flags: []cli.Flag{
			cli.StringFlag{Name: "i", Usage: "network value ie 192.168.1.1/24"},
			cli.StringFlag{Name: "v", Usage: "vlan id"},
		},
		Action: func(c *cli.Context) {
			lib.LxcDemote(c.Args().Get(0), c.String("i"), c.String("v"))
		}}, {

		Name: "destroy", Usage: "destroy Subutai container",
		Action: func(c *cli.Context) {
			lib.LxcDestroy(c.Args().Get(0))
		}}, {

		Name: "export", Usage: "export Subutai container",
		Flags: []cli.Flag{
			cli.StringFlag{Name: "v", Usage: "template version"}},
		Action: func(c *cli.Context) {
			lib.LxcExport(c.Args().Get(0), c.String("v"))
		}}, {

		Name: "import", Usage: "import Subutai template",
		Flags: []cli.Flag{
			cli.StringFlag{Name: "v", Usage: "template version"},
			cli.StringFlag{Name: "t", Usage: "token to access kurjun repo"}},
		Action: func(c *cli.Context) {
			lib.LxcImport(c.Args().Get(0), c.String("v"), c.String("t"))
		}}, {

		Name: "list", Usage: "list Subutai container",
		Flags: []cli.Flag{
			cli.BoolFlag{Name: "c", Usage: "containers only"},
			cli.BoolFlag{Name: "t", Usage: "templates only"},
			cli.BoolFlag{Name: "r", Usage: "registered only"},
			cli.BoolFlag{Name: "i", Usage: "detailed container info"},
			cli.BoolFlag{Name: "a", Usage: "with ancestors"},
			cli.BoolFlag{Name: "f", Usage: "fancy mode"},
			cli.BoolFlag{Name: "p", Usage: "with parent"}},
		Action: func(c *cli.Context) {
			lib.LxcList(c.Args().Get(0), c.Bool("c"), c.Bool("t"), c.Bool("r"), c.Bool("i"), c.Bool("a"), c.Bool("f"), c.Bool("p"))
		}}, {

		Name: "management_network", Usage: "configure management network",
		Flags: []cli.Flag{
			cli.BoolFlag{Name: "listtunnel, l", Usage: "-l"},
			cli.StringFlag{Name: "createtunnel, c", Usage: "-c TUNNELPORTNAME TUNNELIPADDRESS TUNNELTYPE"},

			cli.BoolFlag{Name: "listvnimap, v", Usage: "-v"},
			cli.StringFlag{Name: "createvnimap, m", Usage: "-m TUNNELPORTNAME VNI VLANID ENV_ID"},
		},

		Subcommands: []cli.Command{{
			Name:  "tunnel",
			Usage: "tunnels operation",
			Flags: []cli.Flag{
				cli.StringFlag{Name: "create", Usage: "create tunnel (tunnel -c)"},
				cli.StringFlag{Name: "delete", Usage: "delete tunnel (tunnel -d)"},
				cli.BoolFlag{Name: "list", Usage: "list of tunnels (tunnel -l)"},

				cli.StringFlag{Name: "remoteip", Usage: "remote ip"},
				cli.StringFlag{Name: "vlan", Usage: "tunnel vlan"},
				cli.StringFlag{Name: "vni", Usage: "vni"},
			},
			Action: func(c *cli.Context) {
				lib.VxlanTunnel(c.String("create"), c.String("delete"), c.String("remoteip"), c.String("vlan"), c.String("vni"), c.Bool("list"))
			}}, {

			Name:  "p2p",
			Usage: "p2p network operation",
			Flags: []cli.Flag{
				cli.BoolFlag{Name: "c", Usage: "create p2p instance (p2p -c interfaceName hash key ttl localPeepIPAddr)"},
				cli.BoolFlag{Name: "d", Usage: "delete p2p instance (p2p -d hash)"},
				cli.BoolFlag{Name: "u", Usage: "update p2p instance encryption key (p2p -u hash newkey ttl)"},
				cli.BoolFlag{Name: "l", Usage: "list of p2p instances (p2p -l)"},
				cli.BoolFlag{Name: "p", Usage: "list of p2p participants (p2p -p hash)"}},
			Action: func(c *cli.Context) {
				lib.P2P(c.Bool("c"), c.Bool("d"), c.Bool("u"), c.Bool("l"), c.Bool("p"), os.Args)
			}}},

		Action: func(c *cli.Context) {
			lib.LxcManagementNetwork(os.Args)
		}}, {

		Name: "metrics", Usage: "list Subutai container",
		Flags: []cli.Flag{
			cli.StringFlag{Name: "s", Usage: "start time"},
			cli.StringFlag{Name: "e", Usage: "end time"}},
		Action: func(c *cli.Context) {
			lib.HostMetrics(c.Args().Get(0), c.String("s"), c.String("e"))
		}}, {

		Name: "network", Usage: "containerName set/remove/list network vlan id",
		Flags: []cli.Flag{
			cli.StringFlag{Name: "set, s", Usage: "IPADDRESS/NETMASK"},
			cli.StringFlag{Name: "vlan, v", Usage: "vlanid"},
			cli.BoolFlag{Name: "remove, r", Usage: ""},
			cli.BoolFlag{Name: "list, l", Usage: ""},
		},
		Action: func(c *cli.Context) {
			lib.LxcNetwork(c.Args().Get(0), c.String("s"), c.String("vlan"), c.Bool("r"), c.Bool("l"))
		}}, {

		Name: "promote", Usage: "promote Subutai container",
		Action: func(c *cli.Context) {
			lib.LxcPromote(c.Args().Get(0))
		}}, {

		Name: "proxy", Usage: "Subutai reverse proxy",
		Subcommands: []cli.Command{
			{
				Name:     "add",
				Usage:    "add reverse proxy component",
				HideHelp: true,
				Flags: []cli.Flag{
					cli.StringFlag{Name: "domain,d", Usage: "add domain to vlan"},
					cli.StringFlag{Name: "host, h", Usage: "add host to domain on vlan"},
					cli.StringFlag{Name: "policy, p", Usage: "set load balance policy (rr|lb|hash)"},
					cli.StringFlag{Name: "file, f", Usage: "specify pem certificate file"}},
				Action: func(c *cli.Context) {
					lib.ProxyAdd(c.Args().Get(0), c.String("d"), c.String("h"), c.String("p"), c.String("f"))
				},
			},
			{
				Name:     "del",
				Usage:    "del reverse proxy component",
				HideHelp: true,
				Flags: []cli.Flag{
					cli.BoolFlag{Name: "domain, d", Usage: "delete domain from vlan"},
					cli.StringFlag{Name: "host, h", Usage: "delete host from domain on vlan"}},
				Action: func(c *cli.Context) {
					lib.ProxyDel(c.Args().Get(0), c.String("h"), c.Bool("d"))
				},
			},
			{
				Name:     "check",
				Usage:    "check existing domain or host",
				HideHelp: true,
				Flags: []cli.Flag{
					cli.BoolFlag{Name: "domain, d", Usage: "check domains on vlan"},
					cli.StringFlag{Name: "host, h", Usage: "check hosts on vlan"}},
				Action: func(c *cli.Context) {
					lib.ProxyCheck(c.Args().Get(0), c.String("h"), c.Bool("d"))
				},
			},
		}}, {

		Name: "quota", Usage: "set quotas for Subutai container",
		Flags: []cli.Flag{
			cli.StringFlag{Name: "s", Usage: "set quota for the specified resource type"}},
		Action: func(c *cli.Context) {
			lib.LxcQuota(c.Args().Get(0), c.Args().Get(1), c.String("s"))
		}}, {

		Name: "register", Usage: "register Subutai container",
		Action: func(c *cli.Context) {
			lib.LxcRegister(c.Args().Get(0))
		}}, {

		Name: "rename", Usage: "rename Subutai container",
		Action: func(c *cli.Context) {
			lib.LxcRename(c.Args().Get(0), c.Args().Get(1))
		}}, {

		Name: "restore", Usage: "restore Subutai container",
		Flags: []cli.Flag{
			cli.StringFlag{Name: "d", Usage: "date of backup snapshot"},
			cli.StringFlag{Name: "c", Usage: "name of new container"}},
		Action: func(c *cli.Context) {
			lib.RestoreContainer(c.Args().Get(0), c.Args().Get(1), c.Args().Get(2))
		}}, {

		Name: "stats", Usage: "statistics from host",
		Action: func(c *cli.Context) {
			lib.Stats(c.Args().Get(0), c.Args().Get(1), c.Args().Get(2))
		}}, {

		Name: "start", Usage: "start Subutai container",
		Action: func(c *cli.Context) {
			lib.LxcStart(c.Args().Get(0))
		}}, {

		Name: "stop", Usage: "stop Subutai container",
		Action: func(c *cli.Context) {
			lib.LxcStop(c.Args().Get(0))
		}}, {

		Name: "tunnel", Usage: "create SSH tunnel",
		Flags: []cli.Flag{
			cli.BoolFlag{Name: "g", Usage: "global accessible tunnel"}},
		Action: func(c *cli.Context) {
			lib.Tunnel(c.Args().Get(0), c.Args().Get(1), c.Args().Get(2), c.Bool("g"))
		}}, {

		Name: "unregister", Usage: "unregister Subutai container",
		Action: func(c *cli.Context) {
			lib.LxcUnregister(c.Args().Get(0))
		}}, {

		Name: "update", Usage: "update Subutai management, container or Resource host",
		Flags: []cli.Flag{
			cli.BoolFlag{Name: "c", Usage: "check for updates without installation"}},
		Action: func(c *cli.Context) {
			lib.Update(c.Args().Get(0), c.Bool("c"))
		}},
	}

	app.Run(os.Args)
}
<|endoftext|>