<commit_before>// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Build toolchain using Go 1.4.
//
// The general strategy is to copy the source files we need into
// a new GOPATH workspace, adjust import paths appropriately,
// invoke the Go 1.4 go command to build those sources,
// and then copy the binaries back.

package main

import (
	"os"
	"strings"
)

// bootstrapDirs is a list of directories holding code that must be
// compiled with a Go 1.4 toolchain to produce the bootstrapTargets.
// All directories in this list are relative to and must be below $GOROOT/src/cmd.
// The list is assumed to have two kinds of entries: names without slashes,
// which are commands, and entries beginning with internal/, which are
// packages supporting the commands.
var bootstrapDirs = []string{
	"asm",
	"asm/internal/arch",
	"asm/internal/asm",
	"asm/internal/flags",
	"asm/internal/lex",
	"compile",
	"compile/internal/amd64",
	"compile/internal/arm",
	"compile/internal/arm64",
	"compile/internal/big",
	"compile/internal/gc",
	"compile/internal/mips64",
	"compile/internal/ppc64",
	"compile/internal/ssa",
	"compile/internal/x86",
	"internal/gcprog",
	"internal/obj",
	"internal/obj/arm",
	"internal/obj/arm64",
	"internal/obj/mips",
	"internal/obj/ppc64",
	"internal/obj/x86",
	"link",
	"link/internal/amd64",
	"link/internal/arm",
	"link/internal/arm64",
	"link/internal/ld",
	"link/internal/mips64",
	"link/internal/ppc64",
	"link/internal/x86",
}

func bootstrapBuildTools() {
	goroot_bootstrap := os.Getenv("GOROOT_BOOTSTRAP")
	if goroot_bootstrap == "" {
		goroot_bootstrap = pathf("%s/go1.4", os.Getenv("HOME"))
	}
	xprintf("##### Building Go toolchain using %s.\n", goroot_bootstrap)

	mkzbootstrap(pathf("%s/src/cmd/internal/obj/zbootstrap.go", goroot))

	// Use $GOROOT/pkg/bootstrap as the bootstrap workspace root.
	// We use a subdirectory of $GOROOT/pkg because that's the
	// space within $GOROOT where we store all generated objects.
	// We could use a temporary directory outside $GOROOT instead,
	// but it is easier to debug on failure if the files are in a known location.
	workspace := pathf("%s/pkg/bootstrap", goroot)
	xremoveall(workspace)
	base := pathf("%s/src/bootstrap", workspace)
	xmkdirall(base)

	// Copy source code into $GOROOT/pkg/bootstrap and rewrite import paths.
	for _, dir := range bootstrapDirs {
		src := pathf("%s/src/cmd/%s", goroot, dir)
		dst := pathf("%s/%s", base, dir)
		xmkdirall(dst)
		for _, name := range xreaddirfiles(src) {
			srcFile := pathf("%s/%s", src, name)
			text := readfile(srcFile)
			text = bootstrapFixImports(text, srcFile)
			writefile(text, pathf("%s/%s", dst, name), 0)
		}
	}

	// Set up environment for invoking Go 1.4 go command.
	// GOROOT points at Go 1.4 GOROOT,
	// GOPATH points at our bootstrap workspace,
	// GOBIN is empty, so that binaries are installed to GOPATH/bin,
	// and GOOS, GOHOSTOS, GOARCH, and GOHOSTOS are empty,
	// so that Go 1.4 builds whatever kind of binary it knows how to build.
	// Restore GOROOT, GOPATH, and GOBIN when done.
	// Don't bother with GOOS, GOHOSTOS, GOARCH, and GOHOSTARCH,
	// because setup will take care of those when bootstrapBuildTools returns.

	defer os.Setenv("GOROOT", os.Getenv("GOROOT"))
	os.Setenv("GOROOT", goroot_bootstrap)

	defer os.Setenv("GOPATH", os.Getenv("GOPATH"))
	os.Setenv("GOPATH", workspace)

	defer os.Setenv("GOBIN", os.Getenv("GOBIN"))
	os.Setenv("GOBIN", "")

	os.Setenv("GOOS", "")
	os.Setenv("GOHOSTOS", "")
	os.Setenv("GOARCH", "")
	os.Setenv("GOHOSTARCH", "")

	// Run Go 1.4 to build binaries.
	run(workspace, ShowOutput|CheckExit, pathf("%s/bin/go", goroot_bootstrap), "install", "-v", "bootstrap/...")

	// Copy binaries into tool binary directory.
	for _, name := range bootstrapDirs {
		if !strings.Contains(name, "/") {
			copyfile(pathf("%s/%s%s", tooldir, name, exe), pathf("%s/bin/%s%s", workspace, name, exe), writeExec)
		}
	}

	xprintf("\n")
}

func bootstrapFixImports(text, srcFile string) string {
	lines := strings.SplitAfter(text, "\n")
	inBlock := false
	for i, line := range lines {
		if strings.HasPrefix(line, "import (") {
			inBlock = true
			continue
		}
		if inBlock && strings.HasPrefix(line, ")") {
			inBlock = false
			continue
		}
		if strings.HasPrefix(line, `import "`) || strings.HasPrefix(line, `import . "`) ||
			inBlock && (strings.HasPrefix(line, "\t\"") || strings.HasPrefix(line, "\t. \"")) {
			lines[i] = strings.Replace(line, `"cmd/`, `"bootstrap/`, -1)
		}
	}

	lines[0] = "// Do not edit. Bootstrap copy of " + srcFile + "\n\n//line " + srcFile + ":1\n" + lines[0]

	return strings.Join(lines, "")
}
<commit_msg>cmd/dist: build bootstrap toolchain with -l<commit_after>// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Build toolchain using Go 1.4.
//
// The general strategy is to copy the source files we need into
// a new GOPATH workspace, adjust import paths appropriately,
// invoke the Go 1.4 go command to build those sources,
// and then copy the binaries back.

package main

import (
	"os"
	"strings"
)

// bootstrapDirs is a list of directories holding code that must be
// compiled with a Go 1.4 toolchain to produce the bootstrapTargets.
// All directories in this list are relative to and must be below $GOROOT/src/cmd.
// The list is assumed to have two kinds of entries: names without slashes,
// which are commands, and entries beginning with internal/, which are
// packages supporting the commands.
var bootstrapDirs = []string{
	"asm",
	"asm/internal/arch",
	"asm/internal/asm",
	"asm/internal/flags",
	"asm/internal/lex",
	"compile",
	"compile/internal/amd64",
	"compile/internal/arm",
	"compile/internal/arm64",
	"compile/internal/big",
	"compile/internal/gc",
	"compile/internal/mips64",
	"compile/internal/ppc64",
	"compile/internal/ssa",
	"compile/internal/x86",
	"internal/gcprog",
	"internal/obj",
	"internal/obj/arm",
	"internal/obj/arm64",
	"internal/obj/mips",
	"internal/obj/ppc64",
	"internal/obj/x86",
	"link",
	"link/internal/amd64",
	"link/internal/arm",
	"link/internal/arm64",
	"link/internal/ld",
	"link/internal/mips64",
	"link/internal/ppc64",
	"link/internal/x86",
}

func bootstrapBuildTools() {
	goroot_bootstrap := os.Getenv("GOROOT_BOOTSTRAP")
	if goroot_bootstrap == "" {
		goroot_bootstrap = pathf("%s/go1.4", os.Getenv("HOME"))
	}
	xprintf("##### Building Go toolchain using %s.\n", goroot_bootstrap)

	mkzbootstrap(pathf("%s/src/cmd/internal/obj/zbootstrap.go", goroot))

	// Use $GOROOT/pkg/bootstrap as the bootstrap workspace root.
	// We use a subdirectory of $GOROOT/pkg because that's the
	// space within $GOROOT where we store all generated objects.
	// We could use a temporary directory outside $GOROOT instead,
	// but it is easier to debug on failure if the files are in a known location.
	workspace := pathf("%s/pkg/bootstrap", goroot)
	xremoveall(workspace)
	base := pathf("%s/src/bootstrap", workspace)
	xmkdirall(base)

	// Copy source code into $GOROOT/pkg/bootstrap and rewrite import paths.
	for _, dir := range bootstrapDirs {
		src := pathf("%s/src/cmd/%s", goroot, dir)
		dst := pathf("%s/%s", base, dir)
		xmkdirall(dst)
		for _, name := range xreaddirfiles(src) {
			srcFile := pathf("%s/%s", src, name)
			text := readfile(srcFile)
			text = bootstrapFixImports(text, srcFile)
			writefile(text, pathf("%s/%s", dst, name), 0)
		}
	}

	// Set up environment for invoking Go 1.4 go command.
	// GOROOT points at Go 1.4 GOROOT,
	// GOPATH points at our bootstrap workspace,
	// GOBIN is empty, so that binaries are installed to GOPATH/bin,
	// and GOOS, GOHOSTOS, GOARCH, and GOHOSTOS are empty,
	// so that Go 1.4 builds whatever kind of binary it knows how to build.
	// Restore GOROOT, GOPATH, and GOBIN when done.
	// Don't bother with GOOS, GOHOSTOS, GOARCH, and GOHOSTARCH,
	// because setup will take care of those when bootstrapBuildTools returns.

	defer os.Setenv("GOROOT", os.Getenv("GOROOT"))
	os.Setenv("GOROOT", goroot_bootstrap)

	defer os.Setenv("GOPATH", os.Getenv("GOPATH"))
	os.Setenv("GOPATH", workspace)

	defer os.Setenv("GOBIN", os.Getenv("GOBIN"))
	os.Setenv("GOBIN", "")

	os.Setenv("GOOS", "")
	os.Setenv("GOHOSTOS", "")
	os.Setenv("GOARCH", "")
	os.Setenv("GOHOSTARCH", "")

	// Run Go 1.4 to build binaries. Use -gcflags=-l to disable inlining to
	// workaround bugs in Go 1.4's compiler. See discussion thread:
	// https://groups.google.com/d/msg/golang-dev/Ss7mCKsvk8w/Gsq7VYI0AwAJ
	run(workspace, ShowOutput|CheckExit, pathf("%s/bin/go", goroot_bootstrap), "install", "-gcflags=-l", "-v", "bootstrap/...")

	// Copy binaries into tool binary directory.
	for _, name := range bootstrapDirs {
		if !strings.Contains(name, "/") {
			copyfile(pathf("%s/%s%s", tooldir, name, exe), pathf("%s/bin/%s%s", workspace, name, exe), writeExec)
		}
	}

	xprintf("\n")
}

