<commit_before>package main

import (
	"fmt"
	"net/url"
	"os"
	"os/exec"
	"runtime"
	"strings"
	"syscall"

	"code.google.com/p/goauth2/oauth"
	"github.com/codegangsta/cli"
	"github.com/google/go-github/github"
	"github.com/motemen/ghq/pocket"
	"github.com/motemen/ghq/utils"
)

var Commands = []cli.Command{
	commandGet,
	commandList,
	commandLook,
	commandImport,
}

var commandGet = cli.Command{
	Name:  "get",
	Usage: "Clone/sync with a remote repository",
	Description: `
    Clone a GitHub repository under ghq root direcotry. If the repository is
    already cloned to local, nothing will happen unless '-u' ('--update')
    flag is supplied, in which case 'git remote update' is executed.
    When you use '-p' option, the repository is cloned via SSH.
`,
	Action: doGet,
	Flags: []cli.Flag{
		cli.BoolFlag{"update, u", "Update local repository if cloned already"},
		cli.BoolFlag{"p", "Clone with SSH"},
		cli.BoolFlag{"shallow", "Do a shallow clone"},
	},
}

var commandList = cli.Command{
	Name:  "list",
	Usage: "List local repositories",
	Description: `
    List locally cloned repositories. If a query argument is given, only
    repositories whose names contain that query text are listed. '-e'
    ('--exact') forces the match to be an exact one (i.e. the query equals to
    _project_ or _user_/_project_) If '-p' ('--full-path') is given, the full paths
    to the repository root are printed instead of relative ones.
`,
	Action: doList,
	Flags: []cli.Flag{
		cli.BoolFlag{"exact, e", "Perform an exact match"},
		cli.BoolFlag{"full-path, p", "Print full paths"},
		cli.BoolFlag{"unique", "Print unique subpaths"},
	},
}

var commandLook = cli.Command{
	Name:  "look",
	Usage: "Look into a local repository",
	Description: `
    Look into a locally cloned repository with the shell.
`,
	Action: doLook,
}

var commandImport = cli.Command{
	Name:  "import",
	Usage: "Import repositories from other web services",
	Subcommands: []cli.Command{
		commandImportStarred,
		commandImportPocket,
	},
}

var commandImportStarred = cli.Command{
	Name:  "starred",
	Usage: "Get all starred GitHub repositories",
	Description: `
    Retrieves GitHub repositories that are starred by the user specified and
    performs 'get' for each of them.
`,
	Action: doImportStarred,
	Flags: []cli.Flag{
		cli.BoolFlag{"update, u", "Update local repository if cloned already"},
		cli.BoolFlag{"p", "Clone with SSH"},
		cli.BoolFlag{"shallow", "Do a shallow clone"},
	},
}

var commandImportPocket = cli.Command{
	Name:  "pocket",
	Usage: "Get all github.com entries in Pocket",
	Description: `
    Retrieves Pocket <http://getpocket.com/> entries of github.com and
    performs 'get' for each of them.
`,
	Action: doImportPocket,
	Flags: []cli.Flag{
		cli.BoolFlag{"update, u", "Update local repository if cloned already"},
	},
}

type commandDoc struct {
	Parent    string
	Arguments string
}

var commandDocs = map[string]commandDoc{
	"get":     {"", "[-u] <repository URL> | [-u] [-p] <user>/<project>"},
	"list":    {"", "[-p] [-e] [<query>]"},
	"look":    {"", "<project> | <user>/<project> | <host>/<user>/<project>"},
	"import":  {"", "[-u] [-p] starred <user> | [-u] pocket"},
	"starred": {"import", "[-u] [-p] <user>"},
	"pocket":  {"import", "[-u]"},
}

// Makes template conditionals to generate per-command documents.
func mkCommandsTemplate(genTemplate func(commandDoc) string) string {
	template := "{{if false}}"
	for _, command := range append(Commands, commandImportStarred, commandImportPocket) {
		template = template + fmt.Sprintf("{{else if (eq .Name %q)}}%s", command.Name, genTemplate(commandDocs[command.Name]))
	}
	return template + "{{end}}"
}

func init() {
	argsTemplate := mkCommandsTemplate(func(doc commandDoc) string { return doc.Arguments })
	parentTemplate := mkCommandsTemplate(func(doc commandDoc) string { return string(strings.TrimLeft(doc.Parent+" ", " ")) })

	cli.CommandHelpTemplate = `NAME:
    {{.Name}} - {{.Usage}}

USAGE:
    ghq ` + parentTemplate + `{{.Name}} ` + argsTemplate + `
{{if (len .Description)}}
DESCRIPTION: {{.Description}}
{{end}}{{if (len .Flags)}}
OPTIONS:
    {{range .Flags}}{{.}}
    {{end}}
{{end}}`
}

func doGet(c *cli.Context) {
	argURL := c.Args().Get(0)
	doUpdate := c.Bool("update")
	isShallow := c.Bool("shallow")

	if argURL == "" {
		cli.ShowCommandHelp(c, "get")
		os.Exit(1)
	}

	url, err := NewURL(argURL)
	utils.DieIf(err)

	isSSH := c.Bool("p")
	if isSSH {
		// Assume Git repository if `-p` is given.
		url, err = ConvertGitURLHTTPToSSH(url)
		utils.DieIf(err)
	}

	remote, err := NewRemoteRepository(url)
	utils.DieIf(err)

	if remote.IsValid() == false {
		utils.Log("error", fmt.Sprintf("Not a valid repository: %s", url))
		os.Exit(1)
	}

	getRemoteRepository(remote, doUpdate, isShallow)
}

// getRemoteRepository clones or updates a remote repository remote.
// If doUpdate is true, updates the locally cloned repository. Otherwise does nothing.
// If isShallow is true, does shallow cloning. (no effect if already cloned or the VCS is Mercurial)
func getRemoteRepository(remote RemoteRepository, doUpdate bool, isShallow bool) {
	remoteURL := remote.URL()
	local := LocalRepositoryFromURL(remoteURL)

	path := local.FullPath
	newPath := false

	_, err := os.Stat(path)
	if err != nil {
		if os.IsNotExist(err) {
			newPath = true
			err = nil
		}
		utils.PanicIf(err)
	}

	if newPath {
		utils.Log("clone", fmt.Sprintf("%s -> %s", remoteURL, path))

		vcs := remote.VCS()
		if vcs == nil {
			utils.Log("error", fmt.Sprintf("Counld not found version control system: %s", remoteURL))
			os.Exit(1)
		}

		vcs.Clone(remoteURL, path, isShallow)
	} else {
		if doUpdate {
			utils.Log("update", path)
			local.VCS().Update(path)
		} else {
			utils.Log("exists", path)
		}
	}
}

func doList(c *cli.Context) {
	query := c.Args().First()
	exact := c.Bool("exact")
	printFullPaths := c.Bool("full-path")
	printUniquePaths := c.Bool("unique")

	var filterFn func(*LocalRepository) bool
	if query == "" {
		filterFn = func(_ *LocalRepository) bool {
			return true
		}
	} else if exact {
		filterFn = func(repo *LocalRepository) bool {
			return repo.Matches(query)
		}
	} else {
		filterFn = func(repo *LocalRepository) bool {
			return strings.Contains(repo.NonHostPath(), query)
		}
	}

	repos := []*LocalRepository{}

	walkLocalRepositories(func(repo *LocalRepository) {
		if filterFn(repo) == false {
			return
		}

		repos = append(repos, repo)
	})

	if printUniquePaths {
		subpathCount := map[string]int{} // Count duplicated subpaths (ex. foo/dotfiles and bar/dotfiles)
		reposCount := map[string]int{}   // Check duplicated repositories among roots

		// Primary first
		for _, repo := range repos {
			if reposCount[repo.RelPath] == 0 {
				for _, p := range repo.Subpaths() {
					subpathCount[p] = subpathCount[p] + 1
				}
			}

			reposCount[repo.RelPath] = reposCount[repo.RelPath] + 1
		}

		for _, repo := range repos {
			if reposCount[repo.RelPath] > 1 && repo.IsUnderPrimaryRoot() == false {
				continue
			}

			for _, p := range repo.Subpaths() {
				if subpathCount[p] == 1 {
					fmt.Println(p)
					break
				}
			}
		}
	} else {
		for _, repo := range repos {
			if printFullPaths {
				fmt.Println(repo.FullPath)
			} else {
				fmt.Println(repo.RelPath)
			}
		}
	}
}

func doLook(c *cli.Context) {
	name := c.Args().First()

	if name == "" {
		cli.ShowCommandHelp(c, "look")
		os.Exit(1)
	}

	reposFound := []*LocalRepository{}
	walkLocalRepositories(func(repo *LocalRepository) {
		if repo.Matches(name) {
			reposFound = append(reposFound, repo)
		}
	})

	switch len(reposFound) {
	case 0:
		utils.Log("error", "No repository found")

	case 1:
		if runtime.GOOS == "windows" {
			cmd := exec.Command(os.Getenv("COMSPEC"))
			cmd.Stdin = os.Stdin
			cmd.Stdout = os.Stdout
			cmd.Stderr = os.Stderr
			cmd.Dir = reposFound[0].FullPath
			err := cmd.Start()
			if err == nil {
				cmd.Wait()
				os.Exit(0)
			}
		} else {
			shell := os.Getenv("SHELL")
			if shell == "" {
				shell = "/bin/sh"
			}

			utils.Log("cd", reposFound[0].FullPath)
			err := os.Chdir(reposFound[0].FullPath)
			utils.PanicIf(err)

			syscall.Exec(shell, []string{shell}, syscall.Environ())
		}

	default:
		utils.Log("error", "More than one repositories are found; Try more precise name")
		for _, repo := range reposFound {
			utils.Log("error", "- "+strings.Join(repo.PathParts, "/"))
		}
	}
}

func doImportStarred(c *cli.Context) {
	user := c.Args().First()
	doUpdate := c.Bool("update")
	isSSH := c.Bool("p")
	isShallow := c.Bool("shallow")

	if user == "" {
		cli.ShowCommandHelp(c, "starred")
		os.Exit(1)
	}

	githubToken := os.Getenv("GHQ_GITHUB_TOKEN")

	var client *github.Client

	if githubToken != "" {
		oauthTransport := &oauth.Transport{
			Token: &oauth.Token{AccessToken: githubToken},
		}
		client = github.NewClient(oauthTransport.Client())
	} else {
		client = github.NewClient(nil)
	}
	options := &github.ActivityListStarredOptions{Sort: "created"}

	for page := 1; ; page++ {
		options.Page = page

		repositories, res, err := client.Activity.ListStarred(user, options)
		utils.DieIf(err)

		utils.Log("page", fmt.Sprintf("%d/%d", page, res.LastPage))
		for _, repo := range repositories {
			url, err := url.Parse(*repo.HTMLURL)
			if err != nil {
				utils.Log("error", fmt.Sprintf("Could not parse URL <%s>: %s", repo.HTMLURL, err))
				continue
			}
			if isSSH {
				url, err = ConvertGitURLHTTPToSSH(url)
				if err != nil {
					utils.Log("error", fmt.Sprintf("Could not convert URL <%s>: %s", repo.HTMLURL, err))
					continue
				}
			}

			remote, err := NewRemoteRepository(url)
			if utils.ErrorIf(err) {
				continue
			}

			if remote.IsValid() == false {
				utils.Log("skip", fmt.Sprintf("Not a valid repository: %s", url))
				continue
			}

			getRemoteRepository(remote, doUpdate, isShallow)
		}

		if page >= res.LastPage {
			break
		}
	}
}

func doImportPocket(c *cli.Context) {
	doUpdate := c.Bool("update")
	isShallow := c.Bool("shallow")

	if pocket.ConsumerKey == "" {
		utils.Log("error", "Built without consumer key set")
		return
	}

	accessToken, err := GitConfig("ghq.pocket.token")
	utils.PanicIf(err)

	if accessToken == "" {
		receiverURL, ch, err := pocket.StartAccessTokenReceiver()
		utils.PanicIf(err)

		utils.Log("pocket", "Waiting for Pocket authentication callback at "+receiverURL)

		utils.Log("pocket", "Obtaining request token")
		authRequest, err := pocket.ObtainRequestToken(receiverURL)
		utils.DieIf(err)

		url := pocket.GenerateAuthorizationURL(authRequest.Code, receiverURL)
		utils.Log("open", url)

		<-ch

		utils.Log("pocket", "Obtaining access token")
		authorized, err := pocket.ObtainAccessToken(authRequest.Code)
		utils.DieIf(err)

		utils.Log("authorized", authorized.Username)

		accessToken = authorized.AccessToken
		utils.Run("git", "config", "ghq.pocket.token", authorized.AccessToken)
	}

	utils.Log("pocket", "Retrieving github.com entries")
	res, err := pocket.RetrieveGitHubEntries(accessToken)
	utils.DieIf(err)

	for _, item := range res.List {
		url, err := url.Parse(item.ResolvedURL)
		if err != nil {
			utils.Log("error", fmt.Sprintf("Could not parse URL <%s>: %s", item.ResolvedURL, err))
			continue
		}

		remote, err := NewRemoteRepository(url)
		if utils.ErrorIf(err) {
			continue
		}

		if remote.IsValid() == false {
			utils.Log("skip", fmt.Sprintf("Not a valid repository: %s", url))
			continue
		}

		getRemoteRepository(remote, doUpdate, isShallow)
	}
}
<commit_msg>Add ghq.github.token option to configure<commit_after>package main

import (
	"fmt"
	"net/url"
	"os"
	"os/exec"
	"runtime"
	"strings"
	"syscall"

	"code.google.com/p/goauth2/oauth"
	"github.com/codegangsta/cli"
	"github.com/google/go-github/github"
	"github.com/motemen/ghq/pocket"
	"github.com/motemen/ghq/utils"
)

var Commands = []cli.Command{
	commandGet,
	commandList,
	commandLook,
	commandImport,
}

var commandGet = cli.Command{
	Name:  "get",
	Usage: "Clone/sync with a remote repository",
	Description: `
    Clone a GitHub repository under ghq root direcotry. If the repository is
    already cloned to local, nothing will happen unless '-u' ('--update')
    flag is supplied, in which case 'git remote update' is executed.
    When you use '-p' option, the repository is cloned via SSH.
`,
	Action: doGet,
	Flags: []cli.Flag{
		cli.BoolFlag{"update, u", "Update local repository if cloned already"},
		cli.BoolFlag{"p", "Clone with SSH"},
		cli.BoolFlag{"shallow", "Do a shallow clone"},
	},
}

