mirror of
https://github.com/jhillyerd/inbucket.git
synced 2026-02-08 03:16:00 +00:00
Merge branch 'feature/pkg' into develop, closes #79
This commit is contained in:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -26,8 +26,12 @@ _testmain.go
|
|||||||
*.swo
|
*.swo
|
||||||
|
|
||||||
# our binaries
|
# our binaries
|
||||||
|
/client
|
||||||
|
/client.exe
|
||||||
/inbucket
|
/inbucket
|
||||||
/inbucket.exe
|
/inbucket.exe
|
||||||
/dist/**
|
/dist/**
|
||||||
/cmd/client/client
|
/cmd/client/client
|
||||||
/cmd/client/client.exe
|
/cmd/client/client.exe
|
||||||
|
/cmd/inbucket/inbucket
|
||||||
|
/cmd/inbucket/inbucket.exe
|
||||||
|
|||||||
@@ -2,13 +2,12 @@ language: go
|
|||||||
sudo: false
|
sudo: false
|
||||||
|
|
||||||
env:
|
env:
|
||||||
- DEPLOY_WITH_MAJOR="1.9"
|
- DEPLOY_WITH_MAJOR="1.10"
|
||||||
|
|
||||||
before_script:
|
before_script:
|
||||||
- go get github.com/golang/lint/golint
|
- go get github.com/golang/lint/golint
|
||||||
|
|
||||||
go:
|
go:
|
||||||
- 1.9.x
|
|
||||||
- "1.10"
|
- "1.10"
|
||||||
|
|
||||||
deploy:
|
deploy:
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# Docker build file for Inbucket, see https://www.docker.io/
|
# Docker build file for Inbucket, see https://www.docker.io/
|
||||||
# Inbucket website: http://www.inbucket.org/
|
# Inbucket website: http://www.inbucket.org/
|
||||||
|
|
||||||
FROM golang:1.9-alpine
|
FROM golang:1.10-alpine
|
||||||
MAINTAINER James Hillyerd, @jameshillyerd
|
MAINTAINER James Hillyerd, @jameshillyerd
|
||||||
|
|
||||||
# Configuration (WORKDIR doesn't support env vars)
|
# Configuration (WORKDIR doesn't support env vars)
|
||||||
|
|||||||
29
Makefile
29
Makefile
@@ -1,26 +1,27 @@
|
|||||||
PKG := inbucket
|
SHELL = /bin/sh
|
||||||
SHELL := /bin/sh
|
|
||||||
|
|
||||||
SRC := $(shell find . -type f -name '*.go' -not -path "./vendor/*")
|
SRC := $(shell find . -type f -name '*.go' -not -path "./vendor/*")
|
||||||
PKGS := $$(go list ./... | grep -v /vendor/)
|
PKGS := $(shell go list ./... | grep -v /vendor/)
|
||||||
|
|
||||||
.PHONY: all build clean fmt install lint simplify test
|
.PHONY: all build clean fmt lint simplify test
|
||||||
|
|
||||||
all: test lint build
|
commands = client inbucket
|
||||||
|
|
||||||
|
all: clean test lint build
|
||||||
|
|
||||||
|
$(commands): %: cmd/%
|
||||||
|
go build ./$<
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
go clean
|
go clean $(PKGS)
|
||||||
|
rm -f $(commands)
|
||||||
|
|
||||||
deps:
|
deps:
|
||||||
go get -t ./...
|
go get -t ./...
|
||||||
|
|
||||||
build: clean deps
|
build: deps $(commands)
|
||||||
go build
|
|
||||||
|
|
||||||
install: build
|
test: deps
|
||||||
go install
|
|
||||||
|
|
||||||
test: clean deps
|
|
||||||
go test -race ./...
|
go test -race ./...
|
||||||
|
|
||||||
fmt:
|
fmt:
|
||||||
@@ -31,5 +32,5 @@ simplify:
|
|||||||
|
|
||||||
lint:
|
lint:
|
||||||
@test -z "$(shell gofmt -l . | tee /dev/stderr)" || echo "[WARN] Fix formatting issues with 'make fmt'"
|
@test -z "$(shell gofmt -l . | tee /dev/stderr)" || echo "[WARN] Fix formatting issues with 'make fmt'"
|
||||||
@golint -set_exit_status $${PKGS}
|
@golint -set_exit_status $(PKGS)
|
||||||
@go vet $${PKGS}
|
@go vet $(PKGS)
|
||||||
|
|||||||
@@ -21,6 +21,9 @@ to contribute code to the project check out [CONTRIBUTING.md].
|
|||||||
|
|
||||||
## Homebrew Tap
|
## Homebrew Tap
|
||||||
|
|
||||||
|
(currently broken, being tracked in [issue
|
||||||
|
#68](https://github.com/jhillyerd/inbucket/issues/68))
|
||||||
|
|
||||||
Inbucket has an OS X [Homebrew] tap available as [jhillyerd/inbucket][Homebrew Tap],
|
Inbucket has an OS X [Homebrew] tap available as [jhillyerd/inbucket][Homebrew Tap],
|
||||||
see the `README.md` there for installation instructions.
|
see the `README.md` there for installation instructions.
|
||||||
|
|
||||||
@@ -31,7 +34,7 @@ You will need a functioning [Go installation][Google Go] for this to work.
|
|||||||
|
|
||||||
Grab the Inbucket source code and compile the daemon:
|
Grab the Inbucket source code and compile the daemon:
|
||||||
|
|
||||||
go get -v github.com/jhillyerd/inbucket
|
go get -v github.com/jhillyerd/inbucket/cmd/inbucket
|
||||||
|
|
||||||
Edit etc/inbucket.conf and tailor to your environment. It should work on most
|
Edit etc/inbucket.conf and tailor to your environment. It should work on most
|
||||||
Unix and OS X machines as is. Launch the daemon:
|
Unix and OS X machines as is. Launch the daemon:
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/google/subcommands"
|
"github.com/google/subcommands"
|
||||||
"github.com/jhillyerd/inbucket/rest/client"
|
"github.com/jhillyerd/inbucket/pkg/rest/client"
|
||||||
)
|
)
|
||||||
|
|
||||||
type listCmd struct {
|
type listCmd struct {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/google/subcommands"
|
"github.com/google/subcommands"
|
||||||
"github.com/jhillyerd/inbucket/rest/client"
|
"github.com/jhillyerd/inbucket/pkg/rest/client"
|
||||||
)
|
)
|
||||||
|
|
||||||
type matchCmd struct {
|
type matchCmd struct {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/google/subcommands"
|
"github.com/google/subcommands"
|
||||||
"github.com/jhillyerd/inbucket/rest/client"
|
"github.com/jhillyerd/inbucket/pkg/rest/client"
|
||||||
)
|
)
|
||||||
|
|
||||||
type mboxCmd struct {
|
type mboxCmd struct {
|
||||||
|
|||||||
@@ -12,15 +12,15 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/jhillyerd/inbucket/config"
|
"github.com/jhillyerd/inbucket/pkg/config"
|
||||||
"github.com/jhillyerd/inbucket/filestore"
|
"github.com/jhillyerd/inbucket/pkg/log"
|
||||||
"github.com/jhillyerd/inbucket/httpd"
|
"github.com/jhillyerd/inbucket/pkg/msghub"
|
||||||
"github.com/jhillyerd/inbucket/log"
|
"github.com/jhillyerd/inbucket/pkg/rest"
|
||||||
"github.com/jhillyerd/inbucket/msghub"
|
"github.com/jhillyerd/inbucket/pkg/server/pop3"
|
||||||
"github.com/jhillyerd/inbucket/pop3d"
|
"github.com/jhillyerd/inbucket/pkg/server/smtp"
|
||||||
"github.com/jhillyerd/inbucket/rest"
|
"github.com/jhillyerd/inbucket/pkg/server/web"
|
||||||
"github.com/jhillyerd/inbucket/smtpd"
|
"github.com/jhillyerd/inbucket/pkg/storage/file"
|
||||||
"github.com/jhillyerd/inbucket/webui"
|
"github.com/jhillyerd/inbucket/pkg/webui"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -39,8 +39,8 @@ var (
|
|||||||
shutdownChan = make(chan bool)
|
shutdownChan = make(chan bool)
|
||||||
|
|
||||||
// Server instances
|
// Server instances
|
||||||
smtpServer *smtpd.Server
|
smtpServer *smtp.Server
|
||||||
pop3Server *pop3d.Server
|
pop3Server *pop3.Server
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@@ -119,17 +119,17 @@ func main() {
|
|||||||
ds := filestore.DefaultFileDataStore()
|
ds := filestore.DefaultFileDataStore()
|
||||||
|
|
||||||
// Start HTTP server
|
// Start HTTP server
|
||||||
httpd.Initialize(config.GetWebConfig(), shutdownChan, ds, msgHub)
|
web.Initialize(config.GetWebConfig(), shutdownChan, ds, msgHub)
|
||||||
webui.SetupRoutes(httpd.Router)
|
webui.SetupRoutes(web.Router)
|
||||||
rest.SetupRoutes(httpd.Router)
|
rest.SetupRoutes(web.Router)
|
||||||
go httpd.Start(rootCtx)
|
go web.Start(rootCtx)
|
||||||
|
|
||||||
// Start POP3 server
|
// Start POP3 server
|
||||||
pop3Server = pop3d.New(config.GetPOP3Config(), shutdownChan, ds)
|
pop3Server = pop3.New(config.GetPOP3Config(), shutdownChan, ds)
|
||||||
go pop3Server.Start(rootCtx)
|
go pop3Server.Start(rootCtx)
|
||||||
|
|
||||||
// Startup SMTP server
|
// Startup SMTP server
|
||||||
smtpServer = smtpd.NewServer(config.GetSMTPConfig(), shutdownChan, ds, msgHub)
|
smtpServer = smtp.NewServer(config.GetSMTPConfig(), shutdownChan, ds, msgHub)
|
||||||
go smtpServer.Start(rootCtx)
|
go smtpServer.Start(rootCtx)
|
||||||
|
|
||||||
// Loop forever waiting for signals or shutdown channel
|
// Loop forever waiting for signals or shutdown channel
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
package datastore
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strconv"
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
type HashLock [4096]sync.RWMutex
|
|
||||||
|
|
||||||
func (h *HashLock) Get(hash string) *sync.RWMutex {
|
|
||||||
if len(hash) < 3 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
i, err := strconv.ParseInt(hash[0:3], 16, 0)
|
|
||||||
if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return &h[i]
|
|
||||||
}
|
|
||||||
@@ -16,8 +16,6 @@ apk add --no-cache --virtual .build-deps git
|
|||||||
# Setup
|
# Setup
|
||||||
export GOBIN="$bindir"
|
export GOBIN="$bindir"
|
||||||
cd "$srcdir"
|
cd "$srcdir"
|
||||||
# Fetch tags for describe
|
|
||||||
git fetch -t
|
|
||||||
builddate="$(date -Iseconds)"
|
builddate="$(date -Iseconds)"
|
||||||
buildver="$(git describe --tags --always)"
|
buildver="$(git describe --tags --always)"
|
||||||
|
|
||||||
@@ -30,7 +28,7 @@ echo "### Testing Inbucket"
|
|||||||
go test ./...
|
go test ./...
|
||||||
|
|
||||||
echo "### Building Inbucket"
|
echo "### Building Inbucket"
|
||||||
go build -o inbucket -ldflags "-X 'main.version=$buildver' -X 'main.date=$builddate'" -v .
|
go build -o inbucket -ldflags "-X 'main.version=$buildver' -X 'main.date=$builddate'" -v ./cmd/inbucket
|
||||||
|
|
||||||
echo "### Installing Inbucket"
|
echo "### Installing Inbucket"
|
||||||
set -x
|
set -x
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ func openLogFile() error {
|
|||||||
var err error
|
var err error
|
||||||
logf, err = os.OpenFile(logfname, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0666)
|
logf, err = os.OpenFile(logfname, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0666)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Failed to create %v: %v\n", logfname, err)
|
return fmt.Errorf("failed to create %v: %v", logfname, err)
|
||||||
}
|
}
|
||||||
golog.SetOutput(logf)
|
golog.SetOutput(logf)
|
||||||
Tracef("Opened new logfile")
|
Tracef("Opened new logfile")
|
||||||
@@ -10,15 +10,15 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/jhillyerd/inbucket/datastore"
|
"github.com/jhillyerd/inbucket/pkg/log"
|
||||||
"github.com/jhillyerd/inbucket/httpd"
|
"github.com/jhillyerd/inbucket/pkg/rest/model"
|
||||||
"github.com/jhillyerd/inbucket/log"
|
"github.com/jhillyerd/inbucket/pkg/server/web"
|
||||||
"github.com/jhillyerd/inbucket/rest/model"
|
"github.com/jhillyerd/inbucket/pkg/storage"
|
||||||
"github.com/jhillyerd/inbucket/stringutil"
|
"github.com/jhillyerd/inbucket/pkg/stringutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MailboxListV1 renders a list of messages in a mailbox
|
// MailboxListV1 renders a list of messages in a mailbox
|
||||||
func MailboxListV1(w http.ResponseWriter, req *http.Request, ctx *httpd.Context) (err error) {
|
func MailboxListV1(w http.ResponseWriter, req *http.Request, ctx *web.Context) (err error) {
|
||||||
// Don't have to validate these aren't empty, Gorilla returns 404
|
// Don't have to validate these aren't empty, Gorilla returns 404
|
||||||
name, err := stringutil.ParseMailboxName(ctx.Vars["name"])
|
name, err := stringutil.ParseMailboxName(ctx.Vars["name"])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -48,11 +48,11 @@ func MailboxListV1(w http.ResponseWriter, req *http.Request, ctx *httpd.Context)
|
|||||||
Size: msg.Size(),
|
Size: msg.Size(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return httpd.RenderJSON(w, jmessages)
|
return web.RenderJSON(w, jmessages)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MailboxShowV1 renders a particular message from a mailbox
|
// MailboxShowV1 renders a particular message from a mailbox
|
||||||
func MailboxShowV1(w http.ResponseWriter, req *http.Request, ctx *httpd.Context) (err error) {
|
func MailboxShowV1(w http.ResponseWriter, req *http.Request, ctx *web.Context) (err error) {
|
||||||
// Don't have to validate these aren't empty, Gorilla returns 404
|
// Don't have to validate these aren't empty, Gorilla returns 404
|
||||||
id := ctx.Vars["id"]
|
id := ctx.Vars["id"]
|
||||||
name, err := stringutil.ParseMailboxName(ctx.Vars["name"])
|
name, err := stringutil.ParseMailboxName(ctx.Vars["name"])
|
||||||
@@ -96,7 +96,7 @@ func MailboxShowV1(w http.ResponseWriter, req *http.Request, ctx *httpd.Context)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return httpd.RenderJSON(w,
|
return web.RenderJSON(w,
|
||||||
&model.JSONMessageV1{
|
&model.JSONMessageV1{
|
||||||
Mailbox: name,
|
Mailbox: name,
|
||||||
ID: msg.ID(),
|
ID: msg.ID(),
|
||||||
@@ -115,7 +115,7 @@ func MailboxShowV1(w http.ResponseWriter, req *http.Request, ctx *httpd.Context)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MailboxPurgeV1 deletes all messages from a mailbox
|
// MailboxPurgeV1 deletes all messages from a mailbox
|
||||||
func MailboxPurgeV1(w http.ResponseWriter, req *http.Request, ctx *httpd.Context) (err error) {
|
func MailboxPurgeV1(w http.ResponseWriter, req *http.Request, ctx *web.Context) (err error) {
|
||||||
// Don't have to validate these aren't empty, Gorilla returns 404
|
// Don't have to validate these aren't empty, Gorilla returns 404
|
||||||
name, err := stringutil.ParseMailboxName(ctx.Vars["name"])
|
name, err := stringutil.ParseMailboxName(ctx.Vars["name"])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -133,11 +133,11 @@ func MailboxPurgeV1(w http.ResponseWriter, req *http.Request, ctx *httpd.Context
|
|||||||
}
|
}
|
||||||
log.Tracef("HTTP purged mailbox for %q", name)
|
log.Tracef("HTTP purged mailbox for %q", name)
|
||||||
|
|
||||||
return httpd.RenderJSON(w, "OK")
|
return web.RenderJSON(w, "OK")
|
||||||
}
|
}
|
||||||
|
|
||||||
// MailboxSourceV1 displays the raw source of a message, including headers. Renders text/plain
|
// MailboxSourceV1 displays the raw source of a message, including headers. Renders text/plain
|
||||||
func MailboxSourceV1(w http.ResponseWriter, req *http.Request, ctx *httpd.Context) (err error) {
|
func MailboxSourceV1(w http.ResponseWriter, req *http.Request, ctx *web.Context) (err error) {
|
||||||
// Don't have to validate these aren't empty, Gorilla returns 404
|
// Don't have to validate these aren't empty, Gorilla returns 404
|
||||||
id := ctx.Vars["id"]
|
id := ctx.Vars["id"]
|
||||||
name, err := stringutil.ParseMailboxName(ctx.Vars["name"])
|
name, err := stringutil.ParseMailboxName(ctx.Vars["name"])
|
||||||
@@ -171,7 +171,7 @@ func MailboxSourceV1(w http.ResponseWriter, req *http.Request, ctx *httpd.Contex
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MailboxDeleteV1 removes a particular message from a mailbox
|
// MailboxDeleteV1 removes a particular message from a mailbox
|
||||||
func MailboxDeleteV1(w http.ResponseWriter, req *http.Request, ctx *httpd.Context) (err error) {
|
func MailboxDeleteV1(w http.ResponseWriter, req *http.Request, ctx *web.Context) (err error) {
|
||||||
// Don't have to validate these aren't empty, Gorilla returns 404
|
// Don't have to validate these aren't empty, Gorilla returns 404
|
||||||
id := ctx.Vars["id"]
|
id := ctx.Vars["id"]
|
||||||
name, err := stringutil.ParseMailboxName(ctx.Vars["name"])
|
name, err := stringutil.ParseMailboxName(ctx.Vars["name"])
|
||||||
@@ -197,5 +197,5 @@ func MailboxDeleteV1(w http.ResponseWriter, req *http.Request, ctx *httpd.Contex
|
|||||||
return fmt.Errorf("Delete(%q) failed: %v", id, err)
|
return fmt.Errorf("Delete(%q) failed: %v", id, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return httpd.RenderJSON(w, "OK")
|
return web.RenderJSON(w, "OK")
|
||||||
}
|
}
|
||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/jhillyerd/inbucket/datastore"
|
"github.com/jhillyerd/inbucket/pkg/storage"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
"net/url"
|
"net/url"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/jhillyerd/inbucket/rest/model"
|
"github.com/jhillyerd/inbucket/pkg/rest/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Client accesses the Inbucket REST API v1
|
// Client accesses the Inbucket REST API v1
|
||||||
@@ -30,6 +30,7 @@ type JSONMessageV1 struct {
|
|||||||
Attachments []*JSONMessageAttachmentV1 `json:"attachments"`
|
Attachments []*JSONMessageAttachmentV1 `json:"attachments"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// JSONMessageAttachmentV1 contains information about a MIME attachment
|
||||||
type JSONMessageAttachmentV1 struct {
|
type JSONMessageAttachmentV1 struct {
|
||||||
FileName string `json:"filename"`
|
FileName string `json:"filename"`
|
||||||
ContentType string `json:"content-type"`
|
ContentType string `json:"content-type"`
|
||||||
23
pkg/rest/routes.go
Normal file
23
pkg/rest/routes.go
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
package rest
|
||||||
|
|
||||||
|
import "github.com/gorilla/mux"
|
||||||
|
import "github.com/jhillyerd/inbucket/pkg/server/web"
|
||||||
|
|
||||||
|
// SetupRoutes populates the routes for the REST interface
|
||||||
|
func SetupRoutes(r *mux.Router) {
|
||||||
|
// API v1
|
||||||
|
r.Path("/api/v1/mailbox/{name}").Handler(
|
||||||
|
web.Handler(MailboxListV1)).Name("MailboxListV1").Methods("GET")
|
||||||
|
r.Path("/api/v1/mailbox/{name}").Handler(
|
||||||
|
web.Handler(MailboxPurgeV1)).Name("MailboxPurgeV1").Methods("DELETE")
|
||||||
|
r.Path("/api/v1/mailbox/{name}/{id}").Handler(
|
||||||
|
web.Handler(MailboxShowV1)).Name("MailboxShowV1").Methods("GET")
|
||||||
|
r.Path("/api/v1/mailbox/{name}/{id}").Handler(
|
||||||
|
web.Handler(MailboxDeleteV1)).Name("MailboxDeleteV1").Methods("DELETE")
|
||||||
|
r.Path("/api/v1/mailbox/{name}/{id}/source").Handler(
|
||||||
|
web.Handler(MailboxSourceV1)).Name("MailboxSourceV1").Methods("GET")
|
||||||
|
r.Path("/api/v1/monitor/messages").Handler(
|
||||||
|
web.Handler(MonitorAllMessagesV1)).Name("MonitorAllMessagesV1").Methods("GET")
|
||||||
|
r.Path("/api/v1/monitor/messages/{name}").Handler(
|
||||||
|
web.Handler(MonitorMailboxMessagesV1)).Name("MonitorMailboxMessagesV1").Methods("GET")
|
||||||
|
}
|
||||||
@@ -5,11 +5,11 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
"github.com/jhillyerd/inbucket/httpd"
|
"github.com/jhillyerd/inbucket/pkg/log"
|
||||||
"github.com/jhillyerd/inbucket/log"
|
"github.com/jhillyerd/inbucket/pkg/msghub"
|
||||||
"github.com/jhillyerd/inbucket/msghub"
|
"github.com/jhillyerd/inbucket/pkg/rest/model"
|
||||||
"github.com/jhillyerd/inbucket/rest/model"
|
"github.com/jhillyerd/inbucket/pkg/server/web"
|
||||||
"github.com/jhillyerd/inbucket/stringutil"
|
"github.com/jhillyerd/inbucket/pkg/stringutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -144,17 +144,19 @@ func (ml *msgListener) Close() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MonitorAllMessagesV1 is a web handler which upgrades the connection to a websocket and notifies
|
||||||
|
// the client of all messages received.
|
||||||
func MonitorAllMessagesV1(
|
func MonitorAllMessagesV1(
|
||||||
w http.ResponseWriter, req *http.Request, ctx *httpd.Context) (err error) {
|
w http.ResponseWriter, req *http.Request, ctx *web.Context) (err error) {
|
||||||
// Upgrade to Websocket
|
// Upgrade to Websocket
|
||||||
conn, err := upgrader.Upgrade(w, req, nil)
|
conn, err := upgrader.Upgrade(w, req, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
httpd.ExpWebSocketConnectsCurrent.Add(1)
|
web.ExpWebSocketConnectsCurrent.Add(1)
|
||||||
defer func() {
|
defer func() {
|
||||||
_ = conn.Close()
|
_ = conn.Close()
|
||||||
httpd.ExpWebSocketConnectsCurrent.Add(-1)
|
web.ExpWebSocketConnectsCurrent.Add(-1)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
log.Tracef("HTTP[%v] Upgraded to websocket", req.RemoteAddr)
|
log.Tracef("HTTP[%v] Upgraded to websocket", req.RemoteAddr)
|
||||||
@@ -167,8 +169,10 @@ func MonitorAllMessagesV1(
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MonitorMailboxMessagesV1 is a web handler which upgrades the connection to a websocket and
|
||||||
|
// notifies the client of messages received by a particular mailbox.
|
||||||
func MonitorMailboxMessagesV1(
|
func MonitorMailboxMessagesV1(
|
||||||
w http.ResponseWriter, req *http.Request, ctx *httpd.Context) (err error) {
|
w http.ResponseWriter, req *http.Request, ctx *web.Context) (err error) {
|
||||||
name, err := stringutil.ParseMailboxName(ctx.Vars["name"])
|
name, err := stringutil.ParseMailboxName(ctx.Vars["name"])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -178,10 +182,10 @@ func MonitorMailboxMessagesV1(
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
httpd.ExpWebSocketConnectsCurrent.Add(1)
|
web.ExpWebSocketConnectsCurrent.Add(1)
|
||||||
defer func() {
|
defer func() {
|
||||||
_ = conn.Close()
|
_ = conn.Close()
|
||||||
httpd.ExpWebSocketConnectsCurrent.Add(-1)
|
web.ExpWebSocketConnectsCurrent.Add(-1)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
log.Tracef("HTTP[%v] Upgraded to websocket", req.RemoteAddr)
|
log.Tracef("HTTP[%v] Upgraded to websocket", req.RemoteAddr)
|
||||||
@@ -10,10 +10,10 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/jhillyerd/enmime"
|
"github.com/jhillyerd/enmime"
|
||||||
"github.com/jhillyerd/inbucket/config"
|
"github.com/jhillyerd/inbucket/pkg/config"
|
||||||
"github.com/jhillyerd/inbucket/datastore"
|
"github.com/jhillyerd/inbucket/pkg/msghub"
|
||||||
"github.com/jhillyerd/inbucket/httpd"
|
"github.com/jhillyerd/inbucket/pkg/server/web"
|
||||||
"github.com/jhillyerd/inbucket/msghub"
|
"github.com/jhillyerd/inbucket/pkg/storage"
|
||||||
)
|
)
|
||||||
|
|
||||||
type InputMessageData struct {
|
type InputMessageData struct {
|
||||||
@@ -184,7 +184,7 @@ func testRestGet(url string) (*httptest.ResponseRecorder, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
httpd.Router.ServeHTTP(w, req)
|
web.Router.ServeHTTP(w, req)
|
||||||
return w, nil
|
return w, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -200,8 +200,8 @@ func setupWebServer(ds datastore.DataStore) *bytes.Buffer {
|
|||||||
PublicDir: "../themes/bootstrap/public",
|
PublicDir: "../themes/bootstrap/public",
|
||||||
}
|
}
|
||||||
shutdownChan := make(chan bool)
|
shutdownChan := make(chan bool)
|
||||||
httpd.Initialize(cfg, shutdownChan, ds, &msghub.Hub{})
|
web.Initialize(cfg, shutdownChan, ds, &msghub.Hub{})
|
||||||
SetupRoutes(httpd.Router)
|
SetupRoutes(web.Router)
|
||||||
|
|
||||||
return buf
|
return buf
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package pop3d
|
package pop3
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
@@ -11,8 +11,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/jhillyerd/inbucket/datastore"
|
"github.com/jhillyerd/inbucket/pkg/log"
|
||||||
"github.com/jhillyerd/inbucket/log"
|
"github.com/jhillyerd/inbucket/pkg/storage"
|
||||||
)
|
)
|
||||||
|
|
||||||
// State tracks the current mode of our POP3 state machine
|
// State tracks the current mode of our POP3 state machine
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package pop3d
|
package pop3
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
@@ -7,9 +7,9 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/jhillyerd/inbucket/config"
|
"github.com/jhillyerd/inbucket/pkg/config"
|
||||||
"github.com/jhillyerd/inbucket/datastore"
|
"github.com/jhillyerd/inbucket/pkg/log"
|
||||||
"github.com/jhillyerd/inbucket/log"
|
"github.com/jhillyerd/inbucket/pkg/storage"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Server defines an instance of our POP3 server
|
// Server defines an instance of our POP3 server
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package smtpd
|
package smtp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
@@ -12,10 +12,10 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/jhillyerd/inbucket/datastore"
|
"github.com/jhillyerd/inbucket/pkg/log"
|
||||||
"github.com/jhillyerd/inbucket/log"
|
"github.com/jhillyerd/inbucket/pkg/msghub"
|
||||||
"github.com/jhillyerd/inbucket/msghub"
|
"github.com/jhillyerd/inbucket/pkg/storage"
|
||||||
"github.com/jhillyerd/inbucket/stringutil"
|
"github.com/jhillyerd/inbucket/pkg/stringutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
// State tracks the current mode of our SMTP state machine
|
// State tracks the current mode of our SMTP state machine
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package smtpd
|
package smtp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@@ -13,9 +13,9 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/jhillyerd/inbucket/config"
|
"github.com/jhillyerd/inbucket/pkg/config"
|
||||||
"github.com/jhillyerd/inbucket/datastore"
|
"github.com/jhillyerd/inbucket/pkg/msghub"
|
||||||
"github.com/jhillyerd/inbucket/msghub"
|
"github.com/jhillyerd/inbucket/pkg/storage"
|
||||||
)
|
)
|
||||||
|
|
||||||
type scriptStep struct {
|
type scriptStep struct {
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package smtpd
|
package smtp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"container/list"
|
"container/list"
|
||||||
@@ -10,10 +10,10 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/jhillyerd/inbucket/config"
|
"github.com/jhillyerd/inbucket/pkg/config"
|
||||||
"github.com/jhillyerd/inbucket/datastore"
|
"github.com/jhillyerd/inbucket/pkg/log"
|
||||||
"github.com/jhillyerd/inbucket/log"
|
"github.com/jhillyerd/inbucket/pkg/msghub"
|
||||||
"github.com/jhillyerd/inbucket/msghub"
|
"github.com/jhillyerd/inbucket/pkg/storage"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package httpd
|
package web
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
@@ -6,9 +6,9 @@ import (
|
|||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"github.com/gorilla/sessions"
|
"github.com/gorilla/sessions"
|
||||||
"github.com/jhillyerd/inbucket/config"
|
"github.com/jhillyerd/inbucket/pkg/config"
|
||||||
"github.com/jhillyerd/inbucket/datastore"
|
"github.com/jhillyerd/inbucket/pkg/msghub"
|
||||||
"github.com/jhillyerd/inbucket/msghub"
|
"github.com/jhillyerd/inbucket/pkg/storage"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Context is passed into every request handler function
|
// Context is passed into every request handler function
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package httpd
|
package web
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/jhillyerd/inbucket/log"
|
"github.com/jhillyerd/inbucket/pkg/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TemplateFuncs declares functions made available to all templates (including partials)
|
// TemplateFuncs declares functions made available to all templates (including partials)
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package httpd
|
package web
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"html/template"
|
"html/template"
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package httpd
|
package web
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// Package httpd provides the plumbing for Inbucket's web GUI and RESTful API
|
// Package web provides the plumbing for Inbucket's web GUI and RESTful API
|
||||||
package httpd
|
package web
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
@@ -12,10 +12,10 @@ import (
|
|||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"github.com/gorilla/securecookie"
|
"github.com/gorilla/securecookie"
|
||||||
"github.com/gorilla/sessions"
|
"github.com/gorilla/sessions"
|
||||||
"github.com/jhillyerd/inbucket/config"
|
"github.com/jhillyerd/inbucket/pkg/config"
|
||||||
"github.com/jhillyerd/inbucket/datastore"
|
"github.com/jhillyerd/inbucket/pkg/log"
|
||||||
"github.com/jhillyerd/inbucket/log"
|
"github.com/jhillyerd/inbucket/pkg/msghub"
|
||||||
"github.com/jhillyerd/inbucket/msghub"
|
"github.com/jhillyerd/inbucket/pkg/storage"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Handler is a function type that handles an HTTP request in Inbucket
|
// Handler is a function type that handles an HTTP request in Inbucket
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package httpd
|
package web
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"html/template"
|
"html/template"
|
||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/jhillyerd/inbucket/log"
|
"github.com/jhillyerd/inbucket/pkg/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
var cachedMutex sync.Mutex
|
var cachedMutex sync.Mutex
|
||||||
@@ -11,8 +11,8 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/jhillyerd/enmime"
|
"github.com/jhillyerd/enmime"
|
||||||
"github.com/jhillyerd/inbucket/datastore"
|
"github.com/jhillyerd/inbucket/pkg/log"
|
||||||
"github.com/jhillyerd/inbucket/log"
|
"github.com/jhillyerd/inbucket/pkg/storage"
|
||||||
)
|
)
|
||||||
|
|
||||||
// FileMessage implements Message and contains a little bit of data about a
|
// FileMessage implements Message and contains a little bit of data about a
|
||||||
@@ -11,10 +11,10 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/jhillyerd/inbucket/config"
|
"github.com/jhillyerd/inbucket/pkg/config"
|
||||||
"github.com/jhillyerd/inbucket/datastore"
|
"github.com/jhillyerd/inbucket/pkg/log"
|
||||||
"github.com/jhillyerd/inbucket/log"
|
"github.com/jhillyerd/inbucket/pkg/storage"
|
||||||
"github.com/jhillyerd/inbucket/stringutil"
|
"github.com/jhillyerd/inbucket/pkg/stringutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Name of index file in each mailbox
|
// Name of index file in each mailbox
|
||||||
@@ -140,6 +140,7 @@ func (ds *FileDataStore) AllMailboxes() ([]datastore.Mailbox, error) {
|
|||||||
return mailboxes, nil
|
return mailboxes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LockFor returns the RWMutex for this mailbox, or an error.
|
||||||
func (ds *FileDataStore) LockFor(emailAddress string) (*sync.RWMutex, error) {
|
func (ds *FileDataStore) LockFor(emailAddress string) (*sync.RWMutex, error) {
|
||||||
name, err := stringutil.ParseMailboxName(emailAddress)
|
name, err := stringutil.ParseMailboxName(emailAddress)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -11,7 +11,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/jhillyerd/inbucket/config"
|
"github.com/jhillyerd/inbucket/pkg/config"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
23
pkg/storage/lock.go
Normal file
23
pkg/storage/lock.go
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
package datastore
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HashLock holds a fixed length array of mutexes. This approach allows concurrent mailbox
|
||||||
|
// access in most cases without requiring an infinite number of mutexes.
|
||||||
|
type HashLock [4096]sync.RWMutex
|
||||||
|
|
||||||
|
// Get returns a RWMutex based on the first 12 bits of the mailbox hash. Hash must be a hexidecimal
|
||||||
|
// string of three or more characters.
|
||||||
|
func (h *HashLock) Get(hash string) *sync.RWMutex {
|
||||||
|
if len(hash) < 3 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
i, err := strconv.ParseInt(hash[0:3], 16, 0)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &h[i]
|
||||||
|
}
|
||||||
@@ -3,7 +3,7 @@ package datastore_test
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/jhillyerd/inbucket/datastore"
|
"github.com/jhillyerd/inbucket/pkg/storage"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestHashLock(t *testing.T) {
|
func TestHashLock(t *testing.T) {
|
||||||
@@ -6,8 +6,8 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/jhillyerd/inbucket/config"
|
"github.com/jhillyerd/inbucket/pkg/config"
|
||||||
"github.com/jhillyerd/inbucket/log"
|
"github.com/jhillyerd/inbucket/pkg/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -27,6 +27,7 @@ func (m *MockDataStore) AllMailboxes() ([]Mailbox, error) {
|
|||||||
return args.Get(0).([]Mailbox), args.Error(1)
|
return args.Get(0).([]Mailbox), args.Error(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LockFor mock function returns a new RWMutex, never errors.
|
||||||
func (m *MockDataStore) LockFor(name string) (*sync.RWMutex, error) {
|
func (m *MockDataStore) LockFor(name string) (*sync.RWMutex, error) {
|
||||||
return &sync.RWMutex{}, nil
|
return &sync.RWMutex{}, nil
|
||||||
}
|
}
|
||||||
@@ -7,29 +7,29 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/jhillyerd/inbucket/datastore"
|
"github.com/jhillyerd/inbucket/pkg/log"
|
||||||
"github.com/jhillyerd/inbucket/httpd"
|
"github.com/jhillyerd/inbucket/pkg/server/web"
|
||||||
"github.com/jhillyerd/inbucket/log"
|
"github.com/jhillyerd/inbucket/pkg/storage"
|
||||||
"github.com/jhillyerd/inbucket/sanitize"
|
"github.com/jhillyerd/inbucket/pkg/stringutil"
|
||||||
"github.com/jhillyerd/inbucket/stringutil"
|
"github.com/jhillyerd/inbucket/pkg/webui/sanitize"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MailboxIndex renders the index page for a particular mailbox
|
// MailboxIndex renders the index page for a particular mailbox
|
||||||
func MailboxIndex(w http.ResponseWriter, req *http.Request, ctx *httpd.Context) (err error) {
|
func MailboxIndex(w http.ResponseWriter, req *http.Request, ctx *web.Context) (err error) {
|
||||||
// Form values must be validated manually
|
// Form values must be validated manually
|
||||||
name := req.FormValue("name")
|
name := req.FormValue("name")
|
||||||
selected := req.FormValue("id")
|
selected := req.FormValue("id")
|
||||||
if len(name) == 0 {
|
if len(name) == 0 {
|
||||||
ctx.Session.AddFlash("Account name is required", "errors")
|
ctx.Session.AddFlash("Account name is required", "errors")
|
||||||
_ = ctx.Session.Save(req, w)
|
_ = ctx.Session.Save(req, w)
|
||||||
http.Redirect(w, req, httpd.Reverse("RootIndex"), http.StatusSeeOther)
|
http.Redirect(w, req, web.Reverse("RootIndex"), http.StatusSeeOther)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
name, err = stringutil.ParseMailboxName(name)
|
name, err = stringutil.ParseMailboxName(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Session.AddFlash(err.Error(), "errors")
|
ctx.Session.AddFlash(err.Error(), "errors")
|
||||||
_ = ctx.Session.Save(req, w)
|
_ = ctx.Session.Save(req, w)
|
||||||
http.Redirect(w, req, httpd.Reverse("RootIndex"), http.StatusSeeOther)
|
http.Redirect(w, req, web.Reverse("RootIndex"), http.StatusSeeOther)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
// Remember this mailbox was visited
|
// Remember this mailbox was visited
|
||||||
@@ -40,7 +40,7 @@ func MailboxIndex(w http.ResponseWriter, req *http.Request, ctx *httpd.Context)
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// Render template
|
// Render template
|
||||||
return httpd.RenderTemplate("mailbox/index.html", w, map[string]interface{}{
|
return web.RenderTemplate("mailbox/index.html", w, map[string]interface{}{
|
||||||
"ctx": ctx,
|
"ctx": ctx,
|
||||||
"errorFlash": errorFlash,
|
"errorFlash": errorFlash,
|
||||||
"name": name,
|
"name": name,
|
||||||
@@ -49,24 +49,24 @@ func MailboxIndex(w http.ResponseWriter, req *http.Request, ctx *httpd.Context)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MailboxLink handles pretty links to a particular message. Renders a redirect
|
// MailboxLink handles pretty links to a particular message. Renders a redirect
|
||||||
func MailboxLink(w http.ResponseWriter, req *http.Request, ctx *httpd.Context) (err error) {
|
func MailboxLink(w http.ResponseWriter, req *http.Request, ctx *web.Context) (err error) {
|
||||||
// Don't have to validate these aren't empty, Gorilla returns 404
|
// Don't have to validate these aren't empty, Gorilla returns 404
|
||||||
id := ctx.Vars["id"]
|
id := ctx.Vars["id"]
|
||||||
name, err := stringutil.ParseMailboxName(ctx.Vars["name"])
|
name, err := stringutil.ParseMailboxName(ctx.Vars["name"])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Session.AddFlash(err.Error(), "errors")
|
ctx.Session.AddFlash(err.Error(), "errors")
|
||||||
_ = ctx.Session.Save(req, w)
|
_ = ctx.Session.Save(req, w)
|
||||||
http.Redirect(w, req, httpd.Reverse("RootIndex"), http.StatusSeeOther)
|
http.Redirect(w, req, web.Reverse("RootIndex"), http.StatusSeeOther)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
// Build redirect
|
// Build redirect
|
||||||
uri := fmt.Sprintf("%s?name=%s&id=%s", httpd.Reverse("MailboxIndex"), name, id)
|
uri := fmt.Sprintf("%s?name=%s&id=%s", web.Reverse("MailboxIndex"), name, id)
|
||||||
http.Redirect(w, req, uri, http.StatusSeeOther)
|
http.Redirect(w, req, uri, http.StatusSeeOther)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// MailboxList renders a list of messages in a mailbox. Renders a partial
|
// MailboxList renders a list of messages in a mailbox. Renders a partial
|
||||||
func MailboxList(w http.ResponseWriter, req *http.Request, ctx *httpd.Context) (err error) {
|
func MailboxList(w http.ResponseWriter, req *http.Request, ctx *web.Context) (err error) {
|
||||||
// Don't have to validate these aren't empty, Gorilla returns 404
|
// Don't have to validate these aren't empty, Gorilla returns 404
|
||||||
name, err := stringutil.ParseMailboxName(ctx.Vars["name"])
|
name, err := stringutil.ParseMailboxName(ctx.Vars["name"])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -84,7 +84,7 @@ func MailboxList(w http.ResponseWriter, req *http.Request, ctx *httpd.Context) (
|
|||||||
}
|
}
|
||||||
log.Tracef("Got %v messsages", len(messages))
|
log.Tracef("Got %v messsages", len(messages))
|
||||||
// Render partial template
|
// Render partial template
|
||||||
return httpd.RenderPartial("mailbox/_list.html", w, map[string]interface{}{
|
return web.RenderPartial("mailbox/_list.html", w, map[string]interface{}{
|
||||||
"ctx": ctx,
|
"ctx": ctx,
|
||||||
"name": name,
|
"name": name,
|
||||||
"messages": messages,
|
"messages": messages,
|
||||||
@@ -92,7 +92,7 @@ func MailboxList(w http.ResponseWriter, req *http.Request, ctx *httpd.Context) (
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MailboxShow renders a particular message from a mailbox. Renders an HTML partial
|
// MailboxShow renders a particular message from a mailbox. Renders an HTML partial
|
||||||
func MailboxShow(w http.ResponseWriter, req *http.Request, ctx *httpd.Context) (err error) {
|
func MailboxShow(w http.ResponseWriter, req *http.Request, ctx *web.Context) (err error) {
|
||||||
// Don't have to validate these aren't empty, Gorilla returns 404
|
// Don't have to validate these aren't empty, Gorilla returns 404
|
||||||
id := ctx.Vars["id"]
|
id := ctx.Vars["id"]
|
||||||
name, err := stringutil.ParseMailboxName(ctx.Vars["name"])
|
name, err := stringutil.ParseMailboxName(ctx.Vars["name"])
|
||||||
@@ -117,7 +117,7 @@ func MailboxShow(w http.ResponseWriter, req *http.Request, ctx *httpd.Context) (
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("ReadBody(%q) failed: %v", id, err)
|
return fmt.Errorf("ReadBody(%q) failed: %v", id, err)
|
||||||
}
|
}
|
||||||
body := template.HTML(httpd.TextToHTML(mime.Text))
|
body := template.HTML(web.TextToHTML(mime.Text))
|
||||||
htmlAvailable := mime.HTML != ""
|
htmlAvailable := mime.HTML != ""
|
||||||
var htmlBody template.HTML
|
var htmlBody template.HTML
|
||||||
if htmlAvailable {
|
if htmlAvailable {
|
||||||
@@ -128,7 +128,7 @@ func MailboxShow(w http.ResponseWriter, req *http.Request, ctx *httpd.Context) (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Render partial template
|
// Render partial template
|
||||||
return httpd.RenderPartial("mailbox/_show.html", w, map[string]interface{}{
|
return web.RenderPartial("mailbox/_show.html", w, map[string]interface{}{
|
||||||
"ctx": ctx,
|
"ctx": ctx,
|
||||||
"name": name,
|
"name": name,
|
||||||
"message": msg,
|
"message": msg,
|
||||||
@@ -141,7 +141,7 @@ func MailboxShow(w http.ResponseWriter, req *http.Request, ctx *httpd.Context) (
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MailboxHTML displays the HTML content of a message. Renders a partial
|
// MailboxHTML displays the HTML content of a message. Renders a partial
|
||||||
func MailboxHTML(w http.ResponseWriter, req *http.Request, ctx *httpd.Context) (err error) {
|
func MailboxHTML(w http.ResponseWriter, req *http.Request, ctx *web.Context) (err error) {
|
||||||
// Don't have to validate these aren't empty, Gorilla returns 404
|
// Don't have to validate these aren't empty, Gorilla returns 404
|
||||||
id := ctx.Vars["id"]
|
id := ctx.Vars["id"]
|
||||||
name, err := stringutil.ParseMailboxName(ctx.Vars["name"])
|
name, err := stringutil.ParseMailboxName(ctx.Vars["name"])
|
||||||
@@ -168,7 +168,7 @@ func MailboxHTML(w http.ResponseWriter, req *http.Request, ctx *httpd.Context) (
|
|||||||
}
|
}
|
||||||
// Render partial template
|
// Render partial template
|
||||||
w.Header().Set("Content-Type", "text/html; charset=UTF-8")
|
w.Header().Set("Content-Type", "text/html; charset=UTF-8")
|
||||||
return httpd.RenderPartial("mailbox/_html.html", w, map[string]interface{}{
|
return web.RenderPartial("mailbox/_html.html", w, map[string]interface{}{
|
||||||
"ctx": ctx,
|
"ctx": ctx,
|
||||||
"name": name,
|
"name": name,
|
||||||
"message": message,
|
"message": message,
|
||||||
@@ -178,7 +178,7 @@ func MailboxHTML(w http.ResponseWriter, req *http.Request, ctx *httpd.Context) (
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MailboxSource displays the raw source of a message, including headers. Renders text/plain
|
// MailboxSource displays the raw source of a message, including headers. Renders text/plain
|
||||||
func MailboxSource(w http.ResponseWriter, req *http.Request, ctx *httpd.Context) (err error) {
|
func MailboxSource(w http.ResponseWriter, req *http.Request, ctx *web.Context) (err error) {
|
||||||
// Don't have to validate these aren't empty, Gorilla returns 404
|
// Don't have to validate these aren't empty, Gorilla returns 404
|
||||||
id := ctx.Vars["id"]
|
id := ctx.Vars["id"]
|
||||||
name, err := stringutil.ParseMailboxName(ctx.Vars["name"])
|
name, err := stringutil.ParseMailboxName(ctx.Vars["name"])
|
||||||
@@ -213,14 +213,14 @@ func MailboxSource(w http.ResponseWriter, req *http.Request, ctx *httpd.Context)
|
|||||||
|
|
||||||
// MailboxDownloadAttach sends the attachment to the client; disposition:
|
// MailboxDownloadAttach sends the attachment to the client; disposition:
|
||||||
// attachment, type: application/octet-stream
|
// attachment, type: application/octet-stream
|
||||||
func MailboxDownloadAttach(w http.ResponseWriter, req *http.Request, ctx *httpd.Context) (err error) {
|
func MailboxDownloadAttach(w http.ResponseWriter, req *http.Request, ctx *web.Context) (err error) {
|
||||||
// Don't have to validate these aren't empty, Gorilla returns 404
|
// Don't have to validate these aren't empty, Gorilla returns 404
|
||||||
id := ctx.Vars["id"]
|
id := ctx.Vars["id"]
|
||||||
name, err := stringutil.ParseMailboxName(ctx.Vars["name"])
|
name, err := stringutil.ParseMailboxName(ctx.Vars["name"])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Session.AddFlash(err.Error(), "errors")
|
ctx.Session.AddFlash(err.Error(), "errors")
|
||||||
_ = ctx.Session.Save(req, w)
|
_ = ctx.Session.Save(req, w)
|
||||||
http.Redirect(w, req, httpd.Reverse("RootIndex"), http.StatusSeeOther)
|
http.Redirect(w, req, web.Reverse("RootIndex"), http.StatusSeeOther)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
numStr := ctx.Vars["num"]
|
numStr := ctx.Vars["num"]
|
||||||
@@ -228,7 +228,7 @@ func MailboxDownloadAttach(w http.ResponseWriter, req *http.Request, ctx *httpd.
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Session.AddFlash("Attachment number must be unsigned numeric", "errors")
|
ctx.Session.AddFlash("Attachment number must be unsigned numeric", "errors")
|
||||||
_ = ctx.Session.Save(req, w)
|
_ = ctx.Session.Save(req, w)
|
||||||
http.Redirect(w, req, httpd.Reverse("RootIndex"), http.StatusSeeOther)
|
http.Redirect(w, req, web.Reverse("RootIndex"), http.StatusSeeOther)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
mb, err := ctx.DataStore.MailboxFor(name)
|
mb, err := ctx.DataStore.MailboxFor(name)
|
||||||
@@ -252,7 +252,7 @@ func MailboxDownloadAttach(w http.ResponseWriter, req *http.Request, ctx *httpd.
|
|||||||
if int(num) >= len(body.Attachments) {
|
if int(num) >= len(body.Attachments) {
|
||||||
ctx.Session.AddFlash("Attachment number too high", "errors")
|
ctx.Session.AddFlash("Attachment number too high", "errors")
|
||||||
_ = ctx.Session.Save(req, w)
|
_ = ctx.Session.Save(req, w)
|
||||||
http.Redirect(w, req, httpd.Reverse("RootIndex"), http.StatusSeeOther)
|
http.Redirect(w, req, web.Reverse("RootIndex"), http.StatusSeeOther)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
part := body.Attachments[num]
|
part := body.Attachments[num]
|
||||||
@@ -266,13 +266,13 @@ func MailboxDownloadAttach(w http.ResponseWriter, req *http.Request, ctx *httpd.
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MailboxViewAttach sends the attachment to the client for online viewing
|
// MailboxViewAttach sends the attachment to the client for online viewing
|
||||||
func MailboxViewAttach(w http.ResponseWriter, req *http.Request, ctx *httpd.Context) (err error) {
|
func MailboxViewAttach(w http.ResponseWriter, req *http.Request, ctx *web.Context) (err error) {
|
||||||
// Don't have to validate these aren't empty, Gorilla returns 404
|
// Don't have to validate these aren't empty, Gorilla returns 404
|
||||||
name, err := stringutil.ParseMailboxName(ctx.Vars["name"])
|
name, err := stringutil.ParseMailboxName(ctx.Vars["name"])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Session.AddFlash(err.Error(), "errors")
|
ctx.Session.AddFlash(err.Error(), "errors")
|
||||||
_ = ctx.Session.Save(req, w)
|
_ = ctx.Session.Save(req, w)
|
||||||
http.Redirect(w, req, httpd.Reverse("RootIndex"), http.StatusSeeOther)
|
http.Redirect(w, req, web.Reverse("RootIndex"), http.StatusSeeOther)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
id := ctx.Vars["id"]
|
id := ctx.Vars["id"]
|
||||||
@@ -281,7 +281,7 @@ func MailboxViewAttach(w http.ResponseWriter, req *http.Request, ctx *httpd.Cont
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Session.AddFlash("Attachment number must be unsigned numeric", "errors")
|
ctx.Session.AddFlash("Attachment number must be unsigned numeric", "errors")
|
||||||
_ = ctx.Session.Save(req, w)
|
_ = ctx.Session.Save(req, w)
|
||||||
http.Redirect(w, req, httpd.Reverse("RootIndex"), http.StatusSeeOther)
|
http.Redirect(w, req, web.Reverse("RootIndex"), http.StatusSeeOther)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
mb, err := ctx.DataStore.MailboxFor(name)
|
mb, err := ctx.DataStore.MailboxFor(name)
|
||||||
@@ -305,7 +305,7 @@ func MailboxViewAttach(w http.ResponseWriter, req *http.Request, ctx *httpd.Cont
|
|||||||
if int(num) >= len(body.Attachments) {
|
if int(num) >= len(body.Attachments) {
|
||||||
ctx.Session.AddFlash("Attachment number too high", "errors")
|
ctx.Session.AddFlash("Attachment number too high", "errors")
|
||||||
_ = ctx.Session.Save(req, w)
|
_ = ctx.Session.Save(req, w)
|
||||||
http.Redirect(w, req, httpd.Reverse("RootIndex"), http.StatusSeeOther)
|
http.Redirect(w, req, web.Reverse("RootIndex"), http.StatusSeeOther)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
part := body.Attachments[num]
|
part := body.Attachments[num]
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package webui
|
package webui
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/jhillyerd/inbucket/httpd"
|
"github.com/jhillyerd/inbucket/pkg/server/web"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -12,7 +12,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// RememberMailbox manages the list of recently accessed mailboxes stored in the session
|
// RememberMailbox manages the list of recently accessed mailboxes stored in the session
|
||||||
func RememberMailbox(ctx *httpd.Context, mailbox string) {
|
func RememberMailbox(ctx *web.Context, mailbox string) {
|
||||||
recent := RecentMailboxes(ctx)
|
recent := RecentMailboxes(ctx)
|
||||||
newRecent := make([]string, 1, maxRemembered)
|
newRecent := make([]string, 1, maxRemembered)
|
||||||
newRecent[0] = mailbox
|
newRecent[0] = mailbox
|
||||||
@@ -28,7 +28,7 @@ func RememberMailbox(ctx *httpd.Context, mailbox string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// RecentMailboxes returns a slice of the most recently accessed mailboxes
|
// RecentMailboxes returns a slice of the most recently accessed mailboxes
|
||||||
func RecentMailboxes(ctx *httpd.Context) []string {
|
func RecentMailboxes(ctx *web.Context) []string {
|
||||||
val := ctx.Session.Values[mailboxKey]
|
val := ctx.Session.Values[mailboxKey]
|
||||||
recent, _ := val.([]string)
|
recent, _ := val.([]string)
|
||||||
return recent
|
return recent
|
||||||
@@ -6,13 +6,13 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/jhillyerd/inbucket/config"
|
"github.com/jhillyerd/inbucket/pkg/config"
|
||||||
"github.com/jhillyerd/inbucket/httpd"
|
"github.com/jhillyerd/inbucket/pkg/server/web"
|
||||||
"github.com/jhillyerd/inbucket/stringutil"
|
"github.com/jhillyerd/inbucket/pkg/stringutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
// RootIndex serves the Inbucket landing page
|
// RootIndex serves the Inbucket landing page
|
||||||
func RootIndex(w http.ResponseWriter, req *http.Request, ctx *httpd.Context) (err error) {
|
func RootIndex(w http.ResponseWriter, req *http.Request, ctx *web.Context) (err error) {
|
||||||
greeting, err := ioutil.ReadFile(config.GetWebConfig().GreetingFile)
|
greeting, err := ioutil.ReadFile(config.GetWebConfig().GreetingFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Failed to load greeting: %v", err)
|
return fmt.Errorf("Failed to load greeting: %v", err)
|
||||||
@@ -23,7 +23,7 @@ func RootIndex(w http.ResponseWriter, req *http.Request, ctx *httpd.Context) (er
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// Render template
|
// Render template
|
||||||
return httpd.RenderTemplate("root/index.html", w, map[string]interface{}{
|
return web.RenderTemplate("root/index.html", w, map[string]interface{}{
|
||||||
"ctx": ctx,
|
"ctx": ctx,
|
||||||
"errorFlash": errorFlash,
|
"errorFlash": errorFlash,
|
||||||
"greeting": template.HTML(string(greeting)),
|
"greeting": template.HTML(string(greeting)),
|
||||||
@@ -31,11 +31,11 @@ func RootIndex(w http.ResponseWriter, req *http.Request, ctx *httpd.Context) (er
|
|||||||
}
|
}
|
||||||
|
|
||||||
// RootMonitor serves the Inbucket monitor page
|
// RootMonitor serves the Inbucket monitor page
|
||||||
func RootMonitor(w http.ResponseWriter, req *http.Request, ctx *httpd.Context) (err error) {
|
func RootMonitor(w http.ResponseWriter, req *http.Request, ctx *web.Context) (err error) {
|
||||||
if !config.GetWebConfig().MonitorVisible {
|
if !config.GetWebConfig().MonitorVisible {
|
||||||
ctx.Session.AddFlash("Monitor is disabled in configuration", "errors")
|
ctx.Session.AddFlash("Monitor is disabled in configuration", "errors")
|
||||||
_ = ctx.Session.Save(req, w)
|
_ = ctx.Session.Save(req, w)
|
||||||
http.Redirect(w, req, httpd.Reverse("RootIndex"), http.StatusSeeOther)
|
http.Redirect(w, req, web.Reverse("RootIndex"), http.StatusSeeOther)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
// Get flash messages, save session
|
// Get flash messages, save session
|
||||||
@@ -44,25 +44,25 @@ func RootMonitor(w http.ResponseWriter, req *http.Request, ctx *httpd.Context) (
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// Render template
|
// Render template
|
||||||
return httpd.RenderTemplate("root/monitor.html", w, map[string]interface{}{
|
return web.RenderTemplate("root/monitor.html", w, map[string]interface{}{
|
||||||
"ctx": ctx,
|
"ctx": ctx,
|
||||||
"errorFlash": errorFlash,
|
"errorFlash": errorFlash,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// RootMonitorMailbox serves the Inbucket monitor page for a particular mailbox
|
// RootMonitorMailbox serves the Inbucket monitor page for a particular mailbox
|
||||||
func RootMonitorMailbox(w http.ResponseWriter, req *http.Request, ctx *httpd.Context) (err error) {
|
func RootMonitorMailbox(w http.ResponseWriter, req *http.Request, ctx *web.Context) (err error) {
|
||||||
if !config.GetWebConfig().MonitorVisible {
|
if !config.GetWebConfig().MonitorVisible {
|
||||||
ctx.Session.AddFlash("Monitor is disabled in configuration", "errors")
|
ctx.Session.AddFlash("Monitor is disabled in configuration", "errors")
|
||||||
_ = ctx.Session.Save(req, w)
|
_ = ctx.Session.Save(req, w)
|
||||||
http.Redirect(w, req, httpd.Reverse("RootIndex"), http.StatusSeeOther)
|
http.Redirect(w, req, web.Reverse("RootIndex"), http.StatusSeeOther)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
name, err := stringutil.ParseMailboxName(ctx.Vars["name"])
|
name, err := stringutil.ParseMailboxName(ctx.Vars["name"])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Session.AddFlash(err.Error(), "errors")
|
ctx.Session.AddFlash(err.Error(), "errors")
|
||||||
_ = ctx.Session.Save(req, w)
|
_ = ctx.Session.Save(req, w)
|
||||||
http.Redirect(w, req, httpd.Reverse("RootIndex"), http.StatusSeeOther)
|
http.Redirect(w, req, web.Reverse("RootIndex"), http.StatusSeeOther)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
// Get flash messages, save session
|
// Get flash messages, save session
|
||||||
@@ -71,7 +71,7 @@ func RootMonitorMailbox(w http.ResponseWriter, req *http.Request, ctx *httpd.Con
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// Render template
|
// Render template
|
||||||
return httpd.RenderTemplate("root/monitor.html", w, map[string]interface{}{
|
return web.RenderTemplate("root/monitor.html", w, map[string]interface{}{
|
||||||
"ctx": ctx,
|
"ctx": ctx,
|
||||||
"errorFlash": errorFlash,
|
"errorFlash": errorFlash,
|
||||||
"name": name,
|
"name": name,
|
||||||
@@ -79,7 +79,7 @@ func RootMonitorMailbox(w http.ResponseWriter, req *http.Request, ctx *httpd.Con
|
|||||||
}
|
}
|
||||||
|
|
||||||
// RootStatus serves the Inbucket status page
|
// RootStatus serves the Inbucket status page
|
||||||
func RootStatus(w http.ResponseWriter, req *http.Request, ctx *httpd.Context) (err error) {
|
func RootStatus(w http.ResponseWriter, req *http.Request, ctx *web.Context) (err error) {
|
||||||
smtpListener := fmt.Sprintf("%s:%d", config.GetSMTPConfig().IP4address.String(),
|
smtpListener := fmt.Sprintf("%s:%d", config.GetSMTPConfig().IP4address.String(),
|
||||||
config.GetSMTPConfig().IP4port)
|
config.GetSMTPConfig().IP4port)
|
||||||
pop3Listener := fmt.Sprintf("%s:%d", config.GetPOP3Config().IP4address.String(),
|
pop3Listener := fmt.Sprintf("%s:%d", config.GetPOP3Config().IP4address.String(),
|
||||||
@@ -92,7 +92,7 @@ func RootStatus(w http.ResponseWriter, req *http.Request, ctx *httpd.Context) (e
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// Render template
|
// Render template
|
||||||
return httpd.RenderTemplate("root/status.html", w, map[string]interface{}{
|
return web.RenderTemplate("root/status.html", w, map[string]interface{}{
|
||||||
"ctx": ctx,
|
"ctx": ctx,
|
||||||
"errorFlash": errorFlash,
|
"errorFlash": errorFlash,
|
||||||
"version": config.Version,
|
"version": config.Version,
|
||||||
35
pkg/webui/routes.go
Normal file
35
pkg/webui/routes.go
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
// Package webui powers Inbucket's web GUI
|
||||||
|
package webui
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
"github.com/jhillyerd/inbucket/pkg/server/web"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SetupRoutes populates routes for the webui into the provided Router
|
||||||
|
func SetupRoutes(r *mux.Router) {
|
||||||
|
r.Path("/").Handler(
|
||||||
|
web.Handler(RootIndex)).Name("RootIndex").Methods("GET")
|
||||||
|
r.Path("/monitor").Handler(
|
||||||
|
web.Handler(RootMonitor)).Name("RootMonitor").Methods("GET")
|
||||||
|
r.Path("/monitor/{name}").Handler(
|
||||||
|
web.Handler(RootMonitorMailbox)).Name("RootMonitorMailbox").Methods("GET")
|
||||||
|
r.Path("/status").Handler(
|
||||||
|
web.Handler(RootStatus)).Name("RootStatus").Methods("GET")
|
||||||
|
r.Path("/link/{name}/{id}").Handler(
|
||||||
|
web.Handler(MailboxLink)).Name("MailboxLink").Methods("GET")
|
||||||
|
r.Path("/mailbox").Handler(
|
||||||
|
web.Handler(MailboxIndex)).Name("MailboxIndex").Methods("GET")
|
||||||
|
r.Path("/mailbox/{name}").Handler(
|
||||||
|
web.Handler(MailboxList)).Name("MailboxList").Methods("GET")
|
||||||
|
r.Path("/mailbox/{name}/{id}").Handler(
|
||||||
|
web.Handler(MailboxShow)).Name("MailboxShow").Methods("GET")
|
||||||
|
r.Path("/mailbox/{name}/{id}/html").Handler(
|
||||||
|
web.Handler(MailboxHTML)).Name("MailboxHtml").Methods("GET")
|
||||||
|
r.Path("/mailbox/{name}/{id}/source").Handler(
|
||||||
|
web.Handler(MailboxSource)).Name("MailboxSource").Methods("GET")
|
||||||
|
r.Path("/mailbox/dattach/{name}/{id}/{num}/{file}").Handler(
|
||||||
|
web.Handler(MailboxDownloadAttach)).Name("MailboxDownloadAttach").Methods("GET")
|
||||||
|
r.Path("/mailbox/vattach/{name}/{id}/{num}/{file}").Handler(
|
||||||
|
web.Handler(MailboxViewAttach)).Name("MailboxViewAttach").Methods("GET")
|
||||||
|
}
|
||||||
@@ -18,6 +18,7 @@ var (
|
|||||||
AllowAttrs("style").Matching(cssSafe).Globally()
|
AllowAttrs("style").Matching(cssSafe).Globally()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// HTML sanitizes the provided html, while attempting to preserve inline CSS styling.
|
||||||
func HTML(html string) (output string, err error) {
|
func HTML(html string) (output string, err error) {
|
||||||
output, err = sanitizeStyleTags(html)
|
output, err = sanitizeStyleTags(html)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -3,7 +3,7 @@ package sanitize_test
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/jhillyerd/inbucket/sanitize"
|
"github.com/jhillyerd/inbucket/pkg/webui/sanitize"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestHTMLPlainStrings test plain text passthrough
|
// TestHTMLPlainStrings test plain text passthrough
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
package rest
|
|
||||||
|
|
||||||
import "github.com/gorilla/mux"
|
|
||||||
import "github.com/jhillyerd/inbucket/httpd"
|
|
||||||
|
|
||||||
// SetupRoutes populates the routes for the REST interface
|
|
||||||
func SetupRoutes(r *mux.Router) {
|
|
||||||
// API v1
|
|
||||||
r.Path("/api/v1/mailbox/{name}").Handler(
|
|
||||||
httpd.Handler(MailboxListV1)).Name("MailboxListV1").Methods("GET")
|
|
||||||
r.Path("/api/v1/mailbox/{name}").Handler(
|
|
||||||
httpd.Handler(MailboxPurgeV1)).Name("MailboxPurgeV1").Methods("DELETE")
|
|
||||||
r.Path("/api/v1/mailbox/{name}/{id}").Handler(
|
|
||||||
httpd.Handler(MailboxShowV1)).Name("MailboxShowV1").Methods("GET")
|
|
||||||
r.Path("/api/v1/mailbox/{name}/{id}").Handler(
|
|
||||||
httpd.Handler(MailboxDeleteV1)).Name("MailboxDeleteV1").Methods("DELETE")
|
|
||||||
r.Path("/api/v1/mailbox/{name}/{id}/source").Handler(
|
|
||||||
httpd.Handler(MailboxSourceV1)).Name("MailboxSourceV1").Methods("GET")
|
|
||||||
r.Path("/api/v1/monitor/messages").Handler(
|
|
||||||
httpd.Handler(MonitorAllMessagesV1)).Name("MonitorAllMessagesV1").Methods("GET")
|
|
||||||
r.Path("/api/v1/monitor/messages/{name}").Handler(
|
|
||||||
httpd.Handler(MonitorMailboxMessagesV1)).Name("MonitorMailboxMessagesV1").Methods("GET")
|
|
||||||
}
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
// Package webui powers Inbucket's web GUI
|
|
||||||
package webui
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/gorilla/mux"
|
|
||||||
"github.com/jhillyerd/inbucket/httpd"
|
|
||||||
)
|
|
||||||
|
|
||||||
// SetupRoutes populates routes for the webui into the provided Router
|
|
||||||
func SetupRoutes(r *mux.Router) {
|
|
||||||
r.Path("/").Handler(
|
|
||||||
httpd.Handler(RootIndex)).Name("RootIndex").Methods("GET")
|
|
||||||
r.Path("/monitor").Handler(
|
|
||||||
httpd.Handler(RootMonitor)).Name("RootMonitor").Methods("GET")
|
|
||||||
r.Path("/monitor/{name}").Handler(
|
|
||||||
httpd.Handler(RootMonitorMailbox)).Name("RootMonitorMailbox").Methods("GET")
|
|
||||||
r.Path("/status").Handler(
|
|
||||||
httpd.Handler(RootStatus)).Name("RootStatus").Methods("GET")
|
|
||||||
r.Path("/link/{name}/{id}").Handler(
|
|
||||||
httpd.Handler(MailboxLink)).Name("MailboxLink").Methods("GET")
|
|
||||||
r.Path("/mailbox").Handler(
|
|
||||||
httpd.Handler(MailboxIndex)).Name("MailboxIndex").Methods("GET")
|
|
||||||
r.Path("/mailbox/{name}").Handler(
|
|
||||||
httpd.Handler(MailboxList)).Name("MailboxList").Methods("GET")
|
|
||||||
r.Path("/mailbox/{name}/{id}").Handler(
|
|
||||||
httpd.Handler(MailboxShow)).Name("MailboxShow").Methods("GET")
|
|
||||||
r.Path("/mailbox/{name}/{id}/html").Handler(
|
|
||||||
httpd.Handler(MailboxHTML)).Name("MailboxHtml").Methods("GET")
|
|
||||||
r.Path("/mailbox/{name}/{id}/source").Handler(
|
|
||||||
httpd.Handler(MailboxSource)).Name("MailboxSource").Methods("GET")
|
|
||||||
r.Path("/mailbox/dattach/{name}/{id}/{num}/{file}").Handler(
|
|
||||||
httpd.Handler(MailboxDownloadAttach)).Name("MailboxDownloadAttach").Methods("GET")
|
|
||||||
r.Path("/mailbox/vattach/{name}/{id}/{num}/{file}").Handler(
|
|
||||||
httpd.Handler(MailboxViewAttach)).Name("MailboxViewAttach").Methods("GET")
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user