func bootstrapFixImports(text, srcFile string) string {
	lines := strings.SplitAfter(text, "\n")
	inBlock := false
	for i, line := range lines {
		if strings.HasPrefix(line, "import (") {
			inBlock = true
			continue
		}
		if inBlock && strings.HasPrefix(line, ")") {
			inBlock = false
			continue
		}
		if strings.HasPrefix(line, `import "`) || strings.HasPrefix(line, `import . "`) ||
			inBlock && (strings.HasPrefix(line, "\t\"") || strings.HasPrefix(line, "\t. \"")) {
			lines[i] = strings.Replace(line, `"cmd/`, `"bootstrap/`, -1)
		}
	}

	lines[0] = "// Do not edit. Bootstrap copy of " + srcFile + "\n\n//line " + srcFile + ":1\n" + lines[0]

	return strings.Join(lines, "")
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 VMware, Inc. All Rights Reserved.
//
// 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 dao

import (
	"github.com/vmware/harbor/src/common"
	"github.com/vmware/harbor/src/common/models"

	"fmt"
	"time"

	"github.com/vmware/harbor/src/common/utils/log"
)

//TODO:transaction, return err

// AddProject adds a project to the database along with project roles information and access log records.
func AddProject(project models.Project) (int64, error) {

	o := GetOrmer()
	p, err := o.Raw("insert into project (owner_id, name, creation_time, update_time, deleted, public) values (?, ?, ?, ?, ?, ?)").Prepare()
	if err != nil {
		return 0, err
	}

	now := time.Now()
	r, err := p.Exec(project.OwnerID, project.Name, now, now, project.Deleted, project.Public)
	if err != nil {
		return 0, err
	}

	projectID, err := r.LastInsertId()
	if err != nil {
		return 0, err
	}

	err = AddProjectMember(projectID, project.OwnerID, models.PROJECTADMIN)
	return projectID, err
}

// IsProjectPublic ...
func IsProjectPublic(projectName string) bool {
	project, err := GetProjectByName(projectName)
	if err != nil {
		log.Errorf("Error occurred in GetProjectByName: %v", err)
		return false
	}
	if project == nil {
		return false
	}
	return project.Public == 1
}

//ProjectExists returns whether the project exists according to its name of ID.
func ProjectExists(nameOrID interface{}) (bool, error) {
	o := GetOrmer()
	type dummy struct{}
	sql := `select project_id from project where deleted = 0 and `
	switch nameOrID.(type) {
	case int64:
		sql += `project_id = ?`
	case string:
		sql += `name = ?`
	default:
		return false, fmt.Errorf("Invalid nameOrId: %v", nameOrID)
	}

	var d []dummy
	num, err := o.Raw(sql, nameOrID).QueryRows(&d)
	if err != nil {
		return false, err
	}
	return num > 0, nil

}

// GetProjectByID ...
func GetProjectByID(id int64) (*models.Project, error) {
	o := GetOrmer()

	sql := `select p.project_id, p.name, u.username as owner_name, p.owner_id, p.creation_time, p.update_time, p.public
		from project p left join user u on p.owner_id = u.user_id where p.deleted = 0 and p.project_id = ?`
	queryParam := make([]interface{}, 1)
	queryParam = append(queryParam, id)

	p := []models.Project{}
	count, err := o.Raw(sql, queryParam).QueryRows(&p)

	if err != nil {
		return nil, err
	}

	if count == 0 {
		return nil, nil
	}

	return &p[0], nil
}

// GetProjectByName ...
func GetProjectByName(name string) (*models.Project, error) {
	o := GetOrmer()
	var p []models.Project
	n, err := o.Raw(`select * from project where name = ? and deleted = 0`, name).QueryRows(&p)
	if err != nil {
		return nil, err
	}

	if n == 0 {
		return nil, nil
	}

	return &p[0], nil
}

// GetPermission gets roles that the user has according to the project.
func GetPermission(username, projectName string) (string, error) {
	o := GetOrmer()

	sql := `select r.role_code from role as r
		inner join project_member as pm on r.role_id = pm.role
		inner join user as u on u.user_id = pm.user_id
		inner join project p on p.project_id = pm.project_id
		where u.username = ? and p.name = ? and u.deleted = 0 and p.deleted = 0`

	var r []models.Role
	n, err := o.Raw(sql, username, projectName).QueryRows(&r)
	if err != nil {
		return "", err
	}

	if n == 0 {
		return "", nil
	}

	return r[0].RoleCode, nil
}

// ToggleProjectPublicity toggles the publicity of the project.
func ToggleProjectPublicity(projectID int64, publicity int) error {
	o := GetOrmer()
	sql := "update project set public = ? where project_id = ?"
	_, err := o.Raw(sql, publicity, projectID).Exec()
	return err
}

// GetHasReadPermProjects returns a project list,
// which satisfies the following conditions:
// 1. the project is not deleted
// 2. the prject is public or the user is a member of the project
func GetHasReadPermProjects(username string) ([]*models.Project, error) {
	user, err := GetUser(models.User{
		Username: username,
	})
	if err != nil {
		return nil, err
	}

	o := GetOrmer()

	sql :=
		`select distinct p.project_id, p.name, p.public,
			p.owner_id, p.creation_time, p.update_time
		from project p
		left join project_member pm
		on p.project_id = pm.project_id
		where (pm.user_id = ? or p.public = 1)
		and p.deleted = 0 `

	var projects []*models.Project

	if _, err := o.Raw(sql, user.UserID).QueryRows(&projects); err != nil {
		return nil, err
	}

	return projects, nil
}

// GetTotalOfProjects returns the total count of projects
// according to the query conditions
func GetTotalOfProjects(query *models.ProjectQueryParam, base ...*models.BaseProjectCollection) (int64, error) {

	var (
		owner  string
		name   string
		public *bool
		member string
		role   int
	)

	if query != nil {
		owner = query.Owner
		name = query.Name
		public = query.Public
		if query.Member != nil {
			member = query.Member.Name
			role = query.Member.Role
		}
	}

	sql, params := projectQueryConditions(owner, name, public, member, role, base...)

	sql = `select count(*) ` + sql

	var total int64
	err := GetOrmer().Raw(sql, params).QueryRow(&total)
	return total, err
}

// GetProjects returns a project list according to the query conditions
func GetProjects(query *models.ProjectQueryParam, base ...*models.BaseProjectCollection) ([]*models.Project, error) {

	var (
		owner  string
		name   string
		public *bool
		member string
		role   int
		page   int64
		size   int64
	)

	if query != nil {
		owner = query.Owner
		name = query.Name
		public = query.Public
		if query.Member != nil {
			member = query.Member.Name
			role = query.Member.Role
		}
		if query.Pagination != nil {
			page = query.Pagination.Page
			size = query.Pagination.Size
		}
	}

	sql, params := projectQueryConditions(owner, name, public, member, role, base...)

	sql = `select distinct p.project_id, p.name, p.public, p.owner_id,
				p.creation_time, p.update_time ` + sql
	if size > 0 {
		sql += ` limit ?`
		params = append(params, size)

		if page > 0 {
			sql += ` offset ?`
			params = append(params, (page-1)*size)
		}
	}

	var projects []*models.Project
	_, err := GetOrmer().Raw(sql, params).QueryRows(&projects)
	return projects, err
}

func projectQueryConditions(owner, name string, public *bool, member string,
	role int, base ...*models.BaseProjectCollection) (string, []interface{}) {
	params := []interface{}{}

	// the base project collections:
	// 1. all projects
	// 2. public projects
	// 3. public projects and projects which the user is a member of
	collection := `project `
	if len(base) != 0 && base[0] != nil {
		if len(base[0].Member) > 0 {
			collection = `(select pr.project_id, pr.owner_id, pr.name, pr.
						creation_time, pr.update_time, pr.deleted, pr.public
					from project pr
					join project_member prm
						on pr.project_id = prm.project_id
					join user ur
						on prm.user_id=ur.user_id
					where ur.username=? `
			if base[0].Public {
				collection += ` or pr.public=1 `
			}
			collection += `) `
			params = append(params, base[0].Member)
		} else if base[0].Public {
			collection = `(select * from project pr
					where pr.public=1) `
		}
	}

	sql := ` from ` + collection + ` as p`

	if len(owner) != 0 {
		sql += ` join user u1
					on p.owner_id = u1.user_id`
	}

	if len(member) != 0 {
		sql += ` join project_member pm
					on p.project_id = pm.project_id
					join user u2
					on pm.user_id=u2.user_id`
	}
	sql += ` where p.deleted=0`

	if len(owner) != 0 {
		sql += ` and u1.username=?`
		params = append(params, owner)
	}

	if len(name) != 0 {
		sql += ` and p.name like ?`
		params = append(params, "%"+escape(name)+"%")
	}

	if public != nil {
		sql += ` and p.public = ?`
		if *public {
			params = append(params, 1)
		} else {
			params = append(params, 0)
		}
	}

	if len(member) != 0 {
		sql += ` and u2.username=?`
		params = append(params, member)

		if role > 0 {
			sql += ` and pm.role = ?`
			roleID := 0
			switch role {
			case common.RoleProjectAdmin:
				roleID = 1
			case common.RoleDeveloper:
				roleID = 2
			case common.RoleGuest:
				roleID = 3

			}
			params = append(params, roleID)
		}
	}

	sql += ` order by p.name`

	return sql, params
}

// DeleteProject ...
func DeleteProject(id int64) error {
	project, err := GetProjectByID(id)
	if err != nil {
		return err
	}

	name := fmt.Sprintf("%s#%d", project.Name, project.ProjectID)

	sql := `update project
		set deleted = 1, name = ?
		where project_id = ?`
	_, err = GetOrmer().Raw(sql, name, id).Exec()
	return err
}
<commit_msg>update<commit_after>// Copyright (c) 2017 VMware, Inc. All Rights Reserved.
//
// 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 dao

import (
	"github.com/vmware/harbor/src/common"
	"github.com/vmware/harbor/src/common/models"

	"fmt"
	"time"

	"github.com/vmware/harbor/src/common/utils/log"
)

//TODO:transaction, return err

// AddProject adds a project to the database along with project roles information and access log records.
func AddProject(project models.Project) (int64, error) {

	o := GetOrmer()
	p, err := o.Raw("insert into project (owner_id, name, creation_time, update_time, deleted, public) values (?, ?, ?, ?, ?, ?)").Prepare()
	if err != nil {
		return 0, err
	}

	now := time.Now()
	r, err := p.Exec(project.OwnerID, project.Name, now, now, project.Deleted, project.Public)
	if err != nil {
		return 0, err
	}

	projectID, err := r.LastInsertId()
	if err != nil {
		return 0, err
	}

	err = AddProjectMember(projectID, project.OwnerID, models.PROJECTADMIN)
	return projectID, err
}

// IsProjectPublic ...
func IsProjectPublic(projectName string) bool {
	project, err := GetProjectByName(projectName)
	if err != nil {
		log.Errorf("Error occurred in GetProjectByName: %v", err)
		return false
	}
	if project == nil {
		return false
	}
	return project.Public == 1
}

//ProjectExists returns whether the project exists according to its name of ID.
func ProjectExists(nameOrID interface{}) (bool, error) {
	o := GetOrmer()
	type dummy struct{}
	sql := `select project_id from project where deleted = 0 and `
	switch nameOrID.(type) {
	case int64:
		sql += `project_id = ?`
	case string:
		sql += `name = ?`
	default:
		return false, fmt.Errorf("Invalid nameOrId: %v", nameOrID)
	}

	var d []dummy
	num, err := o.Raw(sql, nameOrID).QueryRows(&d)
	if err != nil {
		return false, err
	}
	return num > 0, nil

}

// GetProjectByID ...
func GetProjectByID(id int64) (*models.Project, error) {
	o := GetOrmer()

	sql := `select p.project_id, p.name, u.username as owner_name, p.owner_id, p.creation_time, p.update_time, p.public
		from project p left join user u on p.owner_id = u.user_id where p.deleted = 0 and p.project_id = ?`
	queryParam := make([]interface{}, 1)
	queryParam = append(queryParam, id)

	p := []models.Project{}
	count, err := o.Raw(sql, queryParam).QueryRows(&p)

	if err != nil {
		return nil, err
	}

	if count == 0 {
		return nil, nil
	}

	return &p[0], nil
}

// GetProjectByName ...
func GetProjectByName(name string) (*models.Project, error) {
	o := GetOrmer()
	var p []models.Project
	n, err := o.Raw(`select * from project where name = ? and deleted = 0`, name).QueryRows(&p)
	if err != nil {
		return nil, err
	}

	if n == 0 {
		return nil, nil
	}

	return &p[0], nil
}

// GetPermission gets roles that the user has according to the project.
func GetPermission(username, projectName string) (string, error) {
	o := GetOrmer()

	sql := `select r.role_code from role as r
		inner join project_member as pm on r.role_id = pm.role
		inner join user as u on u.user_id = pm.user_id
		inner join project p on p.project_id = pm.project_id
		where u.username = ? and p.name = ? and u.deleted = 0 and p.deleted = 0`

	var r []models.Role
	n, err := o.Raw(sql, username, projectName).QueryRows(&r)
	if err != nil {
		return "", err
	}

	if n == 0 {
		return "", nil
	}

	return r[0].RoleCode, nil
}

// ToggleProjectPublicity toggles the publicity of the project.
func ToggleProjectPublicity(projectID int64, publicity int) error {
	o := GetOrmer()
	sql := "update project set public = ? where project_id = ?"
	_, err := o.Raw(sql, publicity, projectID).Exec()
	return err
}

// GetHasReadPermProjects returns a project list,
// which satisfies the following conditions:
// 1. the project is not deleted
// 2. the prject is public or the user is a member of the project
func GetHasReadPermProjects(username string) ([]*models.Project, error) {
	user, err := GetUser(models.User{
		Username: username,
	})
	if err != nil {
		return nil, err
	}

	o := GetOrmer()

	sql :=
		`select distinct p.project_id, p.name, p.public,
			p.owner_id, p.creation_time, p.update_time
		from project p
		left join project_member pm
		on p.project_id = pm.project_id
		where (pm.user_id = ? or p.public = 1)
		and p.deleted = 0 `

	var projects []*models.Project

	if _, err := o.Raw(sql, user.UserID).QueryRows(&projects); err != nil {
		return nil, err
	}

	return projects, nil
}

// GetTotalOfProjects returns the total count of projects
// according to the query conditions
func GetTotalOfProjects(query *models.ProjectQueryParam, base ...*models.BaseProjectCollection) (int64, error) {

	var (
		owner  string
		name   string
		public *bool
		member string
		role   int
	)

	if query != nil {
		owner = query.Owner
		name = query.Name
		public = query.Public
		if query.Member != nil {
			member = query.Member.Name
			role = query.Member.Role
		}
	}

	sql, params := projectQueryConditions(owner, name, public, member, role, base...)

	sql = `select count(*) ` + sql

	var total int64
	err := GetOrmer().Raw(sql, params).QueryRow(&total)
	return total, err
}

// GetProjects returns a project list according to the query conditions
func GetProjects(query *models.ProjectQueryParam, base ...*models.BaseProjectCollection) ([]*models.Project, error) {

	var (
		owner  string
		name   string
		public *bool
		member string
		role   int
		page   int64
		size   int64
	)

	if query != nil {
		owner = query.Owner
		name = query.Name
		public = query.Public
		if query.Member != nil {
			member = query.Member.Name
			role = query.Member.Role
		}
		if query.Pagination != nil {
			page = query.Pagination.Page
			size = query.Pagination.Size
		}
	}

	sql, params := projectQueryConditions(owner, name, public, member, role, base...)

	sql = `select distinct p.project_id, p.name, p.public, p.owner_id,
				p.creation_time, p.update_time ` + sql
	if size > 0 {
		sql += ` limit ?`
		params = append(params, size)

		if page > 0 {
			sql += ` offset ?`
			params = append(params, (page-1)*size)
		}
	}

	var projects []*models.Project
	_, err := GetOrmer().Raw(sql, params).QueryRows(&projects)
	return projects, err
}

func projectQueryConditions(owner, name string, public *bool, member string,
	role int, base ...*models.BaseProjectCollection) (string, []interface{}) {
	params := []interface{}{}

	// the base project collections:
	// 1. all projects
	// 2. public projects
	// 3. public projects and projects which the user is a member of
	collection := `project `
	if len(base) != 0 && base[0] != nil {
		if len(base[0].Member) == 0 && base[0].Public {
			collection = `(select * from project pr
					where pr.public=1) `
		}
		if len(base[0].Member) > 0 && base[0].Public {
			collection = `(select pr.project_id, pr.owner_id, pr.name, pr.
						creation_time, pr.update_time, pr.deleted, pr.public
					from project pr
					join project_member prm
						on pr.project_id = prm.project_id
					join user ur
						on prm.user_id=ur.user_id
					where ur.username=?  or pr.public=1 )`
			params = append(params, base[0].Member)
		}
	}

	sql := ` from ` + collection + ` as p`

	if len(owner) != 0 {
		sql += ` join user u1
					on p.owner_id = u1.user_id`
	}

	if len(member) != 0 {
		sql += ` join project_member pm
					on p.project_id = pm.project_id
					join user u2
					on pm.user_id=u2.user_id`
	}
	sql += ` where p.deleted=0`

	if len(owner) != 0 {
		sql += ` and u1.username=?`
		params = append(params, owner)
	}

	if len(name) != 0 {
		sql += ` and p.name like ?`
		params = append(params, "%"+escape(name)+"%")
	}

	if public != nil {
		sql += ` and p.public = ?`
		if *public {
			params = append(params, 1)
		} else {
			params = append(params, 0)
		}
	}

	if len(member) != 0 {
		sql += ` and u2.username=?`
		params = append(params, member)

		if role > 0 {
			sql += ` and pm.role = ?`
			roleID := 0
			switch role {
			case common.RoleProjectAdmin:
				roleID = 1
			case common.RoleDeveloper:
				roleID = 2
			case common.RoleGuest:
				roleID = 3

			}
			params = append(params, roleID)
		}
	}

	sql += ` order by p.name`

	return sql, params
}

// DeleteProject ...
func DeleteProject(id int64) error {
	project, err := GetProjectByID(id)
	if err != nil {
		return err
	}

	name := fmt.Sprintf("%s#%d", project.Name, project.ProjectID)

	sql := `update project
		set deleted = 1, name = ?
		where project_id = ?`
	_, err = GetOrmer().Raw(sql, name, id).Exec()
	return err
}
<|endoftext|>


<commit_before>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Tests for client.go

package http_test

import (
	"fmt"
	. "http"
	"http/httptest"
	"io/ioutil"
	"os"
	"strconv"
	"strings"
	"testing"
)

var robotsTxtHandler = HandlerFunc(func(w ResponseWriter, r *Request) {
	w.Header().Set("Last-Modified", "sometime")
	fmt.Fprintf(w, "User-agent: go\nDisallow: /something/")
})

func TestClient(t *testing.T) {
	ts := httptest.NewServer(robotsTxtHandler)
	defer ts.Close()

	r, err := Get(ts.URL)
	var b []byte
	if err == nil {
		b, err = ioutil.ReadAll(r.Body)
		r.Body.Close()
	}
	if err != nil {
		t.Error(err)
	} else if s := string(b); !strings.HasPrefix(s, "User-agent:") {
		t.Errorf("Incorrect page body (did not begin with User-agent): %q", s)
	}
}

func TestClientHead(t *testing.T) {
	ts := httptest.NewServer(robotsTxtHandler)
	defer ts.Close()

	r, err := Head(ts.URL)
	if err != nil {
		t.Fatal(err)
	}
	if _, ok := r.Header["Last-Modified"]; !ok {
		t.Error("Last-Modified header not found.")
	}
}

type recordingTransport struct {
	req *Request
}

func (t *recordingTransport) RoundTrip(req *Request) (resp *Response, err os.Error) {
	t.req = req
	return nil, os.NewError("dummy impl")
}

func TestGetRequestFormat(t *testing.T) {
	tr := &recordingTransport{}
	client := &Client{Transport: tr}
	url := "http://dummy.faketld/"
	client.Get(url) // Note: doesn't hit network
	if tr.req.Method != "GET" {
		t.Errorf("expected method %q; got %q", "GET", tr.req.Method)
	}
	if tr.req.URL.String() != url {
		t.Errorf("expected URL %q; got %q", url, tr.req.URL.String())
	}
	if tr.req.Header == nil {
		t.Errorf("expected non-nil request Header")
	}
}

func TestRedirects(t *testing.T) {
	var ts *httptest.Server
	ts = httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
		n, _ := strconv.Atoi(r.FormValue("n"))
		// Test Referer header. (7 is arbitrary position to test at)
		if n == 7 {
			if g, e := r.Referer, ts.URL+"/?n=6"; e != g {
				t.Errorf("on request ?n=7, expected referer of %q; got %q", e, g)
			}
		}
		if n < 15 {
			Redirect(w, r, fmt.Sprintf("/?n=%d", n+1), StatusFound)
			return
		}
		fmt.Fprintf(w, "n=%d", n)
	}))
	defer ts.Close()

	c := &Client{}
	_, err := c.Get(ts.URL)
	if e, g := "Get /?n=10: stopped after 10 redirects", fmt.Sprintf("%v", err); e != g {
		t.Errorf("with default client Get, expected error %q, got %q", e, g)
	}

	// HEAD request should also have the ability to follow redirects.
	_, err = c.Head(ts.URL)
	if e, g := "Head /?n=10: stopped after 10 redirects", fmt.Sprintf("%v", err); e != g {
		t.Errorf("with default client Head, expected error %q, got %q", e, g)
	}

	// Do should also follow redirects.
	greq, _ := NewRequest("GET", ts.URL, nil)
	_, err = c.Do(greq)
	if e, g := "Get /?n=10: stopped after 10 redirects", fmt.Sprintf("%v", err); e != g {
		t.Errorf("with default client Do, expected error %q, got %q", e, g)
	}

	var checkErr os.Error
	var lastVia []*Request
	c = &Client{CheckRedirect: func(_ *Request, via []*Request) os.Error {
		lastVia = via
		return checkErr
	}}
	res, err := c.Get(ts.URL)
	finalUrl := res.Request.URL.String()
	if e, g := "<nil>", fmt.Sprintf("%v", err); e != g {
		t.Errorf("with custom client, expected error %q, got %q", e, g)
	}
	if !strings.HasSuffix(finalUrl, "/?n=15") {
		t.Errorf("expected final url to end in /?n=15; got url %q", finalUrl)
	}
	if e, g := 15, len(lastVia); e != g {
		t.Errorf("expected lastVia to have contained %d elements; got %d", e, g)
	}

	checkErr = os.NewError("no redirects allowed")
	res, err = c.Get(ts.URL)
	finalUrl = res.Request.URL.String()
	if e, g := "Get /?n=1: no redirects allowed", fmt.Sprintf("%v", err); e != g {
		t.Errorf("with redirects forbidden, expected error %q, got %q", e, g)
	}
}
<commit_msg>http: Client test for streaming responses (no code changes)<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Tests for client.go