var commandList = cli.Command{
	Name:  "list",
	Usage: "List local repositories",
	Description: `
    List locally cloned repositories. If a query argument is given, only
    repositories whose names contain that query text are listed. '-e'
    ('--exact') forces the match to be an exact one (i.e. the query equals to
    _project_ or _user_/_project_) If '-p' ('--full-path') is given, the full paths
    to the repository root are printed instead of relative ones.
`,
	Action: doList,
	Flags: []cli.Flag{
		cli.BoolFlag{"exact, e", "Perform an exact match"},
		cli.BoolFlag{"full-path, p", "Print full paths"},
		cli.BoolFlag{"unique", "Print unique subpaths"},
	},
}

var commandLook = cli.Command{
	Name:  "look",
	Usage: "Look into a local repository",
	Description: `
    Look into a locally cloned repository with the shell.
`,
	Action: doLook,
}

var commandImport = cli.Command{
	Name:  "import",
	Usage: "Import repositories from other web services",
	Subcommands: []cli.Command{
		commandImportStarred,
		commandImportPocket,
	},
}

var commandImportStarred = cli.Command{
	Name:  "starred",
	Usage: "Get all starred GitHub repositories",
	Description: `
    Retrieves GitHub repositories that are starred by the user specified and
    performs 'get' for each of them.
`,
	Action: doImportStarred,
	Flags: []cli.Flag{
		cli.BoolFlag{"update, u", "Update local repository if cloned already"},
		cli.BoolFlag{"p", "Clone with SSH"},
		cli.BoolFlag{"shallow", "Do a shallow clone"},
	},
}

var commandImportPocket = cli.Command{
	Name:  "pocket",
	Usage: "Get all github.com entries in Pocket",
	Description: `
    Retrieves Pocket <http://getpocket.com/> entries of github.com and
    performs 'get' for each of them.
`,
	Action: doImportPocket,
	Flags: []cli.Flag{
		cli.BoolFlag{"update, u", "Update local repository if cloned already"},
	},
}

type commandDoc struct {
	Parent    string
	Arguments string
}

var commandDocs = map[string]commandDoc{
	"get":     {"", "[-u] <repository URL> | [-u] [-p] <user>/<project>"},
	"list":    {"", "[-p] [-e] [<query>]"},
	"look":    {"", "<project> | <user>/<project> | <host>/<user>/<project>"},
	"import":  {"", "[-u] [-p] starred <user> | [-u] pocket"},
	"starred": {"import", "[-u] [-p] <user>"},
	"pocket":  {"import", "[-u]"},
}

// Makes template conditionals to generate per-command documents.
func mkCommandsTemplate(genTemplate func(commandDoc) string) string {
	template := "{{if false}}"
	for _, command := range append(Commands, commandImportStarred, commandImportPocket) {
		template = template + fmt.Sprintf("{{else if (eq .Name %q)}}%s", command.Name, genTemplate(commandDocs[command.Name]))
	}
	return template + "{{end}}"
}

func init() {
	argsTemplate := mkCommandsTemplate(func(doc commandDoc) string { return doc.Arguments })
	parentTemplate := mkCommandsTemplate(func(doc commandDoc) string { return string(strings.TrimLeft(doc.Parent+" ", " ")) })

	cli.CommandHelpTemplate = `NAME:
    {{.Name}} - {{.Usage}}

USAGE:
    ghq ` + parentTemplate + `{{.Name}} ` + argsTemplate + `
{{if (len .Description)}}
DESCRIPTION: {{.Description}}
{{end}}{{if (len .Flags)}}
OPTIONS:
    {{range .Flags}}{{.}}
    {{end}}
{{end}}`
}

func doGet(c *cli.Context) {
	argURL := c.Args().Get(0)
	doUpdate := c.Bool("update")
	isShallow := c.Bool("shallow")

	if argURL == "" {
		cli.ShowCommandHelp(c, "get")
		os.Exit(1)
	}

	url, err := NewURL(argURL)
	utils.DieIf(err)

	isSSH := c.Bool("p")
	if isSSH {
		// Assume Git repository if `-p` is given.
		url, err = ConvertGitURLHTTPToSSH(url)
		utils.DieIf(err)
	}

	remote, err := NewRemoteRepository(url)
	utils.DieIf(err)

	if remote.IsValid() == false {
		utils.Log("error", fmt.Sprintf("Not a valid repository: %s", url))
		os.Exit(1)
	}

	getRemoteRepository(remote, doUpdate, isShallow)
}

// getRemoteRepository clones or updates a remote repository remote.
// If doUpdate is true, updates the locally cloned repository. Otherwise does nothing.
// If isShallow is true, does shallow cloning. (no effect if already cloned or the VCS is Mercurial)
func getRemoteRepository(remote RemoteRepository, doUpdate bool, isShallow bool) {
	remoteURL := remote.URL()
	local := LocalRepositoryFromURL(remoteURL)

	path := local.FullPath
	newPath := false

	_, err := os.Stat(path)
	if err != nil {
		if os.IsNotExist(err) {
			newPath = true
			err = nil
		}
		utils.PanicIf(err)
	}

	if newPath {
		utils.Log("clone", fmt.Sprintf("%s -> %s", remoteURL, path))

		vcs := remote.VCS()
		if vcs == nil {
			utils.Log("error", fmt.Sprintf("Counld not found version control system: %s", remoteURL))
			os.Exit(1)
		}

		vcs.Clone(remoteURL, path, isShallow)
	} else {
		if doUpdate {
			utils.Log("update", path)
			local.VCS().Update(path)
		} else {
			utils.Log("exists", path)
		}
	}
}

func doList(c *cli.Context) {
	query := c.Args().First()
	exact := c.Bool("exact")
	printFullPaths := c.Bool("full-path")
	printUniquePaths := c.Bool("unique")

	var filterFn func(*LocalRepository) bool
	if query == "" {
		filterFn = func(_ *LocalRepository) bool {
			return true
		}
	} else if exact {
		filterFn = func(repo *LocalRepository) bool {
			return repo.Matches(query)
		}
	} else {
		filterFn = func(repo *LocalRepository) bool {
			return strings.Contains(repo.NonHostPath(), query)
		}
	}

	repos := []*LocalRepository{}

	walkLocalRepositories(func(repo *LocalRepository) {
		if filterFn(repo) == false {
			return
		}

		repos = append(repos, repo)
	})

	if printUniquePaths {
		subpathCount := map[string]int{} // Count duplicated subpaths (ex. foo/dotfiles and bar/dotfiles)
		reposCount := map[string]int{}   // Check duplicated repositories among roots

		// Primary first
		for _, repo := range repos {
			if reposCount[repo.RelPath] == 0 {
				for _, p := range repo.Subpaths() {
					subpathCount[p] = subpathCount[p] + 1
				}
			}

			reposCount[repo.RelPath] = reposCount[repo.RelPath] + 1
		}

		for _, repo := range repos {
			if reposCount[repo.RelPath] > 1 && repo.IsUnderPrimaryRoot() == false {
				continue
			}

			for _, p := range repo.Subpaths() {
				if subpathCount[p] == 1 {
					fmt.Println(p)
					break
				}
			}
		}
	} else {
		for _, repo := range repos {
			if printFullPaths {
				fmt.Println(repo.FullPath)
			} else {
				fmt.Println(repo.RelPath)
			}
		}
	}
}

func doLook(c *cli.Context) {
	name := c.Args().First()

	if name == "" {
		cli.ShowCommandHelp(c, "look")
		os.Exit(1)
	}

	reposFound := []*LocalRepository{}
	walkLocalRepositories(func(repo *LocalRepository) {
		if repo.Matches(name) {
			reposFound = append(reposFound, repo)
		}
	})

	switch len(reposFound) {
	case 0:
		utils.Log("error", "No repository found")

	case 1:
		if runtime.GOOS == "windows" {
			cmd := exec.Command(os.Getenv("COMSPEC"))
			cmd.Stdin = os.Stdin
			cmd.Stdout = os.Stdout
			cmd.Stderr = os.Stderr
			cmd.Dir = reposFound[0].FullPath
			err := cmd.Start()
			if err == nil {
				cmd.Wait()
				os.Exit(0)
			}
		} else {
			shell := os.Getenv("SHELL")
			if shell == "" {
				shell = "/bin/sh"
			}

			utils.Log("cd", reposFound[0].FullPath)
			err := os.Chdir(reposFound[0].FullPath)
			utils.PanicIf(err)

			syscall.Exec(shell, []string{shell}, syscall.Environ())
		}

	default:
		utils.Log("error", "More than one repositories are found; Try more precise name")
		for _, repo := range reposFound {
			utils.Log("error", "- "+strings.Join(repo.PathParts, "/"))
		}
	}
}

func doImportStarred(c *cli.Context) {
	user := c.Args().First()
	doUpdate := c.Bool("update")
	isSSH := c.Bool("p")
	isShallow := c.Bool("shallow")

	if user == "" {
		cli.ShowCommandHelp(c, "starred")
		os.Exit(1)
	}

	githubToken := os.Getenv("GHQ_GITHUB_TOKEN")

	if githubToken == "" {
		var err error
		githubToken, err = GitConfig("ghq.github.token")
		utils.PanicIf(err)
	}

	var client *github.Client

	if githubToken != "" {
		oauthTransport := &oauth.Transport{
			Token: &oauth.Token{AccessToken: githubToken},
		}
		client = github.NewClient(oauthTransport.Client())
	} else {
		client = github.NewClient(nil)
	}

	options := &github.ActivityListStarredOptions{Sort: "created"}

	for page := 1; ; page++ {
		options.Page = page

		repositories, res, err := client.Activity.ListStarred(user, options)
		utils.DieIf(err)

		utils.Log("page", fmt.Sprintf("%d/%d", page, res.LastPage))
		for _, repo := range repositories {
			url, err := url.Parse(*repo.HTMLURL)
			if err != nil {
				utils.Log("error", fmt.Sprintf("Could not parse URL <%s>: %s", repo.HTMLURL, err))
				continue
			}
			if isSSH {
				url, err = ConvertGitURLHTTPToSSH(url)
				if err != nil {
					utils.Log("error", fmt.Sprintf("Could not convert URL <%s>: %s", repo.HTMLURL, err))
					continue
				}
			}

			remote, err := NewRemoteRepository(url)
			if utils.ErrorIf(err) {
				continue
			}

			if remote.IsValid() == false {
				utils.Log("skip", fmt.Sprintf("Not a valid repository: %s", url))
				continue
			}

			getRemoteRepository(remote, doUpdate, isShallow)
		}

		if page >= res.LastPage {
			break
		}
	}
}

