diff --git a/src/default-config/config.default.yaml b/src/default-config/config.default.yaml
index 32b6cdf..9696177 100644
--- a/src/default-config/config.default.yaml
+++ b/src/default-config/config.default.yaml
@@ -1,5 +1,5 @@
---
-Version : "0.1.2"
+Version : "0.1.3"
# Sample config.yaml file.
# Copy this file to "config/config.yaml" and adjust the
# settings to your requirements
diff --git a/src/global/global.go b/src/global/global.go
index c518d11..a2316b5 100644
--- a/src/global/global.go
+++ b/src/global/global.go
@@ -6,18 +6,35 @@ import (
"io/ioutil"
"os"
"encoding/json"
-
+ "text/template"
+ "path"
+ "regexp"
+ "strings"
+ "time"
+ // "reflect"
)
// Global variables
var ThisSession Session
var MainConfig Config
+// Template declaration
+var templates []string = []string{"autodiscover.xml","autoconfig.xml"}
+var Templates map[string]*template.Template = make(map[string]*template.Template)
+
const defaultConfigDir string = "default-config/"
const configDir string = "config/"
+func NewSessionID() string{
+ timecode := time.Now()
+ id := timecode.Format("20060102150405.000")
+ id = strings.Replace(id,".","",1)
+
+ return id
+}
func NewConfig() Config {
MainConfig = loadConfig()
+ loadXMLTemplates()
return MainConfig
}
func loadConfig() Config {
@@ -37,7 +54,22 @@ func loadConfig() Config {
removeDisabledItems(&cfg)
return cfg
}
-
+func loadXMLTemplates(){
+ for _, tmpl := range templates {
+ tmpl := fmt.Sprintf("templates/%s",tmpl)
+ name := path.Base(tmpl)
+ var fmap = template.FuncMap{
+ "lower": strings.ToLower,
+ "parseUsername": parseUsername,
+ "onoff": chooseOnOff,
+ }
+ t, err := template.New(name).Funcs(fmap).ParseFiles(tmpl)
+ if err != nil {
+ panic (err)
+ }
+ Templates[name] = t
+ }
+}
func unmarshalConfig(file string, cfg *Config) {
if FileExists(file) {
content, err := ioutil.ReadFile(file)
@@ -94,3 +126,40 @@ func JSONify(content interface{}) string {
}
return string(data)
}
+func parseUsername(svc Service, email string) string {
+ if email == "" {
+ return "not-provided"
+ }
+ if svc.UsernameIsFQDN && !svc.RequireLocalDomain{
+ return email
+ } else if svc.UsernameIsFQDN && svc.RequireLocalDomain {
+ re := regexp.MustCompile(`[^@(%40)]+$`)
+ domain := re.FindString(email)
+ localemail := strings.Replace(email, domain,
+ MainConfig.LocalDomain,1)
+ return localemail
+ } else {
+ re := regexp.MustCompile(`^[^@(%40)]+`)
+ username := re.FindString(email)
+ return username
+ }
+}
+func chooseOnOff(value bool) string {
+ if value {
+ return "on"
+ } else {
+ return "off"
+ }
+}
+// GetIP gets a requests IP address by reading off the forwarded-for
+// header (for proxies) and falls back to use the remote address.
+func GetSessionIP() string {
+ r := ThisSession.Request
+ ip := r.RemoteAddr
+ forwarded := r.Header.Get("X-FORWARDED-FOR")
+ if forwarded != "" {
+ ip = forwarded
+ }
+ fmt.Printf("Session %s Connect From : %s\r\f",ThisSession.ID, ip)
+ return ip
+}
diff --git a/src/structs/structs.go b/src/structs/structs.go
index 12197c3..61186d8 100644
--- a/src/structs/structs.go
+++ b/src/structs/structs.go
@@ -4,12 +4,15 @@ import "net/http"
type Session struct {
+ ID string
+ IP string
ResponseWriter http.ResponseWriter
Request *http.Request
Path string
WebContent string
ContentType string
}
+
type Config struct {
Version string `yaml:"Version"`
BaseURL string `yaml:"BaseURL"`
@@ -49,7 +52,7 @@ type Response struct {
Url string `json:"url"`
ContentType string `json:"content_type"`
Message string `json:"message"`
- Content map[string]interface{} `json:"content"`
+ Content map[string]interface{} `json:"content"`
Config Config `json:"_"`
Email string `json:"_"`
}
diff --git a/src/templates/autoconfig.xml b/src/templates/autoconfig.xml
index a721a4b..9fc4796 100644
--- a/src/templates/autoconfig.xml
+++ b/src/templates/autoconfig.xml
@@ -9,7 +9,7 @@
{{ .Server }}
{{ .Port }}
{{ .SocketType }}
- {{ . | parseUsername }}
+ {{ $.Email | parseUsername . }}
{{ .Authentication }}
{{ end }}
@@ -20,7 +20,7 @@
{{ .Server }}
{{ .Port }}>
{{ .SocketType }}
- {{ . | parseUsername }}
+ {{ $.Email | parseUsername . }}
{{ .Authentication }}
{{ end }}
@@ -28,7 +28,7 @@
{{ with .Config.AddressBook }}
{{ if .Enabled }}
- {{ . | parseUsername }}
+ {{ $.Email | parseUsername . }}
{{ .Authentication }}
{{ .Server }}
@@ -37,7 +37,7 @@
{{ with .Config.Calendar }}
{{ if .Enabled }}
- {{ . | parseUsername }}
+ {{ $.Email | parseUsername . }}
{{ .Authentication }}
{{ .Server }}
@@ -48,7 +48,7 @@
- {{ . | parseUsername }}
+ {{ $.Email | parseUsername . }}
diff --git a/src/templates/autodiscover.xml b/src/templates/autodiscover.xml
index 8669b2b..acbf376 100644
--- a/src/templates/autodiscover.xml
+++ b/src/templates/autodiscover.xml
@@ -11,7 +11,7 @@
{{ .Server }}
{{ .Port }}
{{ .UsernameIsFQDN | onoff }}
- {{ . | parseUsername }}
+ {{ $.Email | parseUsername . }}
{{ .SPA | onoff }}
{{ if eq .SocketType "SSL" }}on{{ else }}off{{ end }}
{{ not .NoAuthRequired | onoff }}
@@ -25,7 +25,7 @@
{{ .Server }}
{{ .Port }}
{{ .UsernameIsFQDN | onoff }}
- {{ . | parseUsername }}
+ {{ $.Email | parseUsername . }}
{{ .SPA | onoff }}
{{ .SocketType }}
{{ not .NoAuthRequired | onoff }}
diff --git a/src/web/handler/handler.go b/src/web/handler/handler.go
index f9ceb1f..0ff1839 100644
--- a/src/web/handler/handler.go
+++ b/src/web/handler/handler.go
@@ -8,10 +8,16 @@ import (
"fmt"
)
func WebHandler(w http.ResponseWriter, r *http.Request) {
- fmt.Println("Request For :",r.URL)
+
+
ThisSession = Session{}
ThisSession.ResponseWriter = w
ThisSession.Request = r
+
+ ThisSession.ID = NewSessionID()
+ fmt.Printf("Session %s Request For : %s\r\f",ThisSession.ID, r.URL)
+ ThisSession.IP = GetSessionIP()
+
ThisSession.Path = strings.ToLower(r.URL.Path[1:])
if ThisSession.Path == "" {
ThisSession.Path = "none"
diff --git a/src/web/responses/responses.go b/src/web/responses/responses.go
index be3aa3e..a6eafc9 100644
--- a/src/web/responses/responses.go
+++ b/src/web/responses/responses.go
@@ -2,42 +2,47 @@ package responses
import (
"mailautoconf/global"
. "mailautoconf/structs"
- "text/template"
+ // "text/template"
"fmt"
- "path"
+ // "path"
"strings"
"bytes"
"regexp"
)
var email string
-var fmap = template.FuncMap{
- "lower": strings.ToLower,
- "parseUsername": parseUsername,
- "onoff": chooseOnOff,
- }
+
func MozAutoconfig() string {
// The below link has config-v1.1.xml information
// https://wiki.mozilla.org/Thunderbird:Autoconfiguration:ConfigFileFormat
- tmpl := "templates/autoconfig.xml"
+
+ // parse the querystring
+ if err := global.ThisSession.Request.ParseForm(); err != nil {
+ fmt.Println(err)
+ }
+
+ // build the response
response := Response{}
response.Email = global.ThisSession.Request.FormValue("emailaddress")
email = response.Email
response.Config = global.MainConfig
- name := path.Base(tmpl)
- t, err1 := template.New(name).Funcs(fmap).ParseFiles(tmpl)
- if err1 != nil {
- panic (err1)
- }
+ // set content type to XML
global.ThisSession.ContentType = "application/xml"
+
+ // execute the template
var result bytes.Buffer
- err := t.Execute(&result, response)
+ template := global.Templates["autoconfig.xml"]
+ err := template.Execute(&result, response)
if err != nil {
fmt.Println(err)
}
+
+ // return our string of xml
return result.String()
}
func MsAutoDiscoverXML() string {
+ // MS Outlook Autodiscover.xml
+ //
// Example POST Request (sent from client) :
//
//
@@ -46,27 +51,64 @@ func MsAutoDiscoverXML() string {
// http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a
//
//
- tmpl := "templates/autodiscover.xml"
- email = global.ThisSession.Request.FormValue("EMailAddress")
- response := Response{}
- response.Config = global.MainConfig
- name := path.Base(tmpl)
- t, err1 := template.New(name).Funcs(fmap).ParseFiles(tmpl)
- if err1 != nil {
- panic (err1)
+
+ // Parse the form to get the values
+ if err := global.ThisSession.Request.ParseForm(); err != nil {
+ fmt.Println(err)
}
+
+ // convert the input to a string so we can extract the email address
+ form := fmt.Sprintf("%s",global.ThisSession.Request.Form)
+
+ // fine the EMailAddress section
+ find := regexp.MustCompile(`\(.*?)\<\/EMailAddress\>`)
+ email = find.FindString(form)
+
+ // replace the tags
+ replace := regexp.MustCompile(`\<[\/]?EMailAddress\>`)
+ email = replace.ReplaceAllString(email,``)
+
+ fmt.Printf("Session %s Request for email : %s\r\f",global.ThisSession.ID,email)
+ // build the reponse
+ response := Response{}
+ response.Email = email
+ response.Config = global.MainConfig
+
+ // execute the template
+ template := global.Templates["autodiscover.xml"]
global.ThisSession.ContentType = "application/xml"
var result bytes.Buffer
- err := t.Execute(&result, response)
+ err := template.Execute(&result, response)
if err != nil {
fmt.Println(err)
}
+
+ // return our string of xml
return result.String()
}
func MsAutoDiscoverJSON() string {
+ // MS Outlook Autodiscover.json - undocumented
+ //
// Example Request
// /autodiscover/autodiscover.json?Email=you@your.domain&Protocol=Autodiscoverv1&RedirectCount=1
- return ""
+ email = global.ThisSession.Request.FormValue("Email")
+ protocol := global.ThisSession.Request.FormValue("Protocol")
+ fmt.Println(protocol)
+ global.ThisSession.ContentType = "application/json"
+ switch strings.ToLower(protocol) {
+ case "autodiscoverv1":
+ response := MSAutodiscoverJSONResponse{}
+ response.Protocol = "AutodiscoverV1"
+ response.Url = fmt.Sprintf("%s/Autodiscover/Autodiscover.xml", global.MainConfig.BaseURL)
+ return global.JSONify(response)
+ default:
+
+ response := MSAutodiscoverJSONError{}
+ response.ErrorCode = "InvalidProtocol";
+ response.ErrorMessage = fmt.Sprintf("The given protocol value '%s' is invalid. Supported values are 'AutodiscoverV1'", protocol)
+ return global.JSONify(response)
+ }
+
}
func DefaultResponse() string {
response := Response{}
@@ -81,28 +123,3 @@ func OurConfig() string {
content := global.JSONify(global.MainConfig)
return content
}
-func parseUsername(svc Service) string {
- if email == "" {
- return "not-provided"
- }
- if svc.UsernameIsFQDN && !svc.RequireLocalDomain{
- return email
- } else if svc.UsernameIsFQDN && svc.RequireLocalDomain {
- re := regexp.MustCompile(`[^@(%40)]+$`)
- domain := re.FindString(email)
- localemail := strings.Replace(email, domain,
- global.MainConfig.LocalDomain,1)
- return localemail
- } else {
- re := regexp.MustCompile(`^[^@(%40)]+`)
- username := re.FindString(email)
- return username
- }
-}
-func chooseOnOff(value bool) string {
- if value {
- return "on"
- } else {
- return "off"
- }
-}