package http_test

import (
	"fmt"
	. "http"
	"http/httptest"
	"io"
	"io/ioutil"
	"os"
	"strconv"
	"strings"
	"testing"
)

var robotsTxtHandler = HandlerFunc(func(w ResponseWriter, r *Request) {
	w.Header().Set("Last-Modified", "sometime")
	fmt.Fprintf(w, "User-agent: go\nDisallow: /something/")
})

func TestClient(t *testing.T) {
	ts := httptest.NewServer(robotsTxtHandler)
	defer ts.Close()

	r, err := Get(ts.URL)
	var b []byte
	if err == nil {
		b, err = ioutil.ReadAll(r.Body)
		r.Body.Close()
	}
	if err != nil {
		t.Error(err)
	} else if s := string(b); !strings.HasPrefix(s, "User-agent:") {
		t.Errorf("Incorrect page body (did not begin with User-agent): %q", s)
	}
}

func TestClientHead(t *testing.T) {
	ts := httptest.NewServer(robotsTxtHandler)
	defer ts.Close()

	r, err := Head(ts.URL)
	if err != nil {
		t.Fatal(err)
	}
	if _, ok := r.Header["Last-Modified"]; !ok {
		t.Error("Last-Modified header not found.")
	}
}

type recordingTransport struct {
	req *Request
}

func (t *recordingTransport) RoundTrip(req *Request) (resp *Response, err os.Error) {
	t.req = req
	return nil, os.NewError("dummy impl")
}

func TestGetRequestFormat(t *testing.T) {
	tr := &recordingTransport{}
	client := &Client{Transport: tr}
	url := "http://dummy.faketld/"
	client.Get(url) // Note: doesn't hit network
	if tr.req.Method != "GET" {
		t.Errorf("expected method %q; got %q", "GET", tr.req.Method)
	}
	if tr.req.URL.String() != url {
		t.Errorf("expected URL %q; got %q", url, tr.req.URL.String())
	}
	if tr.req.Header == nil {
		t.Errorf("expected non-nil request Header")
	}
}