func doImportPocket(c *cli.Context) {
	doUpdate := c.Bool("update")
	isShallow := c.Bool("shallow")

	if pocket.ConsumerKey == "" {
		utils.Log("error", "Built without consumer key set")
		return
	}

	accessToken, err := GitConfig("ghq.pocket.token")
	utils.PanicIf(err)

	if accessToken == "" {
		receiverURL, ch, err := pocket.StartAccessTokenReceiver()
		utils.PanicIf(err)

		utils.Log("pocket", "Waiting for Pocket authentication callback at "+receiverURL)

		utils.Log("pocket", "Obtaining request token")
		authRequest, err := pocket.ObtainRequestToken(receiverURL)
		utils.DieIf(err)

		url := pocket.GenerateAuthorizationURL(authRequest.Code, receiverURL)
		utils.Log("open", url)

		<-ch

		utils.Log("pocket", "Obtaining access token")
		authorized, err := pocket.ObtainAccessToken(authRequest.Code)
		utils.DieIf(err)

		utils.Log("authorized", authorized.Username)

		accessToken = authorized.AccessToken
		utils.Run("git", "config", "ghq.pocket.token", authorized.AccessToken)
	}

	utils.Log("pocket", "Retrieving github.com entries")
	res, err := pocket.RetrieveGitHubEntries(accessToken)
	utils.DieIf(err)

	for _, item := range res.List {
		url, err := url.Parse(item.ResolvedURL)
		if err != nil {
			utils.Log("error", fmt.Sprintf("Could not parse URL <%s>: %s", item.ResolvedURL, err))
			continue
		}

		remote, err := NewRemoteRepository(url)
		if utils.ErrorIf(err) {
			continue
		}

		if remote.IsValid() == false {
			utils.Log("skip", fmt.Sprintf("Not a valid repository: %s", url))
			continue
		}

		getRemoteRepository(remote, doUpdate, isShallow)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"os"
	"os/signal"

	"github.com/hashicorp/terraform/command"
	"github.com/mitchellh/cli"
)

// Commands is the mapping of all the available Terraform commands.
var Commands map[string]cli.CommandFactory

// Ui is the cli.Ui used for communicating to the outside world.
var Ui cli.Ui

const ErrorPrefix = "e:"
const OutputPrefix = "o:"

func init() {
	Ui = &cli.PrefixedUi{
		AskPrefix:    OutputPrefix,
		OutputPrefix: OutputPrefix,
		InfoPrefix:   OutputPrefix,
		ErrorPrefix:  ErrorPrefix,
		Ui:           &cli.BasicUi{Writer: os.Stdout},
	}

	Commands = map[string]cli.CommandFactory{
		"apply": func() (cli.Command, error) {
			return &command.ApplyCommand{
				ShutdownCh:  makeShutdownCh(),
				ContextOpts: &ContextOpts,
				Ui:          Ui,
			}, nil
		},

		"graph": func() (cli.Command, error) {
			return &command.GraphCommand{
				ContextOpts: &ContextOpts,
				Ui:          Ui,
			}, nil
		},

		"plan": func() (cli.Command, error) {
			return &command.PlanCommand{
				ContextOpts: &ContextOpts,
				Ui:          Ui,
			}, nil
		},

		"refresh": func() (cli.Command, error) {
			return &command.RefreshCommand{
				ContextOpts: &ContextOpts,
				Ui:          Ui,
			}, nil
		},

		"show": func() (cli.Command, error) {
			return &command.ShowCommand{
				ContextOpts: &ContextOpts,
				Ui:          Ui,
			}, nil
		},

		"version": func() (cli.Command, error) {
			return &command.VersionCommand{
				Revision:          GitCommit,
				Version:           Version,
				VersionPrerelease: VersionPrerelease,
				Ui:                Ui,
			}, nil
		},
	}
}

// makeShutdownCh creates an interrupt listener and returns a channel.
// A message will be sent on the channel for every interrupt received.
func makeShutdownCh() <-chan struct{} {
	resultCh := make(chan struct{})

	signalCh := make(chan os.Signal, 4)
	signal.Notify(signalCh, os.Interrupt)
	go func() {
		for {
			<-signalCh
			resultCh <- struct{}{}
		}
	}()

	return resultCh
}
<commit_msg>Fix compilation, use the new command.Meta object<commit_after>package main

import (
	"os"
	"os/signal"

	"github.com/hashicorp/terraform/command"
	"github.com/mitchellh/cli"
)

// Commands is the mapping of all the available Terraform commands.
var Commands map[string]cli.CommandFactory

// Ui is the cli.Ui used for communicating to the outside world.
var Ui cli.Ui

const ErrorPrefix = "e:"
const OutputPrefix = "o:"

func init() {
	Ui = &cli.PrefixedUi{
		AskPrefix:    OutputPrefix,
		OutputPrefix: OutputPrefix,
		InfoPrefix:   OutputPrefix,
		ErrorPrefix:  ErrorPrefix,
		Ui:           &cli.BasicUi{Writer: os.Stdout},
	}

	meta := command.Meta{
		ContextOpts: &ContextOpts,
		Ui:          Ui,
	}

	Commands = map[string]cli.CommandFactory{
		"apply": func() (cli.Command, error) {
			return &command.ApplyCommand{
				Meta:       meta,
				ShutdownCh: makeShutdownCh(),
			}, nil
		},

		"graph": func() (cli.Command, error) {
			return &command.GraphCommand{
				Meta: meta,
			}, nil
		},

		"plan": func() (cli.Command, error) {
			return &command.PlanCommand{
				Meta: meta,
			}, nil
		},

		"refresh": func() (cli.Command, error) {
			return &command.RefreshCommand{
				Meta: meta,
			}, nil
		},

		"show": func() (cli.Command, error) {
			return &command.ShowCommand{
				Meta: meta,
			}, nil
		},

		"version": func() (cli.Command, error) {
			return &command.VersionCommand{
				Revision:          GitCommit,
				Version:           Version,
				VersionPrerelease: VersionPrerelease,
				Ui:                Ui,
			}, nil
		},
	}
}

// makeShutdownCh creates an interrupt listener and returns a channel.
// A message will be sent on the channel for every interrupt received.
func makeShutdownCh() <-chan struct{} {
	resultCh := make(chan struct{})

	signalCh := make(chan os.Signal, 4)
	signal.Notify(signalCh, os.Interrupt)
	go func() {
		for {
			<-signalCh
			resultCh <- struct{}{}
		}
	}()

	return resultCh
}
<|endoftext|>


<commit_before>package main

import "github.com/codegangsta/cli"

// Commands
var Commands = []cli.Command{
	commandDevices,
	commandPlay,
}

var commandDevices = cli.Command{
	Name:  "devices",
	Usage: "Show AirPlay devices",
	Description: `
`,
	Action: Devices,
}

var commandPlay = cli.Command{
	Name:  "play",
	Usage: "",
	Description: `
`,
	Action: Play,
}
<commit_msg>Add Usage<commit_after>package main

import "github.com/codegangsta/cli"

// Commands
var Commands = []cli.Command{
	commandDevices,
	commandPlay,
}

var commandDevices = cli.Command{
	Name:  "devices",
	Usage: "Show AirPlay devices",
	Description: `
`,
	Action: Devices,
}

var commandPlay = cli.Command{
	Name:  "play",
	Usage: "Play media file",
	Description: `
`,
	Action: Play,
}
<|endoftext|>


<commit_before>package main

import (
	"io"
	"io/ioutil"
	"os"
	"runtime"
	"sync"
)

// FilePipe is a tailable buffer backed by a file.
type FilePipe struct {
	f *os.File

	mu      sync.Mutex
	cond    sync.Cond
	size    int64
	closing bool
}

// Create a new FilePipe backed by a temporary file.
func NewFilePipe() (*FilePipe, error) {
	f, err := ioutil.TempFile("", "filepipe")
	if err != nil {
		return nil, err
	}
	fp := &FilePipe{f: f}
	fp.cond.L = &fp.mu
	runtime.SetFinalizer(fp, (*FilePipe).Release)
	return fp, nil
}

// Release the resources associated with the filepipe. In particular,
// remove the backing file. After this call has been made no readers
// of this filepipe should be used.
func (fp *FilePipe) Release() error {
	fp.Close()
	filename := fp.f.Name()
	err := fp.f.Close()
	if err1 := os.Remove(filename); err == nil {
		err = err1
	}
	return err
}

// Create a new reader that starts reading the filepipe's contents from
// the very beginning.
func (fp *FilePipe) Reader() io.Reader {
	return &filePipeReader{fp: fp, pos: 0}
}

func (fp *FilePipe) Write(buf []byte) (int, error) {
	n, err := fp.f.Write(buf)
	fp.mu.Lock()
	fp.size += int64(n)
	fp.cond.Broadcast()
	fp.mu.Unlock()
	return n, err
}

func (fp *FilePipe) Close() error {
	fp.mu.Lock()
	fp.closing = true
	fp.cond.Broadcast()
	fp.mu.Unlock()
	return nil
}

type filePipeReader struct {
	fp  *FilePipe
	pos int64
}

func (fpr *filePipeReader) Read(buf []byte) (int, error) {
	for {
		n, err := fpr.fp.f.ReadAt(buf, fpr.pos)
		fpr.pos += int64(n)
		if err == io.EOF {
			err = nil
		}
		if err != nil || n > 0 {
			return n, err
		}
		fpr.fp.mu.Lock()
		for fpr.pos >= fpr.fp.size && !fpr.fp.closing {
			fpr.fp.cond.Wait()
		}
		closing := fpr.fp.closing
		fpr.fp.mu.Unlock()
		if closing {
			return 0, io.EOF
		}
	}
}
<commit_msg>fix a premature EOF bug in filepipe<commit_after>package main

import (
	"io"
	"io/ioutil"
	"os"
	"runtime"
	"sync"
)

// FilePipe is a tailable buffer backed by a file.
type FilePipe struct {
	f *os.File

	mu      sync.Mutex
	cond    sync.Cond
	size    int64
	closing bool
}

// Create a new FilePipe backed by a temporary file.
func NewFilePipe() (*FilePipe, error) {
	f, err := ioutil.TempFile("", "filepipe")
	if err != nil {
		return nil, err
	}
	fp := &FilePipe{f: f}
	fp.cond.L = &fp.mu
	runtime.SetFinalizer(fp, (*FilePipe).Release)
	return fp, nil
}

// Release the resources associated with the filepipe. In particular,
// remove the backing file. After this call has been made no readers
// of this filepipe should be used.
func (fp *FilePipe) Release() error {
	fp.Close()
	filename := fp.f.Name()
	err := fp.f.Close()
	if err1 := os.Remove(filename); err == nil {
		err = err1
	}
	return err
}

// Create a new reader that starts reading the filepipe's contents from
// the very beginning.
func (fp *FilePipe) Reader() io.Reader {
	return &filePipeReader{fp: fp, pos: 0}
}

func (fp *FilePipe) Write(buf []byte) (int, error) {
	n, err := fp.f.Write(buf)
	fp.mu.Lock()
	fp.size += int64(n)
	fp.cond.Broadcast()
	fp.mu.Unlock()
	return n, err
}

func (fp *FilePipe) Close() error {
	fp.mu.Lock()
	fp.closing = true
	fp.cond.Broadcast()
	fp.mu.Unlock()
	return nil
}

type filePipeReader struct {
	fp  *FilePipe
	pos int64
}

func (fpr *filePipeReader) Read(buf []byte) (int, error) {
	for {
		n, err := fpr.fp.f.ReadAt(buf, fpr.pos)
		fpr.pos += int64(n)
		if err == io.EOF {
			err = nil
		}
		if err != nil || n > 0 {
			return n, err
		}
		fpr.fp.mu.Lock()
		for fpr.pos >= fpr.fp.size && !fpr.fp.closing {
			fpr.fp.cond.Wait()
		}
		closing := fpr.pos >= fpr.fp.size && fpr.fp.closing // TODO: make a test for the bug that was here
		fpr.fp.mu.Unlock()
		if closing {
			return 0, io.EOF
		}
	}
}
<|endoftext|>


<commit_before>package util

import (
	"github.com/cihub/seelog"
	"log"
	"sync"
)

type mylog struct {
	File string //普通日志
	Log  seelog.LoggerInterface
}

var (
	my_log     *mylog
	mylog_once sync.Once
)

// Mylog  创建mylog单实例
func Mylog(file string) *mylog {
	mylog_once.Do(func() {
		my_log = &mylog{}
		if err := my_log.LoadConfigure(file); err != nil {
			log.Fatalln(err)
		}
	})
	return my_log
}

// LoadConfigure 从file里读取seelog 配置
func (l *mylog) LoadConfigure(file string) error {
	log, err := seelog.LoggerFromConfigAsFile(file)
	if err != nil {
		return err
	}
	l.Log = log

	return nil
}

// Infof 输出info信息
func (l *mylog) Infof(format string, v ...interface{}) {
	l.Log.Infof(format, v)
}

// Debugf 输出debug信息
func (l *mylog) Debugf(format string, v ...interface{}) {
	l.Log.Debugf(format, v)
}

// Warnf 输出warn信息
func (l *mylog) Warnf(format string, v ...interface{}) {
	l.Log.Warnf(format, v)
}

// Errorf 输出error信息
func (l *mylog) Errorf(format string, v ...interface{}) {
	l.Log.Errorf(format, v)
}

// Infof 输出info信息
func (l *mylog) Flush() {
	l.Log.Flush()
}
<commit_msg>add function to util/log.go<commit_after>package util

import (
	"github.com/cihub/seelog"
	"log"
	"sync"
)

type mylog struct {
	File string //普通日志
	Log  seelog.LoggerInterface
}

var (
	my_log     *mylog
	mylog_once sync.Once
)

// Mylog  创建mylog单实例
func Mylog(file string) *mylog {
	mylog_once.Do(func() {
		my_log = &mylog{}
		if err := my_log.LoadConfigure(file); err != nil {
			log.Fatalln(err)
		}
	})
	return my_log
}

// LoadConfigure 从file里读取seelog 配置
func (l *mylog) LoadConfigure(file string) error {
	logger, err := seelog.LoggerFromConfigAsFile(file)
	if err != nil {
		return err
	}
	l.Log = logger

	return nil
}

// Infof 输出info信息
func (l *mylog) Infof(format string, v ...interface{}) {
	l.Log.Infof(format, v)
}

// Debugf 输出debug信息
func (l *mylog) Debugf(format string, v ...interface{}) {
	l.Log.Debugf(format, v)
}

// Warnf 输出warn信息
func (l *mylog) Warnf(format string, v ...interface{}) {
	l.Log.Warnf(format, v)
}

// Errorf 输出error信息
func (l *mylog) Errorf(format string, v ...interface{}) {
	l.Log.Errorf(format, v)
}

func (l *mylog) Info(v ...interface{}){
	l.Log.Info(v)
}

func (l *mylog) Debug(v ...interface{}){
	l.Log.Debug(v)
}

func (l *mylog) Warn(v ...interface{}){
	l.Log.Warn(v)
}

func (l *mylog) Error(v ...interface{}){
	l.Log.Error(v)
}

// Infof 输出info信息
func (l *mylog) Flush() {
	l.Log.Flush()
}
<|endoftext|>


<commit_before>// Copyright © 2016 NAME HERE <EMAIL ADDRESS>
//
// 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 cmd

import (
	"crypto/tls"
	"crypto/x509"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"path/filepath"

	homedir "github.com/mitchellh/go-homedir"
	"github.com/pkg/errors"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

// listCmd represents the list command
var listCmd = &cobra.Command{
	Use:   "list",
	Short: "List all VMs",
	Run: func(cmd *cobra.Command, args []string) {
		// d := virtualbox.NewDriver("", "")
		// outList, err := d.List()
		// if err != nil {
		// 	log.Fatal(err)
		// }
		// fmt.Print(outList)

		host := viper.GetString("server.host")
		port := viper.GetString("server.port")

		home, err := homedir.Dir()
		if err != nil {
			log.Fatal(errors.Wrap(err, "could not detect users home directory"))
		}
		// Create client
		caCert, err := ioutil.ReadFile(filepath.Join(home, ".vmproxy", "cert.pem"))
		if err != nil {
			log.Fatal(err)
		}
		caCertPool := x509.NewCertPool()
		caCertPool.AppendCertsFromPEM(caCert)

		// cert, err := tls.LoadX509KeyPair("client.crt", "client.key")
		// if err != nil {
		// 	log.Fatal(err)
		// }

		client := &http.Client{
			Transport: &http.Transport{
				TLSClientConfig: &tls.Config{
					RootCAs: caCertPool,
					// Certificates: []tls.Certificate{cert},
				},
			},
		}

		// Create request
		req, err := http.NewRequest("GET", "http://"+host+":"+port+"/virtualbox/list", nil)

		// Fetch Request
		resp, err := client.Do(req)
		assert(err)

		// Read Response Body
		respBody, _ := ioutil.ReadAll(resp.Body)

		// Display Results
		fmt.Print(string(respBody))
	},
}

func init() {
	RootCmd.AddCommand(listCmd)

	// Here you will define your flags and configuration settings.

	// Cobra supports Persistent Flags which will work for this command
	// and all subcommands, e.g.:
	// listCmd.PersistentFlags().String("foo", "", "A help for foo")

	// Cobra supports local flags which will only run when this command
	// is called directly, e.g.:
	// listCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")

}
<commit_msg>http to https in client<commit_after>// Copyright © 2016 NAME HERE <EMAIL ADDRESS>
//
// 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 cmd

import (
	"crypto/tls"
	"crypto/x509"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"path/filepath"

	homedir "github.com/mitchellh/go-homedir"
	"github.com/pkg/errors"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

// listCmd represents the list command
var listCmd = &cobra.Command{
	Use:   "list",
	Short: "List all VMs",
	Run: func(cmd *cobra.Command, args []string) {
		// d := virtualbox.NewDriver("", "")
		// outList, err := d.List()
		// if err != nil {
		// 	log.Fatal(err)
		// }
		// fmt.Print(outList)

		host := viper.GetString("server.host")
		port := viper.GetString("server.port")

		home, err := homedir.Dir()
		if err != nil {
			log.Fatal(errors.Wrap(err, "could not detect users home directory"))
		}
		// Create client
		caCert, err := ioutil.ReadFile(filepath.Join(home, ".vmproxy", "cert.pem"))
		if err != nil {
			log.Fatal(err)
		}
		caCertPool := x509.NewCertPool()
		caCertPool.AppendCertsFromPEM(caCert)

		// cert, err := tls.LoadX509KeyPair("client.crt", "client.key")
		// if err != nil {
		// 	log.Fatal(err)
		// }

		client := &http.Client{
			Transport: &http.Transport{
				TLSClientConfig: &tls.Config{
					RootCAs: caCertPool,
					// Certificates: []tls.Certificate{cert},
				},
			},
		}

		// Create request
		req, err := http.NewRequest("GET", "https://"+host+":"+port+"/virtualbox/list", nil)

		// Fetch Request
		resp, err := client.Do(req)
		assert(err)

		// Read Response Body
		respBody, _ := ioutil.ReadAll(resp.Body)

		// Display Results
		fmt.Print(string(respBody))
	},
}

func init() {
	RootCmd.AddCommand(listCmd)

	// Here you will define your flags and configuration settings.

	// Cobra supports Persistent Flags which will work for this command
	// and all subcommands, e.g.:
	// listCmd.PersistentFlags().String("foo", "", "A help for foo")

	// Cobra supports local flags which will only run when this command
	// is called directly, e.g.:
	// listCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")

}
<|endoftext|>


<commit_before>package main

import (
	"crypto/tls"
	"encoding/json"
	"fmt"
	"github.com/codegangsta/cli"
	"golang.org/x/oauth2"
	"io/ioutil"
	"log"
	"net/http"
	"net/http/httputil"
	"os"
	"regexp"
	"strings"
)

var DefaultFlags = []cli.Flag{
	cli.StringFlag{
		Name:  "data",
		Usage: "Body data",
	},
}

var Commands = []cli.Command{
	commandGet,
	commandPost,
	commandPut,
	commandDelete,
	commandHead,
	commandOptions,
	commandPatch,
	commandTrace,
}

var commandGet = cli.Command{
	Name:      "get",
	ShortName: "g",
	Usage:     "Make GET request",
	Description: `
The GET method means retrieve whatever information (in the form of an entity) is identified by the Request-URI.
`,
	Flags:  DefaultFlags,
	Action: doGet,
}

var commandPost = cli.Command{
	Name:      "post",
	ShortName: "p",
	Usage:     "Make POST request",
	Description: `
The POST method is used to request that the origin server accept the entity enclosed in the request
as a new subordinate of the resource identified by the Request-URI in the Request-Line.
`,
	Flags:  DefaultFlags,
	Action: doPost,
}

var commandPut = cli.Command{
	Name:  "put",
	Usage: "Make PUT request",
	Description: `
The PUT method requests that the enclosed entity be stored under the supplied Request-URI.
`,
	Flags:  DefaultFlags,
	Action: doPut,
}

var commandDelete = cli.Command{
	Name:      "delete",
	ShortName: "d",
	Usage:     "Make DELETE request",
	Description: `
The DELETE method requests that the origin server delete the resource identified by the Request-URI.
`,
	Flags:  DefaultFlags,
	Action: doDelete,
}

var commandHead = cli.Command{
	Name:      "head",
	ShortName: "h",
	Usage:     "Make HEAD request",
	Description: `
The HEAD method is identical to GET except that the server MUST NOT return a message-body in the response.
`,
	Flags:  DefaultFlags,
	Action: doHead,
}

var commandOptions = cli.Command{
	Name:      "options",
	ShortName: "o",
	Usage:     "Make OPTIONS request",
	Description: `
The OPTIONS method represents a request for information about the communication options available
on the request/response chain identified by the Request-URI.
`,
	Flags:  DefaultFlags,
	Action: doOptions,
}

var commandPatch = cli.Command{
	Name:  "patch",
	Usage: "Make PATCH request",
	Description: `
The PATCH method requests that a set of changes described in the request entity be applied
to the resource identified by the Request-URI.
`,
	Flags:  DefaultFlags,
	Action: doPatch,
}

var commandTrace = cli.Command{
	Name:      "trace",
	ShortName: "t",
	Usage:     "Make TRACE request",
	Description: `
The TRACE method is used to invoke a remote, application-layer loop-back of the request message.
`,
	Flags:  DefaultFlags,
	Action: doTrace,
}

func assert(err error) {
	if err != nil {
		log.Fatal(err)
	}
}

func doGet(ctx *cli.Context) {
	loadOptions(ctx)
	doRequest(ctx, "GET")
}

func doPost(ctx *cli.Context) {
	loadOptions(ctx)
	doRequest(ctx, "POST")
}

func doPut(ctx *cli.Context) {
	loadOptions(ctx)
	doRequest(ctx, "PUT")
}

func doDelete(ctx *cli.Context) {
	loadOptions(ctx)
	doRequest(ctx, "DELETE")
}

func doHead(ctx *cli.Context) {
	loadOptions(ctx)
	doRequest(ctx, "HEAD")
}

func doOptions(ctx *cli.Context) {
	loadOptions(ctx)
	doRequest(ctx, "OPTIONS")
}

func doPatch(ctx *cli.Context) {
	loadOptions(ctx)
	doRequest(ctx, "PATCH")
}

func doTrace(ctx *cli.Context) {
	loadOptions(ctx)
	doRequest(ctx, "TRACE")
}

func loadOptions(ctx *cli.Context) {
	var err error
	CurrentOptions, err = Opts(ctx)
	if err != nil {
		log.Fatal(err)
		os.Exit(1)
	}
}

func doRequest(ctx *cli.Context, method string) {
	var tr = &http.Transport{
		TLSClientConfig: &tls.Config{
			InsecureSkipVerify: ctx.GlobalBool("insecure"),
		},
	}
	http.DefaultClient = &http.Client{Transport: tr}

	Tracef("doRequest start")
	resp, tok, err := doRequest0(ctx, method)
	if tok != nil && resp != nil && resp.StatusCode != 401 && resp.StatusCode != 403 {
		storeToken(tok)
	}
	if err != nil {
		log.Fatal(err)
		return
	} else {
		Tracef("request done successfully")
	}

	Tracef("printing headers")
	if ctx.GlobalBool("print-headers") {
		headers, _ := json.Marshal(resp.Header)
		fmt.Println(string(headers))
	}

	if ctx.GlobalBool("no-body") {
		Tracef("printing body is disabled")
	} else {
		Tracef("printing body")
		body, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			Tracef("error on read: %v", err)
		} else if body == nil {
			Tracef("no body")
		} else {
			Tracef("body found")
			fmt.Println(string(body))
		}
	}
	Tracef("doRequest end")
}

func stringInSlice(a string, list []string) bool {
	for _, b := range list {
		if b == a {
			return true
		}
	}
	return false
}

func doRequest0(ctx *cli.Context, method string) (*http.Response, *oauth2.Token, error) {
	Tracef("profileName = %s", CurrentOptions.ProfileName)

	targetUrl, err := targetUrl(ctx)
	if err != nil {
		return nil, nil, err
	}
	Tracef("targetUrl = %s", targetUrl)
	data := ctx.String("data")
	Tracef("data = %s", data)
	body := strings.NewReader(data)
	req, err := http.NewRequest(method, targetUrl, body)
	if err != nil {
		return nil, nil, err
	}

	var lastError error
	for retrieve := false; retrieve == false; retrieve = true {
		Tracef("=== phase %s start", toString(retrieve))
		tok, r, err := AccessToken(CurrentOptions.ProfileName, retrieve)
		if err != nil {
			Tracef("phase %s failed (token retrieving failed)", toString(retrieve))
			lastError = err
			continue
		}
		retrieve = r

		req.Header.Set("User-Agent", fmt.Sprintf("%s-%s", ctx.App.Name, Version))
		req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", tok.AccessToken))
		for _, element := range ctx.GlobalStringSlice("header") {
			s := regexp.MustCompile(":").Split(element, 2)
			headerKey := strings.TrimSpace(s[0])
			headerValue := strings.TrimSpace(s[1])
			req.Header.Set(headerKey, headerValue)
			Tracef("custom header [%s: %s]", headerKey, headerValue)
		}
		Tracef("header end")

		dump, err := httputil.DumpRequestOut(req, true)
		if err != nil {
			Tracef("phase %s failed (request dump failed)", toString(retrieve))
			lastError = err
			continue
		}
		Tracef("request = %s", string(dump))

		tr := &http.Transport{
			TLSClientConfig: &tls.Config{
				InsecureSkipVerify: ctx.GlobalBool("insecure"),
			},
		}
		client := &http.Client{
			CheckRedirect: func(req *http.Request, via []*http.Request) error {
				Tracef("redirect to %s", req.URL.String())
				req.Header.Set("User-Agent", fmt.Sprintf("%s-%s", ctx.App.Name, Version))
				req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", tok.AccessToken))
				for _, element := range ctx.StringSlice("header") {
					s := regexp.MustCompile(":").Split(element, 2)
					req.Header.Set(strings.TrimSpace(s[0]), strings.TrimSpace(s[1]))
				}
				return nil
			},
			Transport: tr,
		}
		resp, err := client.Do(req)
		if err != nil {
			Tracef("phase %s failed (request failed)", toString(retrieve))
			lastError = err
			continue
		}

		dumpResp, err := httputil.DumpResponse(resp, true)
		if err != nil {
			log.Printf("%+v%n", err)
		} else {
			Tracef("response = %s", string(dumpResp))
		}

		Tracef("phase %s", toString(retrieve))
		if resp.StatusCode >= 400 && resp.StatusCode < 500 {
			if retrieve {
				Tracef("phase retrieve failed (4XX response)")
				lastError = err
				break
			} else {
				Tracef("phase stored failed (4XX response) -> final result")
			}
		}
		return resp, tok, err
	}
	return nil, nil, fmt.Errorf("%v", lastError)
}

func toString(retrieve bool) string {
	if retrieve {
		return "retrieve"
	}
	return "stored"
}

func targetUrl(ctx *cli.Context) (string, error) {
	if len(ctx.Args()) < 1 {
		return "", fmt.Errorf("target URL required")
	}
	return ctx.Args()[0], nil
}

func storeToken(tok *oauth2.Token) {
	if SaveValues(CurrentOptions.ProfileName, tokenToValues(tok)) {
		Tracef("token stored [%s]", CurrentOptions.ProfileName)
	} else {
		Tracef("fail to store token [%s]", CurrentOptions.ProfileName)
	}
}
<commit_msg>Secure Redirect Authorization header.<commit_after>package main

import (
	"crypto/tls"
	"encoding/json"
	"fmt"
	"github.com/codegangsta/cli"
	"golang.org/x/oauth2"
	"io/ioutil"
	"log"
	"net/http"
	"net/http/httputil"
	"net/url"
	"os"
	"regexp"
	"strings"
)

var DefaultFlags = []cli.Flag{
	cli.StringFlag{
		Name:  "data",
		Usage: "Body data",
	},
}

var Commands = []cli.Command{
	commandGet,
	commandPost,
	commandPut,
	commandDelete,
	commandHead,
	commandOptions,
	commandPatch,
	commandTrace,
}

var commandGet = cli.Command{
	Name:      "get",
	ShortName: "g",
	Usage:     "Make GET request",
	Description: `
The GET method means retrieve whatever information (in the form of an entity) is identified by the Request-URI.
`,
	Flags:  DefaultFlags,
	Action: doGet,
}

var commandPost = cli.Command{
	Name:      "post",
	ShortName: "p",
	Usage:     "Make POST request",
	Description: `
The POST method is used to request that the origin server accept the entity enclosed in the request
as a new subordinate of the resource identified by the Request-URI in the Request-Line.
`,
	Flags:  DefaultFlags,
	Action: doPost,
}

var commandPut = cli.Command{
	Name:  "put",
	Usage: "Make PUT request",
	Description: `
The PUT method requests that the enclosed entity be stored under the supplied Request-URI.
`,
	Flags:  DefaultFlags,
	Action: doPut,
}

var commandDelete = cli.Command{
	Name:      "delete",
	ShortName: "d",
	Usage:     "Make DELETE request",
	Description: `
The DELETE method requests that the origin server delete the resource identified by the Request-URI.
`,
	Flags:  DefaultFlags,
	Action: doDelete,
}

var commandHead = cli.Command{
	Name:      "head",
	ShortName: "h",
	Usage:     "Make HEAD request",
	Description: `
The HEAD method is identical to GET except that the server MUST NOT return a message-body in the response.
`,
	Flags:  DefaultFlags,
	Action: doHead,
}

var commandOptions = cli.Command{
	Name:      "options",
	ShortName: "o",
	Usage:     "Make OPTIONS request",
	Description: `
The OPTIONS method represents a request for information about the communication options available
on the request/response chain identified by the Request-URI.
`,
	Flags:  DefaultFlags,
	Action: doOptions,
}

var commandPatch = cli.Command{
	Name:  "patch",
	Usage: "Make PATCH request",
	Description: `
The PATCH method requests that a set of changes described in the request entity be applied
to the resource identified by the Request-URI.
`,
	Flags:  DefaultFlags,
	Action: doPatch,
}

var commandTrace = cli.Command{
	Name:      "trace",
	ShortName: "t",
	Usage:     "Make TRACE request",
	Description: `
The TRACE method is used to invoke a remote, application-layer loop-back of the request message.
`,
	Flags:  DefaultFlags,
	Action: doTrace,
}

func assert(err error) {
	if err != nil {
		log.Fatal(err)
	}
}

func doGet(ctx *cli.Context) {
	loadOptions(ctx)
	doRequest(ctx, "GET")
}

func doPost(ctx *cli.Context) {
	loadOptions(ctx)
	doRequest(ctx, "POST")
}

func doPut(ctx *cli.Context) {
	loadOptions(ctx)
	doRequest(ctx, "PUT")
}

func doDelete(ctx *cli.Context) {
	loadOptions(ctx)
	doRequest(ctx, "DELETE")
}

func doHead(ctx *cli.Context) {
	loadOptions(ctx)
	doRequest(ctx, "HEAD")
}

func doOptions(ctx *cli.Context) {
	loadOptions(ctx)
	doRequest(ctx, "OPTIONS")
}

func doPatch(ctx *cli.Context) {
	loadOptions(ctx)
	doRequest(ctx, "PATCH")
}

func doTrace(ctx *cli.Context) {
	loadOptions(ctx)
	doRequest(ctx, "TRACE")
}

func loadOptions(ctx *cli.Context) {
	var err error
	CurrentOptions, err = Opts(ctx)
	if err != nil {
		log.Fatal(err)
		os.Exit(1)
	}
}

func doRequest(ctx *cli.Context, method string) {
	var tr = &http.Transport{
		TLSClientConfig: &tls.Config{
			InsecureSkipVerify: ctx.GlobalBool("insecure"),
		},
	}
	http.DefaultClient = &http.Client{Transport: tr}

	Tracef("doRequest start")
	resp, tok, err := doRequest0(ctx, method)
	if tok != nil && resp != nil && resp.StatusCode != 401 && resp.StatusCode != 403 {
		storeToken(tok)
	}
	if err != nil {
		log.Fatal(err)
		return
	} else {
		Tracef("request done successfully")
	}

	Tracef("printing headers")
	if ctx.GlobalBool("print-headers") {
		headers, _ := json.Marshal(resp.Header)
		fmt.Println(string(headers))
	}

	if ctx.GlobalBool("no-body") {
		Tracef("printing body is disabled")
	} else {
		Tracef("printing body")
		body, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			Tracef("error on read: %v", err)
		} else if body == nil {
			Tracef("no body")
		} else {
			Tracef("body found")
			fmt.Println(string(body))
		}
	}
	Tracef("doRequest end")
}

func stringInSlice(a string, list []string) bool {
	for _, b := range list {
		if b == a {
			return true
		}
	}
	return false
}

func doRequest0(ctx *cli.Context, method string) (*http.Response, *oauth2.Token, error) {
	Tracef("profileName = %s", CurrentOptions.ProfileName)

	targetUrl, err := targetUrl(ctx)
	if err != nil {
		return nil, nil, err
	}
	Tracef("targetUrl = %s", targetUrl)
	data := ctx.String("data")
	Tracef("data = %s", data)
	body := strings.NewReader(data)
	req, err := http.NewRequest(method, targetUrl, body)
	if err != nil {
		return nil, nil, err
	}

	var lastError error
	for retrieve := false; retrieve == false; retrieve = true {
		Tracef("=== phase %s start", toString(retrieve))
		tok, r, err := AccessToken(CurrentOptions.ProfileName, retrieve)
		if err != nil {
			Tracef("phase %s failed (token retrieving failed)", toString(retrieve))
			lastError = err
			continue
		}
		retrieve = r

		req.Header.Set("User-Agent", fmt.Sprintf("%s-%s", ctx.App.Name, Version))
		req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", tok.AccessToken))
		for _, element := range ctx.GlobalStringSlice("header") {
			s := regexp.MustCompile(":").Split(element, 2)
			headerKey := strings.TrimSpace(s[0])
			headerValue := strings.TrimSpace(s[1])
			req.Header.Set(headerKey, headerValue)
			Tracef("custom header [%s: %s]", headerKey, headerValue)
		}
		Tracef("header end")

		dump, err := httputil.DumpRequestOut(req, true)
		if err != nil {
			Tracef("phase %s failed (request dump failed)", toString(retrieve))
			lastError = err
			continue
		}
		Tracef("request = %s", string(dump))

		tr := &http.Transport{
			TLSClientConfig: &tls.Config{
				InsecureSkipVerify: ctx.GlobalBool("insecure"),
			},
		}
		client := &http.Client{
			CheckRedirect: func(redirectRequest *http.Request, via []*http.Request) error {
				Tracef("redirect to %s", redirectRequest.URL.String())
				Tracef("original request Host = %s", req.URL.String())
				if matchServer(redirectRequest.URL, req.URL) {
					redirectRequest.Header.Set("Authorization", fmt.Sprintf("Bearer %s", tok.AccessToken))
				}
				redirectRequest.Header.Set("User-Agent", fmt.Sprintf("%s-%s", ctx.App.Name, Version))
				for _, element := range ctx.StringSlice("header") {
					s := regexp.MustCompile(":").Split(element, 2)
					redirectRequest.Header.Set(strings.TrimSpace(s[0]), strings.TrimSpace(s[1]))
				}
				return nil
			},
			Transport: tr,
		}
		resp, err := client.Do(req)
		if err != nil {
			Tracef("phase %s failed (request failed)", toString(retrieve))
			lastError = err
			continue
		}

		dumpResp, err := httputil.DumpResponse(resp, true)
		if err != nil {
			log.Printf("%+v%n", err)
		} else {
			Tracef("response = %s", string(dumpResp))
		}

		Tracef("phase %s", toString(retrieve))
		if resp.StatusCode >= 400 && resp.StatusCode < 500 {
			if retrieve {
				Tracef("phase retrieve failed (4XX response)")
				lastError = err
				break
			} else {
				Tracef("phase stored failed (4XX response) -> final result")
			}
		}
		return resp, tok, err
	}
	return nil, nil, fmt.Errorf("%v", lastError)
}

func matchServer(a *url.URL, b *url.URL) bool {
	if a.Scheme != b.Scheme {
		return false
	}
	if a.Host != b.Host {
		return false
	}
	return true
}

func toString(retrieve bool) string {
	if retrieve {
		return "retrieve"
	}
	return "stored"
}

func targetUrl(ctx *cli.Context) (string, error) {
	if len(ctx.Args()) < 1 {
		return "", fmt.Errorf("target URL required")
	}
	return ctx.Args()[0], nil
}

func storeToken(tok *oauth2.Token) {
	if SaveValues(CurrentOptions.ProfileName, tokenToValues(tok)) {
		Tracef("token stored [%s]", CurrentOptions.ProfileName)
	} else {
		Tracef("fail to store token [%s]", CurrentOptions.ProfileName)
	}
}
<|endoftext|>


<commit_before>package util

import (
    "fmt"
    "os"
    "path/filepath"
    "strconv"
    "strings"
)

func GenPidFilePath(sname string) string {
    wd, err := os.Getwd()
    if err != nil {
        return ""
    }
    return filepath.Join(wd, "pid", fmt.Sprintf("run.%v.pid", sname))
}

func PidFromFile(filepath string) (error, int) {
    if _, err := os.Stat(filepath); os.IsNotExist(err) {
        return nil, 0
    }
    f, err := os.Open(filepath)
    if err != nil {
        return err, 0
    }
    defer f.Close()
    buf := make([]byte, 64)
    n, err := f.Read(buf)
    if err != nil {
        return err, 0
    }
    str := string(buf[:n])
    str = strings.TrimSpace(str)
    pid, err := strconv.Atoi(str)
    if err != nil {
        return err, 0
    }
    return nil, pid
}

func WritePidToFile(filepath string, pid int) error {
    f, err := os.OpenFile(filepath, os.O_RDWR|os.O_CREATE, os.ModePerm)
    if err != nil {
        return err
    }
    defer f.Close()

    f.WriteString(fmt.Sprintf("%v", pid))

    return nil
}

func DeletePidFile(filepath string) error {
    return os.Remove(filepath)
}
<commit_msg>create pid file parent dir if not exist<commit_after>package util

import (
    "fmt"
    "os"
    "path/filepath"
    "strconv"
    "strings"
)

func GenPidFilePath(sname string) string {
    wd, err := os.Getwd()
    if err != nil {
        return ""
    }
    os.MkdirAll(filepath.Join(wd, "pid"), 0700)
    return filepath.Join(wd, "pid", fmt.Sprintf("run.%v.pid", sname))
}

func PidFromFile(filepath string) (error, int) {
    if _, err := os.Stat(filepath); os.IsNotExist(err) {
        return nil, 0
    }
    f, err := os.Open(filepath)
    if err != nil {
        return err, 0
    }
    defer f.Close()
    buf := make([]byte, 64)
    n, err := f.Read(buf)
    if err != nil {
        return err, 0
    }
    str := string(buf[:n])
    str = strings.TrimSpace(str)
    pid, err := strconv.Atoi(str)
    if err != nil {
        return err, 0
    }
    return nil, pid
}

func WritePidToFile(filepath string, pid int) error {
    f, err := os.OpenFile(filepath, os.O_RDWR|os.O_CREATE, os.ModePerm)
    if err != nil {
        return err
    }
    defer f.Close()

    f.WriteString(fmt.Sprintf("%v", pid))

    return nil
}

func DeletePidFile(filepath string) error {
    return os.Remove(filepath)
}
<|endoftext|>


<commit_before>/* 	commands.go
_________________________________
Parses commands and executes them for Kylixor Discord Bot
Andrew Langhill
kylixor.com
*/

package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"time"

	"github.com/bwmarrin/discordgo"
	"github.com/jasonlvhit/gocron"
)

func runCommand(s *discordgo.Session, m *discordgo.MessageCreate, command string, data string) {

	switch command {

	//----- A C C O U N T -----
	//Get amount of coins in players account
	case "account":
		user, _ := jcc.GetUserData(s, m)
		s.ChannelMessageSend(m.ChannelID, fmt.Sprintf("💵 | You have a total of **%d** %scoins", user.Credits, config.Coins))
		break

	//----- C O N F I G -----
	//Modify or reload config
	case "config":
		if m.Author.ID == config.Admin {
			switch data {
			case "reload":
				jcc.UpdateUserFile()
				break

			default:
				s.ChannelMessageSend(m.ChannelID, fmt.Sprintf("```\nPossible Commands:\n1. reload"))

			}
		} else {
			ErrorPrint(s, m.ChannelID, "NOPERM")
		}

	//----- D A I L I E S -----
	//Gets daily Coins
	case "dailies":
		//Retrieve user data from memory
		_, index := jcc.GetUserData(s, m)
		userData := &jcc.Users[index]
		//If the dailies have not been done
		if !userData.Dailies {
			//Mark dailies as done and add the appropriate amount
			userData.Dailies = true
			userData.Credits += 100
			//Indicate to user they have recived their dailies
			s.ChannelMessageSend(m.ChannelID, fmt.Sprintf(
				"💵 | Dailies received! Total %scoins: **%d**", config.Coins, userData.Credits))
			//Write data back out to the file
			jcc.WriteUserFile()
		} else {
			_, nextRuntime := gocron.NextRun()
			timeUntil := time.Until(nextRuntime)
			hour := timeUntil / time.Hour
			timeUntil -= hour * time.Hour
			min := timeUntil / time.Minute
			timeUntil -= min * time.Minute
			sec := timeUntil / time.Second

			hourStr := "s"
			minStr := "s"
			secStr := "s"
			if hour == 1 {
				hourStr = ""
			}
			if min == 1 {
				minStr = ""
			}
			if sec == 1 {
				secStr = ""
			}
			s.ChannelMessageSend(m.ChannelID, fmt.Sprintf(
				"💵 | You have already collected today's dailies.\nDailies reset in %d hour%s, %d minute%s and %d second%s.",
				hour, hourStr, min, minStr, sec, secStr))
		}
		break

	//----- D A R L I N G -----
	//Posts best girl gif
	case "darling":
		embedMsg := &discordgo.MessageEmbed{Description: "Zehro Twu", Color: 0xfa00ff,
			Image: &discordgo.MessageEmbedImage{URL: "https://cdn.discordapp.com/emojis/496406418962776065.gif"}}
		s.ChannelMessageSendEmbed(m.ChannelID, embedMsg)
		break

	//----- H E L P -----
	//Display the readme file
	case "help":
		readme, err := ioutil.ReadFile("README.md")
		if err != nil {
			s.ChannelMessageSend(m.ChannelID, "Error openning README, contact bot admin for assistance")
		}

		//Print readme within a code blog to make the formatting work output
		s.ChannelMessageSend(m.ChannelID, fmt.Sprintf("```"+string(readme)+"```"))
		break

	//----- I P -----
	//Displayed the external IP of the bot
	case "ip":
		if m.Author.ID == config.Admin {
			resp, err := http.Get("http://myexternalip.com/raw")
			if err != nil {
				panic(err)
			}
			defer resp.Body.Close()
			responseData, _ := ioutil.ReadAll(resp.Body)
			s.ChannelMessageSend(m.ChannelID, fmt.Sprintf("Bot's current external IP: %s", string(responseData)))
		}
		break

	//----- V E R S I O N -----
	//Gets the current version from the readme file and prints it
	case "version":
		ver := GetVersion(s)
		s.ChannelMessageSend(m.ChannelID, ver)
		break

	default:
		s.ChannelMessageSend(m.ChannelID, fmt.Sprintf("Unknown command \"%s\"", command))
	}

}
<commit_msg>Create ping command<commit_after>/* 	commands.go
_________________________________
Parses commands and executes them for Kylixor Discord Bot
Andrew Langhill
kylixor.com
*/