func TestRedirects(t *testing.T) {
	var ts *httptest.Server
	ts = httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
		n, _ := strconv.Atoi(r.FormValue("n"))
		// Test Referer header. (7 is arbitrary position to test at)
		if n == 7 {
			if g, e := r.Referer, ts.URL+"/?n=6"; e != g {
				t.Errorf("on request ?n=7, expected referer of %q; got %q", e, g)
			}
		}
		if n < 15 {
			Redirect(w, r, fmt.Sprintf("/?n=%d", n+1), StatusFound)
			return
		}
		fmt.Fprintf(w, "n=%d", n)
	}))
	defer ts.Close()

	c := &Client{}
	_, err := c.Get(ts.URL)
	if e, g := "Get /?n=10: stopped after 10 redirects", fmt.Sprintf("%v", err); e != g {
		t.Errorf("with default client Get, expected error %q, got %q", e, g)
	}

	// HEAD request should also have the ability to follow redirects.
	_, err = c.Head(ts.URL)
	if e, g := "Head /?n=10: stopped after 10 redirects", fmt.Sprintf("%v", err); e != g {
		t.Errorf("with default client Head, expected error %q, got %q", e, g)
	}

	// Do should also follow redirects.
	greq, _ := NewRequest("GET", ts.URL, nil)
	_, err = c.Do(greq)
	if e, g := "Get /?n=10: stopped after 10 redirects", fmt.Sprintf("%v", err); e != g {
		t.Errorf("with default client Do, expected error %q, got %q", e, g)
	}

	var checkErr os.Error
	var lastVia []*Request
	c = &Client{CheckRedirect: func(_ *Request, via []*Request) os.Error {
		lastVia = via
		return checkErr
	}}
	res, err := c.Get(ts.URL)
	finalUrl := res.Request.URL.String()
	if e, g := "<nil>", fmt.Sprintf("%v", err); e != g {
		t.Errorf("with custom client, expected error %q, got %q", e, g)
	}
	if !strings.HasSuffix(finalUrl, "/?n=15") {
		t.Errorf("expected final url to end in /?n=15; got url %q", finalUrl)
	}
	if e, g := 15, len(lastVia); e != g {
		t.Errorf("expected lastVia to have contained %d elements; got %d", e, g)
	}

	checkErr = os.NewError("no redirects allowed")
	res, err = c.Get(ts.URL)
	finalUrl = res.Request.URL.String()
	if e, g := "Get /?n=1: no redirects allowed", fmt.Sprintf("%v", err); e != g {
		t.Errorf("with redirects forbidden, expected error %q, got %q", e, g)
	}
}

func TestStreamingGet(t *testing.T) {
	say := make(chan string)
	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
		w.(Flusher).Flush()
		for str := range say {
			w.Write([]byte(str))
			w.(Flusher).Flush()
		}
	}))
	defer ts.Close()

	c := &Client{}
	res, err := c.Get(ts.URL)
	if err != nil {
		t.Fatal(err)
	}
	var buf [10]byte
	for _, str := range []string{"i", "am", "also", "known", "as", "comet"} {
		say <- str
		n, err := io.ReadFull(res.Body, buf[0:len(str)])
		if err != nil {
			t.Fatalf("ReadFull on %q: %v", str, err)
		}
		if n != len(str) {
			t.Fatalf("Receiving %q, only read %d bytes", str, n)
		}
		got := string(buf[0:n])
		if got != str {
			t.Fatalf("Expected %q, got %q", str, got)
		}
	}
	close(say)
	_, err = io.ReadFull(res.Body, buf[0:1])
	if err != os.EOF {
		t.Fatalf("at end expected EOF, got %v", err)
	}
}
<|endoftext|>


<commit_before>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package ioutil implements some I/O utility functions.
package ioutil

import (
	"bytes"
	"io"
	"os"
	"sort"
)

// readAll reads from r until an error or EOF and returns the data it read
// from the internal buffer allocated with a specified capacity.
func readAll(r io.Reader, capacity int64) ([]byte, os.Error) {
	buf := bytes.NewBuffer(make([]byte, 0, capacity))
	_, err := buf.ReadFrom(r)
	return buf.Bytes(), err
}

// ReadAll reads from r until an error or EOF and returns the data it read.
func ReadAll(r io.Reader) ([]byte, os.Error) {
	return readAll(r, bytes.MinRead)
}

// ReadFile reads the file named by filename and returns the contents.
func ReadFile(filename string) ([]byte, os.Error) {
	f, err := os.Open(filename)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	// It's a good but not certain bet that FileInfo will tell us exactly how much to
	// read, so let's try it but be prepared for the answer to be wrong.
	fi, err := f.Stat()
	var n int64
	if err == nil && fi.Size < 2e9 { // Don't preallocate a huge buffer, just in case.
		n = fi.Size
	}
	// As initial capacity for readAll, use n + a little extra in case Size is zero,
	// and to avoid another allocation after Read has filled the buffer.  The readAll
	// call will read into its allocated internal buffer cheaply.  If the size was
	// wrong, we'll either waste some space off the end or reallocate as needed, but
	// in the overwhelmingly common case we'll get it just right.
	return readAll(f, n+bytes.MinRead)
}

// WriteFile writes data to a file named by filename.
// If the file does not exist, WriteFile creates it with permissions perm;
// otherwise WriteFile truncates it before writing.
func WriteFile(filename string, data []byte, perm uint32) os.Error {
	f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)
	if err != nil {
		return err
	}
	n, err := f.Write(data)
	f.Close()
	if err == nil && n < len(data) {
		err = io.ErrShortWrite
	}
	return err
}

// A fileInfoList implements sort.Interface.
type fileInfoList []*os.FileInfo

func (f fileInfoList) Len() int           { return len(f) }
func (f fileInfoList) Less(i, j int) bool { return f[i].Name < f[j].Name }
func (f fileInfoList) Swap(i, j int)      { f[i], f[j] = f[j], f[i] }

// ReadDir reads the directory named by dirname and returns
// a list of sorted directory entries.
func ReadDir(dirname string) ([]*os.FileInfo, os.Error) {
	f, err := os.Open(dirname)
	if err != nil {
		return nil, err
	}
	list, err := f.Readdir(-1)
	f.Close()
	if err != nil {
		return nil, err
	}
	fi := make(fileInfoList, len(list))
	for i := range list {
		fi[i] = &list[i]
	}
	sort.Sort(fi)
	return fi, nil
}

type nopCloser struct {
	io.Reader
}

func (nopCloser) Close() os.Error { return nil }

// NopCloser returns a ReadCloser with a no-op Close method wrapping
// the provided Reader r.
func NopCloser(r io.Reader) io.ReadCloser {
	return nopCloser{r}
}

type devNull int

func (devNull) Write(p []byte) (int, os.Error) {
	return len(p), nil
}

// Discard is an io.Writer on which all Write calls succeed
// without doing anything.
var Discard io.Writer = devNull(0)
<commit_msg>io/ioutil: improve performance of ioutil.Discard Fixes issue 2084.<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package ioutil implements some I/O utility functions.
package ioutil

import (
	"bytes"
	"io"
	"os"
	"sort"
)

// readAll reads from r until an error or EOF and returns the data it read
// from the internal buffer allocated with a specified capacity.
func readAll(r io.Reader, capacity int64) ([]byte, os.Error) {
	buf := bytes.NewBuffer(make([]byte, 0, capacity))
	_, err := buf.ReadFrom(r)
	return buf.Bytes(), err
}

// ReadAll reads from r until an error or EOF and returns the data it read.
func ReadAll(r io.Reader) ([]byte, os.Error) {
	return readAll(r, bytes.MinRead)
}

// ReadFile reads the file named by filename and returns the contents.
func ReadFile(filename string) ([]byte, os.Error) {
	f, err := os.Open(filename)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	// It's a good but not certain bet that FileInfo will tell us exactly how much to
	// read, so let's try it but be prepared for the answer to be wrong.
	fi, err := f.Stat()
	var n int64
	if err == nil && fi.Size < 2e9 { // Don't preallocate a huge buffer, just in case.
		n = fi.Size
	}
	// As initial capacity for readAll, use n + a little extra in case Size is zero,
	// and to avoid another allocation after Read has filled the buffer.  The readAll
	// call will read into its allocated internal buffer cheaply.  If the size was
	// wrong, we'll either waste some space off the end or reallocate as needed, but
	// in the overwhelmingly common case we'll get it just right.
	return readAll(f, n+bytes.MinRead)
}

// WriteFile writes data to a file named by filename.
// If the file does not exist, WriteFile creates it with permissions perm;
// otherwise WriteFile truncates it before writing.
func WriteFile(filename string, data []byte, perm uint32) os.Error {
	f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)
	if err != nil {
		return err
	}
	n, err := f.Write(data)
	f.Close()
	if err == nil && n < len(data) {
		err = io.ErrShortWrite
	}
	return err
}

// A fileInfoList implements sort.Interface.
type fileInfoList []*os.FileInfo

func (f fileInfoList) Len() int           { return len(f) }
func (f fileInfoList) Less(i, j int) bool { return f[i].Name < f[j].Name }
func (f fileInfoList) Swap(i, j int)      { f[i], f[j] = f[j], f[i] }

// ReadDir reads the directory named by dirname and returns
// a list of sorted directory entries.
func ReadDir(dirname string) ([]*os.FileInfo, os.Error) {
	f, err := os.Open(dirname)
	if err != nil {
		return nil, err
	}
	list, err := f.Readdir(-1)
	f.Close()
	if err != nil {
		return nil, err
	}
	fi := make(fileInfoList, len(list))
	for i := range list {
		fi[i] = &list[i]
	}
	sort.Sort(fi)
	return fi, nil
}

type nopCloser struct {
	io.Reader
}

func (nopCloser) Close() os.Error { return nil }

// NopCloser returns a ReadCloser with a no-op Close method wrapping
// the provided Reader r.
func NopCloser(r io.Reader) io.ReadCloser {
	return nopCloser{r}
}

type devNull int

func (devNull) Write(p []byte) (int, os.Error) {
	return len(p), nil
}

var blackHole = make([]byte, 8192)

func (devNull) ReadFrom(r io.Reader) (n int64, err os.Error) {
	readSize := 0
	for {
		readSize, err = r.Read(blackHole)
		n += int64(readSize)
		if err != nil {
			if err == os.EOF {
				return n, nil
			}
			return
		}
	}
	panic("unreachable")
}

// Discard is an io.Writer on which all Write calls succeed
// without doing anything.
var Discard io.Writer = devNull(0)
<|endoftext|>


<commit_before><commit_msg>updated email to  for Prod settings<commit_after><|endoftext|>


<commit_before>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package websocket

import (
	"bufio"
	"fmt"
	"io"
	"net/http"
)

func newServerConn(rwc io.ReadWriteCloser, buf *bufio.ReadWriter, req *http.Request) (conn *Conn, err error) {
	config := new(Config)
	var hs serverHandshaker = &hybiServerHandshaker{Config: config}
	code, err := hs.ReadHandshake(buf.Reader, req)
	if err == ErrBadWebSocketVersion {
		fmt.Fprintf(buf, "HTTP/1.1 %03d %s\r\n", code, http.StatusText(code))
		fmt.Fprintf(buf, "Sec-WebSocket-Version: %s\r\n", SupportedProtocolVersion)
		buf.WriteString("\r\n")
		buf.WriteString(err.Error())
		buf.Flush()
		return
	}
	if err != nil {
		hs = &hixie76ServerHandshaker{Config: config}
		code, err = hs.ReadHandshake(buf.Reader, req)
	}
	if err != nil {
		hs = &hixie75ServerHandshaker{Config: config}
		code, err = hs.ReadHandshake(buf.Reader, req)
	}
	if err != nil {
		fmt.Fprintf(buf, "HTTP/1.1 %03d %s\r\n", code, http.StatusText(code))
		buf.WriteString("\r\n")
		buf.WriteString(err.Error())
		buf.Flush()
		return
	}
	config.Protocol = nil

	err = hs.AcceptHandshake(buf.Writer)
	if err != nil {
		code = http.StatusBadRequest
		fmt.Fprintf(buf, "HTTP/1.1 %03d %s\r\n", code, http.StatusText(code))
		buf.WriteString("\r\n")
		buf.Flush()
		return
	}
	conn = hs.NewServerConn(buf, rwc, req)
	return
}

/*
Handler is an interface to a WebSocket.

A trivial example server:

	package main

	import (
		"io"
		"net/http"
		"websocket"
	)

	// Echo the data received on the WebSocket.
	func EchoServer(ws *websocket.Conn) {
		io.Copy(ws, ws);
	}

	func main() {
		http.Handle("/echo", websocket.Handler(EchoServer));
		err := http.ListenAndServe(":12345", nil);
		if err != nil {
			panic("ListenAndServe: " + err.String())
		}
	}
*/
type Handler func(*Conn)

// ServeHTTP implements the http.Handler interface for a Web Socket
func (h Handler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	rwc, buf, err := w.(http.Hijacker).Hijack()
	if err != nil {
		panic("Hijack failed: " + err.Error())
		return
	}
	// The server should abort the WebSocket connection if it finds
	// the client did not send a handshake that matches with protocol
	// specification.
	defer rwc.Close()
	conn, err := newServerConn(rwc, buf, req)
	if err != nil {
		return
	}
	if conn == nil {
		panic("unepxected nil conn")
	}
	h(conn)
}
<commit_msg>websocket: fix a trivial example server<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package websocket

import (
	"bufio"
	"fmt"
	"io"
	"net/http"
)

func newServerConn(rwc io.ReadWriteCloser, buf *bufio.ReadWriter, req *http.Request) (conn *Conn, err error) {
	config := new(Config)
	var hs serverHandshaker = &hybiServerHandshaker{Config: config}
	code, err := hs.ReadHandshake(buf.Reader, req)
	if err == ErrBadWebSocketVersion {
		fmt.Fprintf(buf, "HTTP/1.1 %03d %s\r\n", code, http.StatusText(code))
		fmt.Fprintf(buf, "Sec-WebSocket-Version: %s\r\n", SupportedProtocolVersion)
		buf.WriteString("\r\n")
		buf.WriteString(err.Error())
		buf.Flush()
		return
	}
	if err != nil {
		hs = &hixie76ServerHandshaker{Config: config}
		code, err = hs.ReadHandshake(buf.Reader, req)
	}
	if err != nil {
		hs = &hixie75ServerHandshaker{Config: config}
		code, err = hs.ReadHandshake(buf.Reader, req)
	}
	if err != nil {
		fmt.Fprintf(buf, "HTTP/1.1 %03d %s\r\n", code, http.StatusText(code))
		buf.WriteString("\r\n")
		buf.WriteString(err.Error())
		buf.Flush()
		return
	}
	config.Protocol = nil

	err = hs.AcceptHandshake(buf.Writer)
	if err != nil {
		code = http.StatusBadRequest
		fmt.Fprintf(buf, "HTTP/1.1 %03d %s\r\n", code, http.StatusText(code))
		buf.WriteString("\r\n")
		buf.Flush()
		return
	}
	conn = hs.NewServerConn(buf, rwc, req)
	return
}

/*
Handler is an interface to a WebSocket.

A trivial example server:

	package main

	import (
		"io"
		"net/http"
		"websocket"
	)

	// Echo the data received on the WebSocket.
	func EchoServer(ws *websocket.Conn) {
		io.Copy(ws, ws);
	}

	func main() {
		http.Handle("/echo", websocket.Handler(EchoServer));
		err := http.ListenAndServe(":12345", nil);
		if err != nil {
			panic("ListenAndServe: " + err.Error())
		}
	}
*/
type Handler func(*Conn)

// ServeHTTP implements the http.Handler interface for a Web Socket
func (h Handler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	rwc, buf, err := w.(http.Hijacker).Hijack()
	if err != nil {
		panic("Hijack failed: " + err.Error())
		return
	}
	// The server should abort the WebSocket connection if it finds
	// the client did not send a handshake that matches with protocol
	// specification.
	defer rwc.Close()
	conn, err := newServerConn(rwc, buf, req)
	if err != nil {
		return
	}
	if conn == nil {
		panic("unepxected nil conn")
	}
	h(conn)
}
<|endoftext|>


<commit_before>// Copyright 2015 The Serviced Authors.
// 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.

// +build integration,root

package main_test

import (
	"fmt"
	"os/exec"
	"regexp"
	"strings"
	"testing"

	. "github.com/control-center/serviced/tools/serviced-storage"
	"github.com/control-center/serviced/volume"
	. "gopkg.in/check.v1"
)

const (
	size int64 = 100 * 1024 * 1024
)

func TestThinpool(t *testing.T) { TestingT(t) }

type ThinpoolSuite struct {
	devices []*volume.TemporaryDevice
}

func (s *ThinpoolSuite) TempDevice(c *C) *volume.TemporaryDevice {
	dev, err := volume.CreateTemporaryDevice(size)
	if err != nil {
		c.Fatal(err)
	}
	s.devices = append(s.devices, dev)
	return dev
}

var _ = Suite(&ThinpoolSuite{})

func (s *ThinpoolSuite) TearDownTest(c *C) {
	for _, dev := range s.devices {
		dev.Destroy()
	}
}

func (s *ThinpoolSuite) TestEnsurePhysicalDevices(c *C) {
	// Create a couple devices
	devices := []string{
		s.TempDevice(c).LoopDevice(),
		s.TempDevice(c).LoopDevice(),
	}

	// First create the pvs
	err := EnsurePhysicalDevices(devices)
	c.Assert(err, IsNil)

	defer exec.Command("pvremove", devices...).Run()

	// Should be idempotent
	err = EnsurePhysicalDevices(devices)
	c.Assert(err, IsNil)

	// Invalid devices should fail
	err = EnsurePhysicalDevices([]string{"/not/a/device"})
	c.Assert(err, Not(IsNil))
}

func (s *ThinpoolSuite) TestCreateVolumeGroup(c *C) {
	volumeGroup := "serviced-test-1"

	// Should fail if devices are invalid
	err := CreateVolumeGroup(volumeGroup, []string{"/dev/invalid1", "/dev/invalid2"})
	c.Assert(err, Not(IsNil))

	// Create a couple devices
	devices := []string{
		s.TempDevice(c).LoopDevice(),
		s.TempDevice(c).LoopDevice(),
	}

	// Ensure pvs
	err = EnsurePhysicalDevices(devices)
	c.Assert(err, IsNil)
	defer exec.Command("pvremove", devices...).Run()

	// Should succeed now
	err = CreateVolumeGroup(volumeGroup, devices)
	c.Assert(err, IsNil)
	defer exec.Command("vgremove", volumeGroup).Run()

}

func (s *ThinpoolSuite) TestCreateMetadataVolume(c *C) {
	volumeGroup := "serviced-test-2"

	// Should fail if the volume group is invalid
	_, err := CreateMetadataVolume(volumeGroup)
	c.Assert(err, Not(IsNil))

	// Create some devices and a vg
	devices := []string{
		s.TempDevice(c).LoopDevice(),
		s.TempDevice(c).LoopDevice(),
	}
	if err := EnsurePhysicalDevices(devices); err != nil {
		c.Fatal(err)
	}
	defer exec.Command("pvremove", devices...).Run()
	if err := CreateVolumeGroup(volumeGroup, devices); err != nil {
		c.Fatal(err)
	}
	defer exec.Command("vgremove", "-f", volumeGroup).Run()

	// Now the metadata volume should work fine
	mdvol, err := CreateMetadataVolume(volumeGroup)
	c.Assert(err, IsNil)
	defer exec.Command("lvremove", mdvol).Run()

	out, _ := exec.Command("lvs").CombinedOutput()
	c.Assert(strings.Contains(string(out), mdvol), Equals, true)
}

func (s *ThinpoolSuite) TestCreateDataVolume(c *C) {
	volumeGroup := "serviced-test-5"

	// Should fail if the volume group is invalid
	_, err := CreateDataVolume(volumeGroup)
	c.Assert(err, Not(IsNil))

	// Create some devices and a vg
	devices := []string{
		s.TempDevice(c).LoopDevice(),
		s.TempDevice(c).LoopDevice(),
	}
	if err := EnsurePhysicalDevices(devices); err != nil {
		c.Fatal(err)
	}
	if err := CreateVolumeGroup(volumeGroup, devices); err != nil {
		c.Fatal(err)
	}
	defer exec.Command("vgremove", "-f", volumeGroup).Run()

	// Now the data volume should work fine
	mdvol, err := CreateDataVolume(volumeGroup)
	c.Assert(err, IsNil)

	out, _ := exec.Command("lvs").CombinedOutput()
	c.Assert(strings.Contains(string(out), mdvol), Equals, true)
}

func (s *ThinpoolSuite) TestConvertToThinpool(c *C) {
	// Should fail if the VG/LV's are invalid
	err := ConvertToThinPool("NotAVolumeGroup", "NotALogicalVolume", "NotALogicalVolume")
	c.Assert(err, Not(IsNil))

	// Set up VG and LV's for test
	dev1 := s.TempDevice(c)
	dev2 := s.TempDevice(c)
	devices := []string{dev1.LoopDevice(), dev2.LoopDevice()}
	EnsurePhysicalDevices(devices)
	volumeGroup := "serviced-test-6"
	CreateVolumeGroup(volumeGroup, devices)
	defer exec.Command("vgremove", "-f", volumeGroup).Run()
	metadataVolume, _ := CreateMetadataVolume(volumeGroup)
	dataVolume, _ := CreateDataVolume(volumeGroup)

	err = ConvertToThinPool(volumeGroup, dataVolume, metadataVolume)
	c.Assert(err, IsNil)
	out, _ := exec.Command("lvs", "-o", "lv_name,lv_attr", "--noheading", "--nameprefixes",
		volumeGroup).CombinedOutput()

	regexName := regexp.MustCompile("LVM2_LV_NAME='(.+?)'")
	regexAttr := regexp.MustCompile("LVM2_LV_ATTR='(.+?)'")
	for _, line := range strings.Split(string(out), "n") {
		match := regexName.FindStringSubmatch(line)
		if len(match) != 2 || match[1] != dataVolume {
			continue
		}

		match = regexAttr.FindStringSubmatch(line)
		c.Assert(len(match), Equals, 2)
		attrs := match[1]
		volumeType := attrs[0]
		// Per lvs man page, volume type of "t" implies thin pool
		c.Assert(volumeType, Equals, "t"[0])
		return
	}
	// Did not find thinpool
	c.Assert(nil, Not(IsNil))
}

func (s *ThinpoolSuite) TestGetInfoForLogicalVolume(c *C) {
	// Set up thin pool for test
	dev1 := s.TempDevice(c)
	dev2 := s.TempDevice(c)
	devices := []string{dev1.LoopDevice(), dev2.LoopDevice()}
	EnsurePhysicalDevices(devices)
	volumeGroup := "serviced-test-3"
	CreateVolumeGroup(volumeGroup, devices)
	defer exec.Command("vgremove", "-f", volumeGroup).Run()
	metadataVolume, _ := CreateMetadataVolume(volumeGroup)
	dataVolume, _ := CreateDataVolume(volumeGroup)
	ConvertToThinPool(volumeGroup, dataVolume, metadataVolume)

	// Should fail if invalid logical volume
	_, err := GetInfoForLogicalVolume("/not/a/logical/volume")
	c.Assert(err, Not(IsNil))

	// Should work for valid params
	lvInfo, err := GetInfoForLogicalVolume(dataVolume)
	c.Assert(err, IsNil)
	c.Assert(lvInfo.Name, Equals, dataVolume)
	c.Assert(lvInfo.KernelMajor, Not(Equals), 0)
	c.Assert(lvInfo.KernelMinor, Not(Equals), 0)
}

func (s *ThinpoolSuite) TestGetThinpoolName(c *C) {
	// Should fail with invalid logical volume
	lvInfo := LogicalVolumeInfo{}
	_, err := lvInfo.GetThinpoolName()
	c.Assert(err, Not(IsNil))

	// Set up thin pool for test
	dev1 := s.TempDevice(c)
	dev2 := s.TempDevice(c)
	devices := []string{dev1.LoopDevice(), dev2.LoopDevice()}
	EnsurePhysicalDevices(devices)
	volumeGroup := "serviced-test-4"
	CreateVolumeGroup(volumeGroup, devices)
	defer exec.Command("vgremove", "-f", volumeGroup).Run()
	metadataVolume, _ := CreateMetadataVolume(volumeGroup)
	dataVolume, _ := CreateDataVolume(volumeGroup)
	ConvertToThinPool(volumeGroup, dataVolume, metadataVolume)
	lvInfo, err = GetInfoForLogicalVolume(dataVolume)

	// Should work for valid params
	thinpoolName, err := lvInfo.GetThinpoolName()
	c.Assert(err, IsNil)
	c.Assert(thinpoolName, Not(Equals), "")

	//TODO: How can we test that the thinpoolName actually refers to the proper device?
}
<commit_msg>Fix extra import<commit_after>// Copyright 2015 The Serviced Authors.
// 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.

// +build integration,root

package main_test

import (
	"os/exec"
	"regexp"
	"strings"
	"testing"

	. "github.com/control-center/serviced/tools/serviced-storage"
	"github.com/control-center/serviced/volume"
	. "gopkg.in/check.v1"
)

const (
	size int64 = 100 * 1024 * 1024
)

func TestThinpool(t *testing.T) { TestingT(t) }

type ThinpoolSuite struct {
	devices []*volume.TemporaryDevice
}

func (s *ThinpoolSuite) TempDevice(c *C) *volume.TemporaryDevice {
	dev, err := volume.CreateTemporaryDevice(size)
	if err != nil {
		c.Fatal(err)
	}
	s.devices = append(s.devices, dev)
	return dev
}