package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"time"

	"github.com/bwmarrin/discordgo"
	"github.com/jasonlvhit/gocron"
)

func runCommand(s *discordgo.Session, m *discordgo.MessageCreate, command string, data string) {

	switch command {

	//----- A C C O U N T -----
	//Get amount of coins in players account
	case "account":
		user, _ := jcc.GetUserData(s, m)
		s.ChannelMessageSend(m.ChannelID, fmt.Sprintf("💵 | You have a total of **%d** %scoins", user.Credits, config.Coins))
		break

	//----- C O N F I G -----
	//Modify or reload config
	case "config":
		if m.Author.ID == config.Admin {
			switch data {
			case "reload":
				jcc.UpdateUserFile()
				break

			default:
				s.ChannelMessageSend(m.ChannelID, fmt.Sprintf("```\nPossible Commands:\n1. reload\n```"))

			}
		} else {
			ErrorPrint(s, m.ChannelID, "NOPERM")
		}

	//----- D A I L I E S -----
	//Gets daily Coins
	case "dailies":
		//Retrieve user data from memory
		_, index := jcc.GetUserData(s, m)
		userData := &jcc.Users[index]
		//If the dailies have not been done
		if !userData.Dailies {
			//Mark dailies as done and add the appropriate amount
			userData.Dailies = true
			userData.Credits += 100
			//Indicate to user they have recived their dailies
			s.ChannelMessageSend(m.ChannelID, fmt.Sprintf(
				"💵 | Dailies received! Total %scoins: **%d**", config.Coins, userData.Credits))
			//Write data back out to the file
			jcc.WriteUserFile()
		} else {
			_, nextRuntime := gocron.NextRun()
			timeUntil := time.Until(nextRuntime)
			hour := timeUntil / time.Hour
			timeUntil -= hour * time.Hour
			min := timeUntil / time.Minute
			timeUntil -= min * time.Minute
			sec := timeUntil / time.Second

			hourStr := "s"
			minStr := "s"
			secStr := "s"
			if hour == 1 {
				hourStr = ""
			}
			if min == 1 {
				minStr = ""
			}
			if sec == 1 {
				secStr = ""
			}
			s.ChannelMessageSend(m.ChannelID, fmt.Sprintf(
				"💵 | You have already collected today's dailies.\nDailies reset in %d hour%s, %d minute%s and %d second%s.",
				hour, hourStr, min, minStr, sec, secStr))
		}
		break

	//----- D A R L I N G -----
	//Posts best girl gif
	case "darling":
		embedMsg := &discordgo.MessageEmbed{Description: "Zehro Twu", Color: 0xfa00ff,
			Image: &discordgo.MessageEmbedImage{URL: "https://cdn.discordapp.com/emojis/496406418962776065.gif"}}
		s.ChannelMessageSendEmbed(m.ChannelID, embedMsg)
		break

	//----- H E L P -----
	//Display the readme file
	case "help":
		readme, err := ioutil.ReadFile("README.md")
		if err != nil {
			s.ChannelMessageSend(m.ChannelID, "Error openning README, contact bot admin for assistance")
		}

		//Print readme within a code blog to make the formatting work output
		s.ChannelMessageSend(m.ChannelID, fmt.Sprintf("```"+string(readme)+"```"))
		break

	//----- I P -----
	//Displayed the external IP of the bot
	case "ip":
		if m.Author.ID == config.Admin {
			resp, err := http.Get("http://myexternalip.com/raw")
			if err != nil {
				panic(err)
			}
			defer resp.Body.Close()
			responseData, _ := ioutil.ReadAll(resp.Body)
			s.ChannelMessageSend(m.ChannelID, fmt.Sprintf("Bot's current external IP: %s", string(responseData)))
		}
		break

	//----- K A R M A -----
	//Displays the current amount of karma the bot has
	case "karma":
		s.ChannelMessageSend(m.ChannelID, fmt.Sprintf("☯ | Current Karma: %d", jcc.Karma))
		break

	//----- P I N G -----
	//Replies immediately with 'pong' then calculates the difference of the timestamps to get the ping
	case "ping":
		pongMessage, _ := s.ChannelMessageSend(m.ChannelID, "Pong!")
		pingTime, _ := m.Timestamp.Parse()
		pongTime, _ := pongMessage.Timestamp.Parse()
		s.ChannelMessageEdit(m.ChannelID, pongMessage.ID, fmt.Sprintf("Pong! %vms", pongTime.Sub(pingTime)))
		break

	//----- V E R S I O N -----
	//Gets the current version from the readme file and prints it
	case "version":
		ver := GetVersion(s)
		s.ChannelMessageSend(m.ChannelID, ver)
		break

	default:
		s.ChannelMessageSend(m.ChannelID, fmt.Sprintf("Unknown command \"%s\"", command))
	}

}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"io"
	"log"
	"net"
	"regexp"
	"sort"
	"strings"
	"time"
)