var _ = Suite(&ThinpoolSuite{})

func (s *ThinpoolSuite) TearDownTest(c *C) {
	for _, dev := range s.devices {
		dev.Destroy()
	}
}

func (s *ThinpoolSuite) TestEnsurePhysicalDevices(c *C) {
	// Create a couple devices
	devices := []string{
		s.TempDevice(c).LoopDevice(),
		s.TempDevice(c).LoopDevice(),
	}

	// First create the pvs
	err := EnsurePhysicalDevices(devices)
	c.Assert(err, IsNil)

	defer exec.Command("pvremove", devices...).Run()

	// Should be idempotent
	err = EnsurePhysicalDevices(devices)
	c.Assert(err, IsNil)

	// Invalid devices should fail
	err = EnsurePhysicalDevices([]string{"/not/a/device"})
	c.Assert(err, Not(IsNil))
}

func (s *ThinpoolSuite) TestCreateVolumeGroup(c *C) {
	volumeGroup := "serviced-test-1"

	// Should fail if devices are invalid
	err := CreateVolumeGroup(volumeGroup, []string{"/dev/invalid1", "/dev/invalid2"})
	c.Assert(err, Not(IsNil))

	// Create a couple devices
	devices := []string{
		s.TempDevice(c).LoopDevice(),
		s.TempDevice(c).LoopDevice(),
	}

	// Ensure pvs
	err = EnsurePhysicalDevices(devices)
	c.Assert(err, IsNil)
	defer exec.Command("pvremove", devices...).Run()

	// Should succeed now
	err = CreateVolumeGroup(volumeGroup, devices)
	c.Assert(err, IsNil)
	defer exec.Command("vgremove", volumeGroup).Run()

}

func (s *ThinpoolSuite) TestCreateMetadataVolume(c *C) {
	volumeGroup := "serviced-test-2"

	// Should fail if the volume group is invalid
	_, err := CreateMetadataVolume(volumeGroup)
	c.Assert(err, Not(IsNil))

	// Create some devices and a vg
	devices := []string{
		s.TempDevice(c).LoopDevice(),
		s.TempDevice(c).LoopDevice(),
	}
	if err := EnsurePhysicalDevices(devices); err != nil {
		c.Fatal(err)
	}
	defer exec.Command("pvremove", devices...).Run()
	if err := CreateVolumeGroup(volumeGroup, devices); err != nil {
		c.Fatal(err)
	}
	defer exec.Command("vgremove", "-f", volumeGroup).Run()

	// Now the metadata volume should work fine
	mdvol, err := CreateMetadataVolume(volumeGroup)
	c.Assert(err, IsNil)
	defer exec.Command("lvremove", mdvol).Run()

	out, _ := exec.Command("lvs").CombinedOutput()
	c.Assert(strings.Contains(string(out), mdvol), Equals, true)
}

func (s *ThinpoolSuite) TestCreateDataVolume(c *C) {
	volumeGroup := "serviced-test-5"

	// Should fail if the volume group is invalid
	_, err := CreateDataVolume(volumeGroup)
	c.Assert(err, Not(IsNil))

	// Create some devices and a vg
	devices := []string{
		s.TempDevice(c).LoopDevice(),
		s.TempDevice(c).LoopDevice(),
	}
	if err := EnsurePhysicalDevices(devices); err != nil {
		c.Fatal(err)
	}
	if err := CreateVolumeGroup(volumeGroup, devices); err != nil {
		c.Fatal(err)
	}
	defer exec.Command("vgremove", "-f", volumeGroup).Run()

	// Now the data volume should work fine
	mdvol, err := CreateDataVolume(volumeGroup)
	c.Assert(err, IsNil)

	out, _ := exec.Command("lvs").CombinedOutput()
	c.Assert(strings.Contains(string(out), mdvol), Equals, true)
}

func (s *ThinpoolSuite) TestConvertToThinpool(c *C) {
	// Should fail if the VG/LV's are invalid
	err := ConvertToThinPool("NotAVolumeGroup", "NotALogicalVolume", "NotALogicalVolume")
	c.Assert(err, Not(IsNil))

	// Set up VG and LV's for test
	dev1 := s.TempDevice(c)
	dev2 := s.TempDevice(c)
	devices := []string{dev1.LoopDevice(), dev2.LoopDevice()}
	EnsurePhysicalDevices(devices)
	volumeGroup := "serviced-test-6"
	CreateVolumeGroup(volumeGroup, devices)
	defer exec.Command("vgremove", "-f", volumeGroup).Run()
	metadataVolume, _ := CreateMetadataVolume(volumeGroup)
	dataVolume, _ := CreateDataVolume(volumeGroup)

	err = ConvertToThinPool(volumeGroup, dataVolume, metadataVolume)
	c.Assert(err, IsNil)
	out, _ := exec.Command("lvs", "-o", "lv_name,lv_attr", "--noheading", "--nameprefixes",
		volumeGroup).CombinedOutput()

	regexName := regexp.MustCompile("LVM2_LV_NAME='(.+?)'")
	regexAttr := regexp.MustCompile("LVM2_LV_ATTR='(.+?)'")
	for _, line := range strings.Split(string(out), "n") {
		match := regexName.FindStringSubmatch(line)
		if len(match) != 2 || match[1] != dataVolume {
			continue
		}

		match = regexAttr.FindStringSubmatch(line)
		c.Assert(len(match), Equals, 2)
		attrs := match[1]
		volumeType := attrs[0]
		// Per lvs man page, volume type of "t" implies thin pool
		c.Assert(volumeType, Equals, "t"[0])
		return
	}
	// Did not find thinpool
	c.Assert(nil, Not(IsNil))
}

func (s *ThinpoolSuite) TestGetInfoForLogicalVolume(c *C) {
	// Set up thin pool for test
	dev1 := s.TempDevice(c)
	dev2 := s.TempDevice(c)
	devices := []string{dev1.LoopDevice(), dev2.LoopDevice()}
	EnsurePhysicalDevices(devices)
	volumeGroup := "serviced-test-3"
	CreateVolumeGroup(volumeGroup, devices)
	defer exec.Command("vgremove", "-f", volumeGroup).Run()
	metadataVolume, _ := CreateMetadataVolume(volumeGroup)
	dataVolume, _ := CreateDataVolume(volumeGroup)
	ConvertToThinPool(volumeGroup, dataVolume, metadataVolume)

	// Should fail if invalid logical volume
	_, err := GetInfoForLogicalVolume("/not/a/logical/volume")
	c.Assert(err, Not(IsNil))

	// Should work for valid params
	lvInfo, err := GetInfoForLogicalVolume(dataVolume)
	c.Assert(err, IsNil)
	c.Assert(lvInfo.Name, Equals, dataVolume)
	c.Assert(lvInfo.KernelMajor, Not(Equals), 0)
	c.Assert(lvInfo.KernelMinor, Not(Equals), 0)
}

func (s *ThinpoolSuite) TestGetThinpoolName(c *C) {
	// Should fail with invalid logical volume
	lvInfo := LogicalVolumeInfo{}
	_, err := lvInfo.GetThinpoolName()
	c.Assert(err, Not(IsNil))

	// Set up thin pool for test
	dev1 := s.TempDevice(c)
	dev2 := s.TempDevice(c)
	devices := []string{dev1.LoopDevice(), dev2.LoopDevice()}
	EnsurePhysicalDevices(devices)
	volumeGroup := "serviced-test-4"
	CreateVolumeGroup(volumeGroup, devices)
	defer exec.Command("vgremove", "-f", volumeGroup).Run()
	metadataVolume, _ := CreateMetadataVolume(volumeGroup)
	dataVolume, _ := CreateDataVolume(volumeGroup)
	ConvertToThinPool(volumeGroup, dataVolume, metadataVolume)
	lvInfo, err = GetInfoForLogicalVolume(dataVolume)

	// Should work for valid params
	thinpoolName, err := lvInfo.GetThinpoolName()
	c.Assert(err, IsNil)
	c.Assert(thinpoolName, Not(Equals), "")

	//TODO: How can we test that the thinpoolName actually refers to the proper device?
}
<|endoftext|>


<commit_before>//+build ignore

package main

import (
	"bytes"
	"errors"
	"io"
	"io/ioutil"
	"log"
	"net/http"

	"golang.org/x/net/html"
	"layeh.com/radius/dictionary"
	"layeh.com/radius/dictionarygen"
)

const (
	Init = iota
	FoundPre
	Discarding
)

func main() {
	resp, err := http.Get(`https://wiki.mikrotik.com/wiki/Manual:RADIUS_Client/vendor_dictionary`)
	if err != nil {
		log.Fatal(err)
	}
	defer resp.Body.Close()

	// the dictionary is inside a <pre> tag, so... tokenize it out
	var extractedBody bytes.Buffer
	var state int

	tokenizer := html.NewTokenizer(resp.Body)
	for {
		tokenType := tokenizer.Next()
		if tokenType == html.ErrorToken {
			err := tokenizer.Err()
			if err == io.EOF {
				break
			} else {
				log.Fatal(err)
			}
		}

		switch state {
		case Init:
			if tokenType == html.StartTagToken {
				token := tokenizer.Token()
				if token.Data == "pre" {
					state = FoundPre
				}
			}

		case FoundPre:
			if tokenType == html.TextToken {
				extractedBody.WriteString(tokenizer.Token().Data)
			} else {
				state = Discarding
			}
		}
	}

	parser := dictionary.Parser{
		Opener: restrictedOpener{
			"main.dictionary": extractedBody.Bytes(),
		},
	}
	dict, err := parser.ParseFile("main.dictionary")
	if err != nil {
		log.Fatal(err)
	}

	if len(dict.Vendors) != 1 || dict.Vendors[0].Number != 14988 {
		log.Fatal("expected dictionary to contain vendor 14988")
	}

	gen := dictionarygen.Generator{
		Package: "mikrotik",
	}
	generated, err := gen.Generate(dict)
	if err != nil {
		log.Fatal(err)
	}

	if err := ioutil.WriteFile("generated.go", generated, 0644); err != nil {
		log.Fatal(err)
	}
}

type restrictedOpener map[string][]byte

func (r restrictedOpener) OpenFile(name string) (dictionary.File, error) {
	contents, ok := r[name]
	if !ok {
		return nil, errors.New("unknown file " + name)
	}
	return &restrictedFile{
		Reader:    bytes.NewReader(contents),
		NameValue: name,
	}, nil
}

type restrictedFile struct {
	io.Reader
	NameValue string
}

func (r *restrictedFile) Name() string {
	return r.NameValue
}

func (r *restrictedFile) Close() error {
	return nil
}
<commit_msg>vendors/mikrotik: remove golang.org/x/net/html dependency<commit_after>//+build ignore

package main

import (
	"bytes"
	"encoding/json"
	"errors"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"regexp"

	"layeh.com/radius/dictionary"
	"layeh.com/radius/dictionarygen"
)

type ParseResponse struct {
	Text map[string]string `json:"text"`
}

type APIResponse struct {
	Parse *ParseResponse `json:"parse"`
}

var dictRe = regexp.MustCompile(`(?ms)^<pre>$(.*)^</pre>$`)

func main() {
	resp, err := http.Get(`https://wiki.mikrotik.com/api.php?page=Manual:RADIUS_Client/vendor_dictionary&action=parse&format=json`)
	if err != nil {
		log.Fatal(err)
	}
	defer resp.Body.Close()

	decoder := json.NewDecoder(resp.Body)
	var apiResponse APIResponse
	if err := decoder.Decode(&apiResponse); err != nil {
		log.Fatal(err)
	}

	pageContents := apiResponse.Parse.Text["*"]
	dictContents := dictRe.FindStringSubmatch(pageContents)[1]

	parser := dictionary.Parser{
		Opener: restrictedOpener{
			"main.dictionary": []byte(dictContents),
		},
	}
	dict, err := parser.ParseFile("main.dictionary")
	if err != nil {
		log.Fatal(err)
	}

	if len(dict.Vendors) != 1 || dict.Vendors[0].Number != 14988 {
		log.Fatal("expected dictionary to contain vendor 14988")
	}

	gen := dictionarygen.Generator{
		Package: "mikrotik",
	}
	generated, err := gen.Generate(dict)
	if err != nil {
		log.Fatal(err)
	}

	if err := ioutil.WriteFile("generated.go", generated, 0644); err != nil {
		log.Fatal(err)
	}
}