type Server struct {
	eventChan  chan Event
	running    bool
	name       string
	clientMap  map[string]*Client  //Map of nicks → clients
	channelMap map[string]*Channel //Map of channel names → channels
}

type Client struct {
	server     *Server
	connection net.Conn
	signalChan chan int
	outputChan chan string
	nick       string
	registered bool
	channelMap map[string]*Channel
}

type Channel struct {
	name      string
	topic     string
	clientMap map[string]*Client
}

type Event struct {
	client *Client
	input  string
}

const (
	signalStop int = iota
)

const (
	rplWelcome int = iota
	rplJoin
	rplPart
	rplTopic
	rplNoTopic
	rplNames
	rplNickChange
	errMoreArgs
	errNoNick
	errInvalidNick
	errNickInUse
	errAlreadyReg
	errNoSuchNick
	errUnknownCommand
	errNotReg
)

var (
	nickRegexp    = regexp.MustCompile(`^[a-zA-Z\[\]_^{|}][a-zA-Z0-9\[\]_^{|}]*$`)
	channelRegexp = regexp.MustCompile(`^#[a-z0-9_\-]+$`)
)

func NewServer() *Server {
	return &Server{eventChan: make(chan Event),
		name:       "rosella",
		clientMap:  make(map[string]*Client),
		channelMap: make(map[string]*Channel)}
}

func (s *Server) Run() {
	go func() {
		for {
			s.handleEvent(<-s.eventChan)
		}
	}()
}

func (s *Server) HandleConnection(conn net.Conn) {

	client := &Client{server: s,
		connection: conn,
		outputChan: make(chan string),
		signalChan: make(chan int),
		channelMap: make(map[string]*Channel)}

	go client.clientThread()
}

func (s *Server) handleEvent(e Event) {
	fields := strings.Fields(e.input)

	if len(fields) < 1 {
		return
	}

	if strings.HasPrefix(fields[0], ":") {
		fields = fields[1:]
	}

	command := strings.ToUpper(fields[0])
	args := fields[1:]

	switch {
	case command == "NICK":
		if len(args) < 1 {
			e.client.reply(errNoNick)
			return
		}

		newNick := args[0]

		//Check newNick is of valid formatting (regex)
		if nickRegexp.MatchString(newNick) == false {
			e.client.reply(errInvalidNick, newNick)
			return
		}

		if _, exists := s.clientMap[newNick]; exists {
			e.client.reply(errNickInUse, newNick)
			return
		}

		//Protect the server name from being used
		if newNick == s.name {
			e.client.reply(errNickInUse, newNick)
			return
		}

		e.client.setNick(newNick)

	case command == "USER":
		//This command is completely disused, we use nick to register

	case command == "JOIN":
		if e.client.registered == false {
			e.client.reply(errNotReg)
			return
		}

		if len(args) < 1 {
			e.client.reply(errMoreArgs)
			return
		}

		if args[0] == "0" {
			//Quit all channels
			for channel := range e.client.channelMap {
				s.partChannel(e.client, channel)
			}
			return
		}

		channels := strings.Split(args[0], ",")
		for _, channel := range channels {
			//Join the channel if it's valid
			if channelRegexp.Match([]byte(channel)) {
				s.joinChannel(e.client, channel)
			}
		}

	case command == "PART":
		if e.client.registered == false {
			e.client.reply(errNotReg)
			return
		}

		if len(args) < 1 {
			e.client.reply(errMoreArgs)
			return
		}

		channels := strings.Split(args[0], ",")
		for _, channel := range channels {
			//Part the channel if it's valid
			if channelRegexp.Match([]byte(channel)) {
				s.partChannel(e.client, channel)
			}
		}

	case command == "PRIVMSG":
		if e.client.registered == false {
			e.client.reply(errNotReg)
			return
		}

		if len(args) < 2 {
			e.client.reply(errMoreArgs)
			return
		}

		message := strings.Join(args[1:], " ")

		channel, chanExists := s.channelMap[args[0]]
		client, clientExists := s.clientMap[args[0]]

		if chanExists {
			for _, c := range channel.clientMap {
				if c != e.client {
					c.outputChan <- fmt.Sprintf(":%s PRIVMSG %s %s", e.client.nick, args[0], message)
				}
			}
		} else if clientExists {
			client.outputChan <- fmt.Sprintf(":%s PRIVMSG %s %s", e.client.nick, client.nick, message)
		} else {
			e.client.reply(errNoSuchNick, args[0])
		}

	case command == "QUIT":
		if e.client.registered == false {
			e.client.reply(errNotReg)
			return
		}

		//Stop the client, which will auto part channels and quit
		e.client.signalChan <- signalStop
	case command == "TOPIC":
		if e.client.registered == false {
			e.client.reply(errNotReg)
			return
		}

		if len(args) < 1 {
			e.client.reply(errMoreArgs)
			return
		}

		channel, exists := s.channelMap[args[0]]
		if exists == false {
			e.client.reply(errNoSuchNick, args[0])
			return
		}

		channelName := args[0]

		if len(args) == 1 {
			e.client.reply(rplTopic, channelName, channel.topic)
			return
		}

		if args[1] == ":" {
			channel.topic = ""
			for _, client := range channel.clientMap {
				client.reply(rplNoTopic, channelName)
			}
		} else {
			topic := strings.Join(args[1:], " ")
			topic = strings.TrimPrefix(topic, ":")
			channel.topic = topic

			for _, client := range channel.clientMap {
				client.reply(rplTopic, channelName, channel.topic)
			}
		}

	default:
		e.client.reply(errUnknownCommand, command)
	}
}

func (s *Server) joinChannel(client *Client, channelName string) {
	channel, exists := s.channelMap[channelName]
	if exists == false {
		channel = &Channel{name: channelName,
			topic:     "",
			clientMap: make(map[string]*Client)}
		s.channelMap[channelName] = channel
	}

	channel.clientMap[client.nick] = client
	client.channelMap[channelName] = channel

	for _, c := range channel.clientMap {
		c.reply(rplJoin, client.nick, channelName)
	}

	if channel.topic != "" {
		client.reply(rplTopic, channelName, channel.topic)
	} else {
		client.reply(rplNoTopic, channelName)
	}

	nicks := make([]string, 0, 100)
	for nick := range channel.clientMap {
		nicks = append(nicks, nick)
	}

	client.reply(rplNames, channelName, strings.Join(nicks, " "))
}

func (s *Server) partChannel(client *Client, channelName string) {
	channel, exists := s.channelMap[channelName]
	if exists == false {
		return
	}

	//Notify clients of the part
	for _, c := range channel.clientMap {
		c.reply(rplPart, client.nick, channelName)
	}

	delete(channel.clientMap, client.nick)
	delete(client.channelMap, channelName)
}

func (c *Client) clientThread() {
	defer c.connection.Close()

	readSignalChan := make(chan int, 1)
	writeSignalChan := make(chan int, 1)
	writeChan := make(chan string, 100)

	go c.readThread(readSignalChan)
	go c.writeThread(writeSignalChan, writeChan)

	for {
		select {
		case signal := <-c.signalChan:
			//Do stuff
			if signal == signalStop {
				readSignalChan <- signalStop
				writeSignalChan <- signalStop
				break
			}
		case line := <-c.outputChan:
			select {
			case writeChan <- line:
				//It worked
			default:
				log.Printf("Dropped a line for client: %q", c.nick)
				//Do nothing, dropping the line
			}
		}
	}

	//Part from all channels
	for channelName := range c.channelMap {
		c.server.partChannel(c, channelName)
	}

	//Remove from client list
	delete(c.server.clientMap, c.nick)
}

func (c *Client) readThread(signalChan chan int) {
	for {
		select {
		case signal := <-signalChan:
			if signal == signalStop {
				return
			}
		default:
			c.connection.SetReadDeadline(time.Now().Add(time.Second * 3))
			buf := make([]byte, 512)
			ln, err := c.connection.Read(buf)
			if err != nil {
				if err == io.EOF {
					//They must have dc'd
					c.signalChan <- signalStop
					return
				}
				continue
			}

			rawLines := buf[:ln]
			lines := bytes.Split(rawLines, []byte("\r\n"))
			for _, line := range lines {
				if len(line) > 0 {
					c.server.eventChan <- Event{client: c, input: string(line)}
				}
			}
		}
	}
}

func (c *Client) writeThread(signalChan chan int, outputChan chan string) {
	for {
		select {
		case signal := <-signalChan:
			if signal == signalStop {
				return
			}
		case output := <-outputChan:
			line := []byte(fmt.Sprintf("%s\r\n", output))

			c.connection.SetWriteDeadline(time.Now().Add(time.Second * 30))
			_, err := c.connection.Write(line)
			if err != nil {
				log.Printf("Write err: %q", err.Error())
				c.signalChan <- signalStop
				return
			}
		}
	}
}

//Send a reply to a user with the code specified
func (c *Client) reply(code int, args ...string) {
	switch code {
	case rplWelcome:
		c.outputChan <- fmt.Sprintf(":%s 001 %s :Welcome to %s", c.server.name, c.nick, c.server.name)
	case rplJoin:
		c.outputChan <- fmt.Sprintf(":%s JOIN %s", args[0], args[1])
	case rplPart:
		c.outputChan <- fmt.Sprintf(":%s PART %s", args[0], args[1])
	case rplTopic:
		c.outputChan <- fmt.Sprintf(":%s 332 %s %s :%s", c.server.name, c.nick, args[0], args[1])
	case rplNoTopic:
		c.outputChan <- fmt.Sprintf(":%s 331 %s %s :No topic is set", c.server.name, c.nick, args[0])
	case rplNames:
		//TODO: break long lists up into multiple messages
		c.outputChan <- fmt.Sprintf(":%s 353 %s = %s :%s", c.server.name, c.nick, args[0], args[1])
		c.outputChan <- fmt.Sprintf(":%s 366 %s", c.server.name, c.nick)
	case rplNickChange:
		c.outputChan <- fmt.Sprintf(":%s NICK %s", args[0], args[1])
	case errMoreArgs:
		c.outputChan <- fmt.Sprintf(":%s 461 %s %s :Not enough params", c.server.name, c.nick, args[0])
	case errNoNick:
		c.outputChan <- fmt.Sprintf(":%s 431 %s :No nickname given", c.server.name, c.nick)
	case errInvalidNick:
		c.outputChan <- fmt.Sprintf(":%s 432 %s %s :Erronenous nickname", c.server.name, c.nick, args[0])
	case errNickInUse:
		c.outputChan <- fmt.Sprintf(":%s 433 %s %s :Nick already in use", c.server.name, c.nick, args[0])
	case errAlreadyReg:
		c.outputChan <- fmt.Sprintf(":%s 462 :You need a valid nick first", c.server.name)
	case errNoSuchNick:
		c.outputChan <- fmt.Sprintf(":%s 401 %s %s :No such nick/channel", c.server.name, c.nick, args[0])
	case errUnknownCommand:
		c.outputChan <- fmt.Sprintf(":%s 421 %s %s :Unknown command", c.server.name, c.nick, args[0])
	case errNotReg:
		c.outputChan <- fmt.Sprintf(":%s 451 :You have not registered", c.server.name)
	}
}