type restrictedOpener map[string][]byte

func (r restrictedOpener) OpenFile(name string) (dictionary.File, error) {
	contents, ok := r[name]
	if !ok {
		return nil, errors.New("unknown file " + name)
	}
	return &restrictedFile{
		Reader:    bytes.NewReader(contents),
		NameValue: name,
	}, nil
}

type restrictedFile struct {
	io.Reader
	NameValue string
}

func (r *restrictedFile) Name() string {
	return r.NameValue
}

func (r *restrictedFile) Close() error {
	return nil
}
<|endoftext|>


<commit_before>package presilo

import (
	"bytes"
	//"fmt"
	//"strings"
)

/*
  Generates valid Java code for a given schema.
*/
func GenerateJava(schema *ObjectSchema, module string) string {

	var ret bytes.Buffer

	ret.WriteString("package " + module)
	ret.WriteString("\n")
	ret.WriteString(generateJavaImports(schema))
	ret.WriteString("\n")
	ret.WriteString(generateJavaTypeDeclaration(schema))
  ret.WriteString("\n")
  ret.WriteString(generateJavaVariables(schema))
	ret.WriteString("\n")
	ret.WriteString(generateJavaConstructor(schema))
	ret.WriteString("\n")
	ret.WriteString(generateJavaFunctions(schema))
	ret.WriteString("\n")

	return ret.String()
}

func generateJavaImports(schema *ObjectSchema) string {

  var ret bytes.Buffer
  return ret.String()
}

func generateJavaTypeDeclaration(schema *ObjectSchema) string {

  var ret bytes.Buffer
  return ret.String()
}

func generateJavaVariables(schema *ObjectSchema) string {

  var ret bytes.Buffer
  return ret.String()
}

func generateJavaConstructor(schema *ObjectSchema) string {

  var ret bytes.Buffer
  return ret.String()
}

func generateJavaFunctions(schema *ObjectSchema) string {

  var ret bytes.Buffer
  return ret.String()
}
<commit_msg>Implemented java signature and ctor<commit_after>package presilo

import (
	"bytes"
	"fmt"
	"strings"
)

/*
  Generates valid Java code for a given schema.
*/
func GenerateJava(schema *ObjectSchema, module string) string {

	var ret bytes.Buffer

	ret.WriteString("package " + module)
	ret.WriteString("\n")
	ret.WriteString(generateJavaImports(schema))
	ret.WriteString("\n")
	ret.WriteString(generateJavaTypeDeclaration(schema))
	ret.WriteString("\n")
	ret.WriteString(generateJavaConstructor(schema))
	ret.WriteString("\n")
	ret.WriteString(generateJavaFunctions(schema))
	ret.WriteString("\n}\n")

	return ret.String()
}

func generateJavaImports(schema *ObjectSchema) string {

  // import regex if we need it
  if(containsRegexpMatch(schema)) {
    return "import java.util.regex.Pattern;\n\n"
  }
  return ""
}

func generateJavaTypeDeclaration(schema *ObjectSchema) string {

  var ret bytes.Buffer
  var subschema TypeSchema
  var propertyName string
  var toWrite string

  toWrite = fmt.Sprintf("public class %s\n{\n", ToCamelCase(schema.Title))
  ret.WriteString(toWrite)

  for propertyName, subschema = range schema.Properties {

    propertyName = ToJavaCase(propertyName)
    toWrite = fmt.Sprintf("\n\tprotected %s %s;", generateJavaTypeForSchema(subschema), propertyName)
    ret.WriteString(toWrite)
  }

  return ret.String()
}

func generateJavaConstructor(schema *ObjectSchema) string {

  var ret bytes.Buffer
  var subschema TypeSchema
  var declarations, setters []string
  var propertyName string
  var toWrite string

  toWrite = fmt.Sprintf("\n\tpublic %s(", ToCamelCase(schema.Title))
  ret.WriteString(toWrite)

  for _, propertyName = range schema.RequiredProperties {

    subschema = schema.Properties[propertyName]
    propertyName = ToJavaCase(propertyName)

    toWrite = fmt.Sprintf("%s %s", generateJavaTypeForSchema(subschema), propertyName)
    declarations = append(declarations, toWrite)

    toWrite = fmt.Sprintf("\n\t\tset%s(%s);", ToCamelCase(propertyName), propertyName)
    setters = append(setters, toWrite)
  }

  toWrite = strings.Join(declarations, ",")
  ret.WriteString(toWrite)
  ret.WriteString(")\n\t{")

  for _, setter := range setters {
    ret.WriteString(setter)
  }

  ret.WriteString("\n\t}\n")
  return ret.String()
}

func generateJavaFunctions(schema *ObjectSchema) string {

  var ret bytes.Buffer
  return ret.String()
}

func generateJavaTypeForSchema(subschema TypeSchema) string {
  return "String"
}
<|endoftext|>


<commit_before>// Copyright (c) 2016-2017 Daniel Oaks <daniel@danieloaks.net>
// released under the MIT license

package irc

import (
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"strconv"
	"strings"
	"time"

	"github.com/DanielOaks/girc-go/ircmsg"
	"github.com/tidwall/buntdb"
)

var (
	errAccountCreation     = errors.New("Account could not be created")
	errCertfpAlreadyExists = errors.New("An account already exists with your certificate")
)

// AccountRegistration manages the registration of accounts.
type AccountRegistration struct {
	Enabled                bool
	EnabledCallbacks       []string
	EnabledCredentialTypes []string
}

// AccountCredentials stores the various methods for verifying accounts.
type AccountCredentials struct {
	PassphraseSalt []byte
	PassphraseHash []byte
	Certificate    string // fingerprint
}

// NewAccountRegistration returns a new AccountRegistration, configured correctly.
func NewAccountRegistration(config AccountRegistrationConfig) (accountReg AccountRegistration) {
	if config.Enabled {
		accountReg.Enabled = true
		for _, name := range config.EnabledCallbacks {
			// we store "none" as "*" internally
			if name == "none" {
				name = "*"
			}
			accountReg.EnabledCallbacks = append(accountReg.EnabledCallbacks, name)
		}
		// no need to make this configurable, right now at least
		accountReg.EnabledCredentialTypes = []string{
			"passphrase",
			"certfp",
		}
	}
	return accountReg
}

// regHandler parses the REG command.
func regHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
	subcommand := strings.ToLower(msg.Params[0])

	if subcommand == "create" {
		return regCreateHandler(server, client, msg)
	} else if subcommand == "verify" {
		client.Notice("Parsing VERIFY")
	} else {
		client.Send(nil, server.name, ERR_UNKNOWNERROR, client.nick, "REG", msg.Params[0], "Unknown subcommand")
	}

	return false
}

// removeFailedRegCreateData removes the data created by REG CREATE if the account creation fails early.
func removeFailedRegCreateData(store *buntdb.DB, account string) {
	// error is ignored here, we can't do much about it anyways
	store.Update(func(tx *buntdb.Tx) error {
		tx.Delete(fmt.Sprintf(keyAccountExists, account))
		tx.Delete(fmt.Sprintf(keyAccountRegTime, account))
		tx.Delete(fmt.Sprintf(keyAccountCredentials, account))

		return nil
	})
}

// regCreateHandler parses the REG CREATE command.
func regCreateHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
	// get and sanitise account name
	account := strings.TrimSpace(msg.Params[1])
	casefoldedAccount, err := CasefoldName(account)
	// probably don't need explicit check for "*" here... but let's do it anyway just to make sure
	if err != nil || msg.Params[1] == "*" {
		client.Send(nil, server.name, ERR_REG_UNSPECIFIED_ERROR, client.nick, account, "Account name is not valid")
		return false
	}

	// check whether account exists
	// do it all in one write tx to prevent races
	err = server.store.Update(func(tx *buntdb.Tx) error {
		accountKey := fmt.Sprintf(keyAccountExists, casefoldedAccount)

		_, err := tx.Get(accountKey)
		if err != buntdb.ErrNotFound {
			//TODO(dan): if account verified key doesn't exist account is not verified, calc the maximum time without verification and expire and continue if need be
			client.Send(nil, server.name, ERR_ACCOUNT_ALREADY_EXISTS, client.nick, account, "Account already exists")
			return errAccountCreation
		}

		registeredTimeKey := fmt.Sprintf(keyAccountRegTime, casefoldedAccount)

		tx.Set(accountKey, "1", nil)
		tx.Set(fmt.Sprintf(keyAccountName, casefoldedAccount), account, nil)
		tx.Set(registeredTimeKey, strconv.FormatInt(time.Now().Unix(), 10), nil)
		return nil
	})

	// account could not be created and relevant numerics have been dispatched, abort
	if err != nil {
		if err != errAccountCreation {
			client.Send(nil, server.name, ERR_UNKNOWNERROR, client.nick, "REG", "CREATE", "Could not register")
			log.Println("Could not save registration initial data:", err.Error())
		}
		return false
	}

	// account didn't already exist, continue with account creation and dispatching verification (if required)
	callback := strings.ToLower(msg.Params[2])
	var callbackNamespace, callbackValue string

	if callback == "*" {
		callbackNamespace = "*"
	} else if strings.Contains(callback, ":") {
		callbackValues := strings.SplitN(callback, ":", 2)
		callbackNamespace, callbackValue = callbackValues[0], callbackValues[1]
	} else {
		callbackNamespace = server.accountRegistration.EnabledCallbacks[0]
		callbackValue = callback
	}

	// ensure the callback namespace is valid
	// need to search callback list, maybe look at using a map later?
	var callbackValid bool
	for _, name := range server.accountRegistration.EnabledCallbacks {
		if callbackNamespace == name {
			callbackValid = true
		}
	}

	if !callbackValid {
		client.Send(nil, server.name, ERR_REG_INVALID_CALLBACK, client.nick, account, callbackNamespace, "Callback namespace is not supported")
		removeFailedRegCreateData(server.store, casefoldedAccount)
		return false
	}

	// get credential type/value
	var credentialType, credentialValue string

	if len(msg.Params) > 4 {
		credentialType = strings.ToLower(msg.Params[3])
		credentialValue = msg.Params[4]
	} else if len(msg.Params) == 4 {
		credentialType = "passphrase" // default from the spec
		credentialValue = msg.Params[3]
	} else {
		client.Send(nil, server.name, ERR_NEEDMOREPARAMS, client.nick, msg.Command, "Not enough parameters")
		removeFailedRegCreateData(server.store, casefoldedAccount)
		return false
	}

	// ensure the credential type is valid
	var credentialValid bool
	for _, name := range server.accountRegistration.EnabledCredentialTypes {
		if credentialType == name {
			credentialValid = true
		}
	}
	if credentialType == "certfp" && client.certfp == "" {
		client.Send(nil, server.name, ERR_REG_INVALID_CRED_TYPE, client.nick, credentialType, callbackNamespace, "You are not using a certificate")
		removeFailedRegCreateData(server.store, casefoldedAccount)
		return false
	}

	if !credentialValid {
		client.Send(nil, server.name, ERR_REG_INVALID_CRED_TYPE, client.nick, credentialType, callbackNamespace, "Credential type is not supported")
		removeFailedRegCreateData(server.store, casefoldedAccount)
		return false
	}

	// store details
	err = server.store.Update(func(tx *buntdb.Tx) error {
		// certfp special lookup key
		if credentialType == "certfp" {
			assembledKeyCertToAccount := fmt.Sprintf(keyCertToAccount, client.certfp)

			// make sure certfp doesn't already exist because that'd be silly
			_, err := tx.Get(assembledKeyCertToAccount)
			if err != buntdb.ErrNotFound {
				return errCertfpAlreadyExists
			}

			tx.Set(assembledKeyCertToAccount, casefoldedAccount, nil)
		}

		// make creds
		var creds AccountCredentials

		// always set passphrase salt
		creds.PassphraseSalt, err = NewSalt()
		if err != nil {
			return fmt.Errorf("Could not create passphrase salt: %s", err.Error())
		}

		if credentialType == "certfp" {
			creds.Certificate = client.certfp
		} else if credentialType == "passphrase" {
			creds.PassphraseHash, err = server.passwords.GenerateFromPassword(creds.PassphraseSalt, credentialValue)
			if err != nil {
				return fmt.Errorf("Could not hash password: %s", err)
			}
		}
		credText, err := json.Marshal(creds)
		if err != nil {
			return fmt.Errorf("Could not marshal creds: %s", err)
		}
		tx.Set(fmt.Sprintf(keyAccountCredentials, account), string(credText), nil)

		return nil
	})

	// details could not be stored and relevant numerics have been dispatched, abort
	if err != nil {
		errMsg := "Could not register"
		if err == errCertfpAlreadyExists {
			errMsg = "An account already exists for your certificate fingerprint"
		}
		client.Send(nil, server.name, ERR_UNKNOWNERROR, client.nick, "REG", "CREATE", errMsg)
		log.Println("Could not save registration creds:", err.Error())
		removeFailedRegCreateData(server.store, casefoldedAccount)
		return false
	}

	// automatically complete registration
	if callbackNamespace == "*" {
		err = server.store.Update(func(tx *buntdb.Tx) error {
			tx.Set(fmt.Sprintf(keyAccountVerified, casefoldedAccount), "1", nil)

			// load acct info inside store tx
			account := ClientAccount{
				Name:         strings.TrimSpace(msg.Params[1]),
				RegisteredAt: time.Now(),
				Clients:      []*Client{client},
			}
			//TODO(dan): Consider creating ircd-wide account adding/removing/affecting lock for protecting access to these sorts of variables
			server.accounts[casefoldedAccount] = &account
			client.account = &account

			client.Send(nil, server.name, RPL_REGISTRATION_SUCCESS, client.nick, account.Name, "Account created")
			client.Send(nil, server.name, RPL_LOGGEDIN, client.nick, client.nickMaskString, account.Name, fmt.Sprintf("You are now logged in as %s", account.Name))
			client.Send(nil, server.name, RPL_SASLSUCCESS, client.nick, "Authentication successful")
			return nil
		})
		if err != nil {
			client.Send(nil, server.name, ERR_UNKNOWNERROR, client.nick, "REG", "CREATE", "Could not register")
			log.Println("Could not save verification confirmation (*):", err.Error())
			removeFailedRegCreateData(server.store, casefoldedAccount)
			return false
		}

		return false
	}

	// dispatch callback
	client.Notice(fmt.Sprintf("We should dispatch a real callback here to %s:%s", callbackNamespace, callbackValue))

	return false
}
<commit_msg>accountreg: Fix crash<commit_after>// Copyright (c) 2016-2017 Daniel Oaks <daniel@danieloaks.net>
// released under the MIT license