func (c *Client) setNick(nick string) {
	if c.nick != "" {
		delete(c.server.clientMap, c.nick)
		for _, channel := range c.channelMap {
			delete(channel.clientMap, c.nick)
		}
	}

	//Set up new nick
	oldNick := c.nick
	c.nick = nick
	c.server.clientMap[c.nick] = c

	if oldNick == "" {
		//Oldnick is ""
		c.registered = true
		c.reply(rplWelcome)
	} else {
		clients := make([]string, 0, 100)

		for _, channel := range c.channelMap {
			channel.clientMap[c.nick] = c

			//Collect list of client nicks who can see us
			for client := range channel.clientMap {
				clients = append(clients, client)
			}
		}

		//By sorting the nicks and skipping duplicates we send each client one message
		sort.Strings(clients)
		prevNick := ""
		for _, nick := range clients {
			if nick == prevNick {
				continue
			}
			prevNick = nick

			client, exists := c.server.clientMap[nick]
			if exists {
				client.reply(rplNickChange, oldNick, c.nick)
			}
		}
	}
}
<commit_msg>Fixed duplicate nickname issues and /quit bug<commit_after>package main

import (
	"bytes"
	"fmt"
	"io"
	"log"
	"net"
	"regexp"
	"sort"
	"strings"
	"time"
)

type Server struct {
	eventChan  chan Event
	running    bool
	name       string
	clientMap  map[string]*Client  //Map of nicks → clients
	channelMap map[string]*Channel //Map of channel names → channels
}

type Client struct {
	server     *Server
	connection net.Conn
	signalChan chan int
	outputChan chan string
	nick       string
	registered bool
	connected  bool
	channelMap map[string]*Channel
}

type Channel struct {
	name      string
	topic     string
	clientMap map[string]*Client
}

type Event struct {
	client *Client
	input  string
}

const (
	signalStop int = iota
)

const (
	rplWelcome int = iota
	rplJoin
	rplPart
	rplTopic
	rplNoTopic
	rplNames
	rplNickChange
	rplKill
	errMoreArgs
	errNoNick
	errInvalidNick
	errNickInUse
	errAlreadyReg
	errNoSuchNick
	errUnknownCommand
	errNotReg
)

var (
	nickRegexp    = regexp.MustCompile(`^[a-zA-Z\[\]_^{|}][a-zA-Z0-9\[\]_^{|}]*$`)
	channelRegexp = regexp.MustCompile(`^#[a-z0-9_\-]+$`)
)

func NewServer() *Server {
	return &Server{eventChan: make(chan Event),
		name:       "rosella",
		clientMap:  make(map[string]*Client),
		channelMap: make(map[string]*Channel)}
}

func (s *Server) Run() {
	go func() {
		for {
			s.handleEvent(<-s.eventChan)
		}
	}()
}

func (s *Server) HandleConnection(conn net.Conn) {

	client := &Client{server: s,
		connection: conn,
		outputChan: make(chan string),
		signalChan: make(chan int, 3),
		channelMap: make(map[string]*Channel),
		connected:  true}

	go client.clientThread()
}

func (s *Server) handleEvent(e Event) {
	fields := strings.Fields(e.input)

	if len(fields) < 1 {
		return
	}

	if strings.HasPrefix(fields[0], ":") {
		fields = fields[1:]
	}

	command := strings.ToUpper(fields[0])
	args := fields[1:]

	switch {
	case command == "NICK":
		if len(args) < 1 {
			e.client.reply(errNoNick)
			return
		}

		newNick := args[0]

		//Check newNick is of valid formatting (regex)
		if nickRegexp.MatchString(newNick) == false {
			e.client.reply(errInvalidNick, newNick)
			return
		}

		if _, exists := s.clientMap[newNick]; exists {
			e.client.reply(errNickInUse, newNick)
			return
		}

		//Protect the server name from being used
		if newNick == s.name {
			e.client.reply(errNickInUse, newNick)
			return
		}

		e.client.setNick(newNick)

	case command == "USER":
		if e.client.nick == "" {
			e.client.reply(rplKill, "Your nickname is already being used")
			e.client.disconnect()
		} else {
			e.client.reply(rplWelcome)
			e.client.registered = true
		}

	case command == "JOIN":
		if e.client.registered == false {
			e.client.reply(errNotReg)
			return
		}

		if len(args) < 1 {
			e.client.reply(errMoreArgs)
			return
		}

		if args[0] == "0" {
			//Quit all channels
			for channel := range e.client.channelMap {
				s.partChannel(e.client, channel)
			}
			return
		}

		channels := strings.Split(args[0], ",")
		for _, channel := range channels {
			//Join the channel if it's valid
			if channelRegexp.Match([]byte(channel)) {
				s.joinChannel(e.client, channel)
			}
		}

	case command == "PART":
		if e.client.registered == false {
			e.client.reply(errNotReg)
			return
		}

		if len(args) < 1 {
			e.client.reply(errMoreArgs)
			return
		}

		channels := strings.Split(args[0], ",")
		for _, channel := range channels {
			//Part the channel if it's valid
			if channelRegexp.Match([]byte(channel)) {
				s.partChannel(e.client, channel)
			}
		}

	case command == "PRIVMSG":
		if e.client.registered == false {
			e.client.reply(errNotReg)
			return
		}

		if len(args) < 2 {
			e.client.reply(errMoreArgs)
			return
		}

		message := strings.Join(args[1:], " ")

		channel, chanExists := s.channelMap[args[0]]
		client, clientExists := s.clientMap[args[0]]

		if chanExists {
			for _, c := range channel.clientMap {
				if c != e.client {
					c.outputChan <- fmt.Sprintf(":%s PRIVMSG %s %s", e.client.nick, args[0], message)
				}
			}
		} else if clientExists {
			client.outputChan <- fmt.Sprintf(":%s PRIVMSG %s %s", e.client.nick, client.nick, message)
		} else {
			e.client.reply(errNoSuchNick, args[0])
		}

	case command == "QUIT":
		if e.client.registered == false {
			e.client.reply(errNotReg)
			return
		}

		//Stop the client, which will auto part channels and quit
		e.client.disconnect()

	case command == "TOPIC":
		if e.client.registered == false {
			e.client.reply(errNotReg)
			return
		}

		if len(args) < 1 {
			e.client.reply(errMoreArgs)
			return
		}

		channel, exists := s.channelMap[args[0]]
		if exists == false {
			e.client.reply(errNoSuchNick, args[0])
			return
		}

		channelName := args[0]

		if len(args) == 1 {
			e.client.reply(rplTopic, channelName, channel.topic)
			return
		}

		if args[1] == ":" {
			channel.topic = ""
			for _, client := range channel.clientMap {
				client.reply(rplNoTopic, channelName)
			}
		} else {
			topic := strings.Join(args[1:], " ")
			topic = strings.TrimPrefix(topic, ":")
			channel.topic = topic

			for _, client := range channel.clientMap {
				client.reply(rplTopic, channelName, channel.topic)
			}
		}

	default:
		e.client.reply(errUnknownCommand, command)
	}
}

func (s *Server) joinChannel(client *Client, channelName string) {
	channel, exists := s.channelMap[channelName]
	if exists == false {
		channel = &Channel{name: channelName,
			topic:     "",
			clientMap: make(map[string]*Client)}
		s.channelMap[channelName] = channel
	}

	channel.clientMap[client.nick] = client
	client.channelMap[channelName] = channel

	for _, c := range channel.clientMap {
		c.reply(rplJoin, client.nick, channelName)
	}

	if channel.topic != "" {
		client.reply(rplTopic, channelName, channel.topic)
	} else {
		client.reply(rplNoTopic, channelName)
	}

	nicks := make([]string, 0, 100)
	for nick := range channel.clientMap {
		nicks = append(nicks, nick)
	}

	client.reply(rplNames, channelName, strings.Join(nicks, " "))
}

func (s *Server) partChannel(client *Client, channelName string) {
	channel, exists := s.channelMap[channelName]
	if exists == false {
		return
	}

	//Notify clients of the part
	for _, c := range channel.clientMap {
		c.reply(rplPart, client.nick, channelName)
	}

	delete(channel.clientMap, client.nick)
	delete(client.channelMap, channelName)
}

func (c *Client) clientThread() {
	defer c.connection.Close()

	readSignalChan := make(chan int, 3)
	writeSignalChan := make(chan int, 3)
	writeChan := make(chan string, 100)

	go c.readThread(readSignalChan)
	go c.writeThread(writeSignalChan, writeChan)

	for {
		select {
		case signal := <-c.signalChan:
			//Do stuff
			if signal == signalStop {
				readSignalChan <- signalStop
				writeSignalChan <- signalStop
				break
			}
		case line := <-c.outputChan:
			select {
			case writeChan <- line:
				//It worked
			default:
				log.Printf("Dropped a line for client: %q", c.nick)
				//Do nothing, dropping the line
			}
		}
	}

	//Part from all channels
	for channelName := range c.channelMap {
		c.server.partChannel(c, channelName)
	}

	delete(c.server.clientMap, c.nick)

}

func (c *Client) readThread(signalChan chan int) {
	for {
		select {
		case signal := <-signalChan:
			if signal == signalStop {
				return
			}
		default:
			c.connection.SetReadDeadline(time.Now().Add(time.Second * 3))
			buf := make([]byte, 512)
			ln, err := c.connection.Read(buf)
			if err != nil {
				if err == io.EOF {
					//They must have dc'd
					c.signalChan <- signalStop
					return
				}
				continue
			}

			rawLines := buf[:ln]
			lines := bytes.Split(rawLines, []byte("\r\n"))
			for _, line := range lines {
				if len(line) > 0 {
					c.server.eventChan <- Event{client: c, input: string(line)}
				}
			}
		}
	}
}

func (c *Client) writeThread(signalChan chan int, outputChan chan string) {
	for {
		select {
		case signal := <-signalChan:
			if signal == signalStop {
				return
			}
		case output := <-outputChan:
			line := []byte(fmt.Sprintf("%s\r\n", output))

			c.connection.SetWriteDeadline(time.Now().Add(time.Second * 30))
			_, err := c.connection.Write(line)
			if err != nil {
				log.Printf("Write err: %q", err.Error())
				c.signalChan <- signalStop
				return
			}
		}
	}
}

func (c *Client) disconnect() {
	c.connected = false
	c.signalChan <- signalStop
}

//Send a reply to a user with the code specified
func (c *Client) reply(code int, args ...string) {
	if c.connected == false {
		return
	}

	switch code {
	case rplWelcome:
		c.outputChan <- fmt.Sprintf(":%s 001 %s :Welcome to %s", c.server.name, c.nick, c.server.name)
	case rplJoin:
		c.outputChan <- fmt.Sprintf(":%s JOIN %s", args[0], args[1])
	case rplPart:
		c.outputChan <- fmt.Sprintf(":%s PART %s", args[0], args[1])
	case rplTopic:
		c.outputChan <- fmt.Sprintf(":%s 332 %s %s :%s", c.server.name, c.nick, args[0], args[1])
	case rplNoTopic:
		c.outputChan <- fmt.Sprintf(":%s 331 %s %s :No topic is set", c.server.name, c.nick, args[0])
	case rplNames:
		//TODO: break long lists up into multiple messages
		c.outputChan <- fmt.Sprintf(":%s 353 %s = %s :%s", c.server.name, c.nick, args[0], args[1])
		c.outputChan <- fmt.Sprintf(":%s 366 %s", c.server.name, c.nick)
	case rplNickChange:
		c.outputChan <- fmt.Sprintf(":%s NICK %s", args[0], args[1])
	case rplKill:
		c.outputChan <- fmt.Sprintf(":%s KILL %s A A %s", c.server.name, c.nick, args[0])
	case errMoreArgs:
		c.outputChan <- fmt.Sprintf(":%s 461 %s %s :Not enough params", c.server.name, c.nick, args[0])
	case errNoNick:
		c.outputChan <- fmt.Sprintf(":%s 431 %s :No nickname given", c.server.name, c.nick)
	case errInvalidNick:
		c.outputChan <- fmt.Sprintf(":%s 432 %s %s :Erronenous nickname", c.server.name, c.nick, args[0])
	case errNickInUse:
		c.outputChan <- fmt.Sprintf(":%s 433 %s %s :Nick already in use", c.server.name, c.nick, args[0])
	case errAlreadyReg:
		c.outputChan <- fmt.Sprintf(":%s 462 :You need a valid nick first", c.server.name)
	case errNoSuchNick:
		c.outputChan <- fmt.Sprintf(":%s 401 %s %s :No such nick/channel", c.server.name, c.nick, args[0])
	case errUnknownCommand:
		c.outputChan <- fmt.Sprintf(":%s 421 %s %s :Unknown command", c.server.name, c.nick, args[0])
	case errNotReg:
		c.outputChan <- fmt.Sprintf(":%s 451 :You have not registered", c.server.name)
	}
}

func (c *Client) setNick(nick string) {
	if c.nick != "" {
		delete(c.server.clientMap, c.nick)
		for _, channel := range c.channelMap {
			delete(channel.clientMap, c.nick)
		}
	}

	//Set up new nick
	oldNick := c.nick
	c.nick = nick
	c.server.clientMap[c.nick] = c

	clients := make([]string, 0, 100)

	for _, channel := range c.channelMap {
		channel.clientMap[c.nick] = c

		//Collect list of client nicks who can see us
		for client := range channel.clientMap {
			clients = append(clients, client)
		}
	}

	//By sorting the nicks and skipping duplicates we send each client one message
	sort.Strings(clients)
	prevNick := ""
	for _, nick := range clients {
		if nick == prevNick {
			continue
		}
		prevNick = nick

		client, exists := c.server.clientMap[nick]
		if exists {
			client.reply(rplNickChange, oldNick, c.nick)
		}
	}
}
<|endoftext|>