package irc

import (
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"strconv"
	"strings"
	"time"

	"github.com/DanielOaks/girc-go/ircmsg"
	"github.com/tidwall/buntdb"
)

var (
	errAccountCreation     = errors.New("Account could not be created")
	errCertfpAlreadyExists = errors.New("An account already exists with your certificate")
)

// AccountRegistration manages the registration of accounts.
type AccountRegistration struct {
	Enabled                bool
	EnabledCallbacks       []string
	EnabledCredentialTypes []string
}

// AccountCredentials stores the various methods for verifying accounts.
type AccountCredentials struct {
	PassphraseSalt []byte
	PassphraseHash []byte
	Certificate    string // fingerprint
}

// NewAccountRegistration returns a new AccountRegistration, configured correctly.
func NewAccountRegistration(config AccountRegistrationConfig) (accountReg AccountRegistration) {
	if config.Enabled {
		accountReg.Enabled = true
		for _, name := range config.EnabledCallbacks {
			// we store "none" as "*" internally
			if name == "none" {
				name = "*"
			}
			accountReg.EnabledCallbacks = append(accountReg.EnabledCallbacks, name)
		}
		// no need to make this configurable, right now at least
		accountReg.EnabledCredentialTypes = []string{
			"passphrase",
			"certfp",
		}
	}
	return accountReg
}

// regHandler parses the REG command.
func regHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
	subcommand := strings.ToLower(msg.Params[0])

	if subcommand == "create" {
		return regCreateHandler(server, client, msg)
	} else if subcommand == "verify" {
		client.Notice("Parsing VERIFY")
	} else {
		client.Send(nil, server.name, ERR_UNKNOWNERROR, client.nick, "REG", msg.Params[0], "Unknown subcommand")
	}

	return false
}

// removeFailedRegCreateData removes the data created by REG CREATE if the account creation fails early.
func removeFailedRegCreateData(store *buntdb.DB, account string) {
	// error is ignored here, we can't do much about it anyways
	store.Update(func(tx *buntdb.Tx) error {
		tx.Delete(fmt.Sprintf(keyAccountExists, account))
		tx.Delete(fmt.Sprintf(keyAccountRegTime, account))
		tx.Delete(fmt.Sprintf(keyAccountCredentials, account))

		return nil
	})
}

// regCreateHandler parses the REG CREATE command.
func regCreateHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
	// make sure reg is enabled
	if !server.accountRegistration.Enabled {
		client.Send(nil, server.name, ERR_REG_UNSPECIFIED_ERROR, client.nick, "*", "Account registration is disabled")
		return false
	}

	// get and sanitise account name
	account := strings.TrimSpace(msg.Params[1])
	casefoldedAccount, err := CasefoldName(account)
	// probably don't need explicit check for "*" here... but let's do it anyway just to make sure
	if err != nil || msg.Params[1] == "*" {
		client.Send(nil, server.name, ERR_REG_UNSPECIFIED_ERROR, client.nick, account, "Account name is not valid")
		return false
	}

	// check whether account exists
	// do it all in one write tx to prevent races
	err = server.store.Update(func(tx *buntdb.Tx) error {
		accountKey := fmt.Sprintf(keyAccountExists, casefoldedAccount)

		_, err := tx.Get(accountKey)
		if err != buntdb.ErrNotFound {
			//TODO(dan): if account verified key doesn't exist account is not verified, calc the maximum time without verification and expire and continue if need be
			client.Send(nil, server.name, ERR_ACCOUNT_ALREADY_EXISTS, client.nick, account, "Account already exists")
			return errAccountCreation
		}

		registeredTimeKey := fmt.Sprintf(keyAccountRegTime, casefoldedAccount)

		tx.Set(accountKey, "1", nil)
		tx.Set(fmt.Sprintf(keyAccountName, casefoldedAccount), account, nil)
		tx.Set(registeredTimeKey, strconv.FormatInt(time.Now().Unix(), 10), nil)
		return nil
	})

	// account could not be created and relevant numerics have been dispatched, abort
	if err != nil {
		if err != errAccountCreation {
			client.Send(nil, server.name, ERR_UNKNOWNERROR, client.nick, "REG", "CREATE", "Could not register")
			log.Println("Could not save registration initial data:", err.Error())
		}
		return false
	}

	// account didn't already exist, continue with account creation and dispatching verification (if required)
	callback := strings.ToLower(msg.Params[2])
	var callbackNamespace, callbackValue string

	if callback == "*" {
		callbackNamespace = "*"
	} else if strings.Contains(callback, ":") {
		callbackValues := strings.SplitN(callback, ":", 2)
		callbackNamespace, callbackValue = callbackValues[0], callbackValues[1]
	} else {
		callbackNamespace = server.accountRegistration.EnabledCallbacks[0]
		callbackValue = callback
	}

	// ensure the callback namespace is valid
	// need to search callback list, maybe look at using a map later?
	var callbackValid bool
	for _, name := range server.accountRegistration.EnabledCallbacks {
		if callbackNamespace == name {
			callbackValid = true
		}
	}

	if !callbackValid {
		client.Send(nil, server.name, ERR_REG_INVALID_CALLBACK, client.nick, account, callbackNamespace, "Callback namespace is not supported")
		removeFailedRegCreateData(server.store, casefoldedAccount)
		return false
	}

	// get credential type/value
	var credentialType, credentialValue string

	if len(msg.Params) > 4 {
		credentialType = strings.ToLower(msg.Params[3])
		credentialValue = msg.Params[4]
	} else if len(msg.Params) == 4 {
		credentialType = "passphrase" // default from the spec
		credentialValue = msg.Params[3]
	} else {
		client.Send(nil, server.name, ERR_NEEDMOREPARAMS, client.nick, msg.Command, "Not enough parameters")
		removeFailedRegCreateData(server.store, casefoldedAccount)
		return false
	}

	// ensure the credential type is valid
	var credentialValid bool
	for _, name := range server.accountRegistration.EnabledCredentialTypes {
		if credentialType == name {
			credentialValid = true
		}
	}
	if credentialType == "certfp" && client.certfp == "" {
		client.Send(nil, server.name, ERR_REG_INVALID_CRED_TYPE, client.nick, credentialType, callbackNamespace, "You are not using a certificate")
		removeFailedRegCreateData(server.store, casefoldedAccount)
		return false
	}

	if !credentialValid {
		client.Send(nil, server.name, ERR_REG_INVALID_CRED_TYPE, client.nick, credentialType, callbackNamespace, "Credential type is not supported")
		removeFailedRegCreateData(server.store, casefoldedAccount)
		return false
	}

	// store details
	err = server.store.Update(func(tx *buntdb.Tx) error {
		// certfp special lookup key
		if credentialType == "certfp" {
			assembledKeyCertToAccount := fmt.Sprintf(keyCertToAccount, client.certfp)

			// make sure certfp doesn't already exist because that'd be silly
			_, err := tx.Get(assembledKeyCertToAccount)
			if err != buntdb.ErrNotFound {
				return errCertfpAlreadyExists
			}

			tx.Set(assembledKeyCertToAccount, casefoldedAccount, nil)
		}

		// make creds
		var creds AccountCredentials

		// always set passphrase salt
		creds.PassphraseSalt, err = NewSalt()
		if err != nil {
			return fmt.Errorf("Could not create passphrase salt: %s", err.Error())
		}

		if credentialType == "certfp" {
			creds.Certificate = client.certfp
		} else if credentialType == "passphrase" {
			creds.PassphraseHash, err = server.passwords.GenerateFromPassword(creds.PassphraseSalt, credentialValue)
			if err != nil {
				return fmt.Errorf("Could not hash password: %s", err)
			}
		}
		credText, err := json.Marshal(creds)
		if err != nil {
			return fmt.Errorf("Could not marshal creds: %s", err)
		}
		tx.Set(fmt.Sprintf(keyAccountCredentials, account), string(credText), nil)

		return nil
	})

	// details could not be stored and relevant numerics have been dispatched, abort
	if err != nil {
		errMsg := "Could not register"
		if err == errCertfpAlreadyExists {
			errMsg = "An account already exists for your certificate fingerprint"
		}
		client.Send(nil, server.name, ERR_UNKNOWNERROR, client.nick, "REG", "CREATE", errMsg)
		log.Println("Could not save registration creds:", err.Error())
		removeFailedRegCreateData(server.store, casefoldedAccount)
		return false
	}

	// automatically complete registration
	if callbackNamespace == "*" {
		err = server.store.Update(func(tx *buntdb.Tx) error {
			tx.Set(fmt.Sprintf(keyAccountVerified, casefoldedAccount), "1", nil)

			// load acct info inside store tx
			account := ClientAccount{
				Name:         strings.TrimSpace(msg.Params[1]),
				RegisteredAt: time.Now(),
				Clients:      []*Client{client},
			}
			//TODO(dan): Consider creating ircd-wide account adding/removing/affecting lock for protecting access to these sorts of variables
			server.accounts[casefoldedAccount] = &account
			client.account = &account

			client.Send(nil, server.name, RPL_REGISTRATION_SUCCESS, client.nick, account.Name, "Account created")
			client.Send(nil, server.name, RPL_LOGGEDIN, client.nick, client.nickMaskString, account.Name, fmt.Sprintf("You are now logged in as %s", account.Name))
			client.Send(nil, server.name, RPL_SASLSUCCESS, client.nick, "Authentication successful")
			return nil
		})
		if err != nil {
			client.Send(nil, server.name, ERR_UNKNOWNERROR, client.nick, "REG", "CREATE", "Could not register")
			log.Println("Could not save verification confirmation (*):", err.Error())
			removeFailedRegCreateData(server.store, casefoldedAccount)
			return false
		}

		return false
	}

	// dispatch callback
	client.Notice(fmt.Sprintf("We should dispatch a real callback here to %s:%s", callbackNamespace, callbackValue))

	return false
}
<|endoftext|>