<commit_before>package rsa

/*
	#cgo LDFLAGS: -lssl -lcrypto
	#include <openssl/rsa.h>
	#include <openssl/engine.h>
	#include <openssl/pem.h>
	#include <openssl/err.h>
	#include <stdio.h>
	#include <stdlib.h>
	#include <string.h>

	char last_error_string[2048] = {0};

	RSA* get_rsa_from_public_key(char * pem)
	{
		RSA* RSA = RSA_new();

		BIO* bio = BIO_new(BIO_s_mem());
		int len = BIO_write(bio, pem, strlen(pem));
		EVP_PKEY* evp_key = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL);
		RSA = EVP_PKEY_get1_RSA(evp_key);

		return RSA;
	}

	RSA* get_rsa_from_private_key(char * pem, char * password)
	{
		RSA* RSA = RSA_new();

		BIO* bio = BIO_new(BIO_s_mem());
		int len = BIO_write(bio, pem, strlen(pem));
		RSA = PEM_read_bio_RSAPrivateKey(bio, NULL, NULL, NULL);
		//RSA = PEM_read_bio_RSAPrivateKey(bio, NULL, (unsigned char*) password, NULL);
		//RSA = EVP_PKEY_get1_RSA(evp_key);

		return RSA;
	}

 	RSA* rsa_read_pem_public(char* pem){
 		FILE * fp = fopen(pem,"r");
 		if(fp == NULL){
 			return get_rsa_from_public_key(pem);
 			snprintf(last_error_string,sizeof(last_error_string),"open \"%s\" failed",pem);
			return NULL;
 		}

 		RSA * public_key = RSA_new();

 		if (!PEM_read_RSA_PUBKEY(fp, &public_key, NULL, NULL)){
 			snprintf(last_error_string,sizeof(last_error_string),"%s",ERR_error_string(ERR_get_error(),NULL));
			RSA_free(public_key);
			return NULL;
		}
		return public_key;
 	}

 	RSA* rsa_read_pem_private(char* pem, char * password){
 		FILE * fp = fopen(pem,"r");
 		if(fp == NULL){
 			if (NULL == get_rsa_from_private_key(pem, password)) {
				snprintf(last_error_string,sizeof(last_error_string),"open \"%s\" failed",pem);
				return NULL;
			}
 		}
 		RSA * private_key = RSA_new();

 		//if (!PEM_read_RSAPrivateKey(fp, &private_key, (unsigned char*)password, NULL)){
 		if (!PEM_read_RSAPrivateKey(fp, &private_key, NULL, NULL)){
 			snprintf(last_error_string,sizeof(last_error_string),"%s",ERR_error_string(ERR_get_error(),NULL));
			RSA_free(private_key);
			return NULL;
		}
		return private_key;
 	}

	int rsa_private_encrypt(int fromSize,unsigned char *from,char** to, char* pem, int padding, char* password){
		RSA* private_key = rsa_read_pem_private(pem, password);
		if(!private_key){
			return -1;
		}
		*to = (char*)malloc(sizeof(char) * RSA_size(private_key));
		int n = RSA_private_encrypt(fromSize,from,(unsigned char *)*to,private_key,padding);
		if (n == -1){
 			snprintf(last_error_string,sizeof(last_error_string),"%s",ERR_error_string(ERR_get_error(),NULL));
		}
		RSA_free(private_key);
		return n;
	}

	int rsa_public_decrypt(int fromSize,unsigned char *from,char** to, char* pem, int padding){
		RSA* public_key = rsa_read_pem_public(pem);
		if(!public_key){
			return -1;
		}
		*to = (char*)malloc(sizeof(char) * RSA_size(public_key));
		int n = RSA_public_decrypt(fromSize,from,(unsigned char *)*to,public_key,padding);
		if (n == -1){
 			snprintf(last_error_string,sizeof(last_error_string),"%s",ERR_error_string(ERR_get_error(),NULL));
		}
		RSA_free(public_key);
		return n;

	}
*/
import "C"
import "unsafe"
import "fmt"

const (
	RSA_PKCS1_PADDING = C.RSA_PKCS1_PADDING
	RSA_NO_PADDING    = C.RSA_NO_PADDING
)

func PublicDecrypt(from []byte, pem string, padding int) ([]byte, error) {
	var to *C.char = nil

	if n := C.rsa_public_decrypt(C.int(len(from)),
		(*C.uchar)(unsafe.Pointer(&from[0])),
		//(*C.uchar)(unsafe.Pointer(&to[0])),
		(**C.char)(unsafe.Pointer(&to)),
		C.CString(pem),
		C.int(padding)); n < 0 {
		return nil, fmt.Errorf("%s", C.GoString(&C.last_error_string[0]))
	} else {
		m := C.GoBytes(unsafe.Pointer(to), n)
		C.free(unsafe.Pointer(to))
		return m, nil
	}
}

func PrivateEncrypt(from []byte, pem string, padding int, password string) ([]byte, error) {
	var to *C.char = nil

	if n := C.rsa_private_encrypt(C.int(len(from)),
		(*C.uchar)(unsafe.Pointer(&from[0])),
		(**C.char)(unsafe.Pointer(&to)),
		//(*C.uchar)(unsafe.Pointer(&to[0])),
		C.CString(pem),
		C.int(padding),
		C.CString(password)); n < 0 {
		return nil, fmt.Errorf("%s", C.GoString(&C.last_error_string[0]))
	} else {
		m := C.GoBytes(unsafe.Pointer(to), n)
		C.free(unsafe.Pointer(to))
		return m, nil
	}
}

func Destroy() {
	C.ERR_clear_error()
}

func init() {
	C.ERR_load_ERR_strings()
}
<commit_msg>add flags<commit_after>package rsa

/*
	#cgo CFLAGS: -I/usr/local/opt/openssl/include
	#cgo LDFLAGS: -L/usr/include/openssl -Lmy/library/src -lcrypto
	#include <openssl/rsa.h>
	#include <openssl/engine.h>
	#include <openssl/pem.h>
	#include <openssl/err.h>
	#include <stdio.h>
	#include <stdlib.h>
	#include <string.h>

	char last_error_string[2048] = {0};

	RSA* get_rsa_from_public_key(char * pem)
	{
		RSA* RSA = RSA_new();

		BIO* bio = BIO_new(BIO_s_mem());
		int len = BIO_write(bio, pem, strlen(pem));
		EVP_PKEY* evp_key = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL);
		RSA = EVP_PKEY_get1_RSA(evp_key);

		return RSA;
	}

	RSA* get_rsa_from_private_key(char * pem, char * password)
	{
		RSA* RSA = RSA_new();

		BIO* bio = BIO_new(BIO_s_mem());
		int len = BIO_write(bio, pem, strlen(pem));
		RSA = PEM_read_bio_RSAPrivateKey(bio, NULL, NULL, NULL);
		//RSA = PEM_read_bio_RSAPrivateKey(bio, NULL, (unsigned char*) password, NULL);
		//RSA = EVP_PKEY_get1_RSA(evp_key);

		return RSA;
	}

 	RSA* rsa_read_pem_public(char* pem){
 		FILE * fp = fopen(pem,"r");
 		if(fp == NULL){
 			return get_rsa_from_public_key(pem);
 			snprintf(last_error_string,sizeof(last_error_string),"open \"%s\" failed",pem);
			return NULL;
 		}

 		RSA * public_key = RSA_new();

 		if (!PEM_read_RSA_PUBKEY(fp, &public_key, NULL, NULL)){
 			snprintf(last_error_string,sizeof(last_error_string),"%s",ERR_error_string(ERR_get_error(),NULL));
			RSA_free(public_key);
			return NULL;
		}
		return public_key;
 	}

 	RSA* rsa_read_pem_private(char* pem, char * password){
 		FILE * fp = fopen(pem,"r");
 		if(fp == NULL){
 			if (NULL == get_rsa_from_private_key(pem, password)) {
				snprintf(last_error_string,sizeof(last_error_string),"open \"%s\" failed",pem);
				return NULL;
			}
 		}
 		RSA * private_key = RSA_new();

 		//if (!PEM_read_RSAPrivateKey(fp, &private_key, (unsigned char*)password, NULL)){
 		if (!PEM_read_RSAPrivateKey(fp, &private_key, NULL, NULL)){
 			snprintf(last_error_string,sizeof(last_error_string),"%s",ERR_error_string(ERR_get_error(),NULL));
			RSA_free(private_key);
			return NULL;
		}
		return private_key;
 	}

	int rsa_private_encrypt(int fromSize,unsigned char *from,char** to, char* pem, int padding, char* password){
		RSA* private_key = rsa_read_pem_private(pem, password);
		if(!private_key){
			return -1;
		}
		*to = (char*)malloc(sizeof(char) * RSA_size(private_key));
		int n = RSA_private_encrypt(fromSize,from,(unsigned char *)*to,private_key,padding);
		if (n == -1){
 			snprintf(last_error_string,sizeof(last_error_string),"%s",ERR_error_string(ERR_get_error(),NULL));
		}
		RSA_free(private_key);
		return n;
	}

	int rsa_public_decrypt(int fromSize,unsigned char *from,char** to, char* pem, int padding){
		RSA* public_key = rsa_read_pem_public(pem);
		if(!public_key){
			return -1;
		}
		*to = (char*)malloc(sizeof(char) * RSA_size(public_key));
		int n = RSA_public_decrypt(fromSize,from,(unsigned char *)*to,public_key,padding);
		if (n == -1){
 			snprintf(last_error_string,sizeof(last_error_string),"%s",ERR_error_string(ERR_get_error(),NULL));
		}
		RSA_free(public_key);
		return n;

	}
*/
import "C"
import "unsafe"
import "fmt"

const (
	RSA_PKCS1_PADDING = C.RSA_PKCS1_PADDING
	RSA_NO_PADDING    = C.RSA_NO_PADDING
)

func PublicDecrypt(from []byte, pem string, padding int) ([]byte, error) {
	var to *C.char = nil

	if n := C.rsa_public_decrypt(C.int(len(from)),
		(*C.uchar)(unsafe.Pointer(&from[0])),
		//(*C.uchar)(unsafe.Pointer(&to[0])),
		(**C.char)(unsafe.Pointer(&to)),
		C.CString(pem),
		C.int(padding)); n < 0 {
		return nil, fmt.Errorf("%s", C.GoString(&C.last_error_string[0]))
	} else {
		m := C.GoBytes(unsafe.Pointer(to), n)
		C.free(unsafe.Pointer(to))
		return m, nil
	}
}

func PrivateEncrypt(from []byte, pem string, padding int, password string) ([]byte, error) {
	var to *C.char = nil

	if n := C.rsa_private_encrypt(C.int(len(from)),
		(*C.uchar)(unsafe.Pointer(&from[0])),
		(**C.char)(unsafe.Pointer(&to)),
		//(*C.uchar)(unsafe.Pointer(&to[0])),
		C.CString(pem),
		C.int(padding),
		C.CString(password)); n < 0 {
		return nil, fmt.Errorf("%s", C.GoString(&C.last_error_string[0]))
	} else {
		m := C.GoBytes(unsafe.Pointer(to), n)
		C.free(unsafe.Pointer(to))
		return m, nil
	}
}

func Destroy() {
	C.ERR_clear_error()
}

func init() {
	C.ERR_load_ERR_strings()
}
<|endoftext|>


<commit_before>package mmvdump

import (
	"os"
	"testing"
)

func TestMmvDump1(t *testing.T) {
	f, err := os.Open("testdata/test1.mmv")
	if err != nil {
		panic(err)
	}

	s, err := os.Stat("testdata/test1.mmv")
	if err != nil {
		panic(err)
	}

	data := make([]byte, s.Size())
	f.Read(data)

	h, tocs, metrics, values, instances, indoms, strings, err := Dump(data)
	if err != nil {
		t.Error(err)
		return
	}

	if h.G1 != h.G2 {
		t.Error("Invalid Header")
	}

	if len(tocs) != 3 {
		t.Errorf("expected number of tocs %d, got %d", 3, len(tocs))
	}

	if len(indoms) != 0 {
		t.Errorf("expected number of indoms %d, got %d", 0, len(indoms))
	}

	if len(strings) != 2 {
		t.Errorf("expected number of strings %d, got %d", 2, len(strings))
	}

	if len(metrics) != 1 {
		t.Errorf("expected number of strings %d, got %d", 1, len(metrics))
	}

	if len(values) != 1 {
		t.Errorf("expected number of strings %d, got %d", 1, len(values))
	}

	if len(instances) != 0 {
		t.Errorf("expected number of strings %d, got %d", 0, len(instances))
	}
}
<commit_msg>mmvdump: refactor data fetching<commit_after>package mmvdump

import (
	"os"
	"testing"
)

func data(filename string) []byte {
	f, err := os.Open(filename)
	if err != nil {
		panic(err)
	}

	s, err := os.Stat(filename)
	if err != nil {
		panic(err)
	}

	data := make([]byte, s.Size())
	n, err := f.Read(data)
	if err != nil {
		panic(err)
	}

	if int64(n) != s.Size() {
		panic("Could not read complete file" + filename + " into memory")
	}

	return data
}

func TestMmvDump1(t *testing.T) {
	d := data("testdata/test1.mmv")

	h, tocs, metrics, values, instances, indoms, strings, err := Dump(d)
	if err != nil {
		t.Error(err)
		return
	}

	if h.G1 != h.G2 {
		t.Error("Invalid Header")
	}

	if len(tocs) != 3 {
		t.Errorf("expected number of tocs %d, got %d", 3, len(tocs))
	}

	if len(indoms) != 0 {
		t.Errorf("expected number of indoms %d, got %d", 0, len(indoms))
	}

	if len(strings) != 2 {
		t.Errorf("expected number of strings %d, got %d", 2, len(strings))
	}

	if len(metrics) != 1 {
		t.Errorf("expected number of strings %d, got %d", 1, len(metrics))
	}

	if len(values) != 1 {
		t.Errorf("expected number of strings %d, got %d", 1, len(values))
	}

	if len(instances) != 0 {
		t.Errorf("expected number of strings %d, got %d", 0, len(instances))
	}
}
<|endoftext|>