Пример #1
1
// Panic, but a little nicer
func programmerError(str string) {
	panic(locale.Errorf("Programmer Error: %s", locale.Sprintf(str)))
}
Пример #2
0
func parseQuotedString(str string) (string, locale.Error) {
	// strip the quotes
	if str[0] != '"' || str[len(str)-1] != '"' {
		return "", locale.Errorf("%q does not look like an RFC 7230 quoted-string", str)
	}
	in := str[1 : len(str)-1]
	// main algo
	out := make([]byte, len(in))
	o := uint(0)
	for i := uint(0); i < uint(len(in)); i++ {
		switch {
		case isQdtext(in[i]):
			out[o] = in[i]
			o++
		case in[i] == '\\':
			i++
			switch {
			case isHTAB(in[i]) || isSP(in[i]) || isVCHAR(in[i]) || isObsText(in[i]):
				out[o] = in[i]
				o++
			default:
				return "", locale.Errorf("%c is not a legal character to follow a backslash in an RFC 7230 quoted-string", in[i])
			}
		default:
			return "", locale.Errorf("%c is not a legal character in an RFC 7230 quoted-string", in[i])
		}
	}
	// return
	return string(out[:o]), nil
}
Пример #3
0
func sdGetSocket() (socket net.Listener, err locale.Error) {
	fds := sd.ListenFds(true)
	if fds == nil {
		err = locale.Errorf("Failed to aquire sockets from systemd")
		return
	}
	if len(fds) != 1 {
		err = locale.Errorf("Wrong number of sockets from systemd: expected %d but got %d", 1, len(fds))
		return
	}
	socket, uerr := net.FileListener(fds[0])
	err = locale.UntranslatedError(uerr)
	fds[0].Close()
	return
}
Пример #4
0
func TwilioSMSWaitForCallback(conf *periwinkle.Cfg, messageSID string) (backend.TwilioSMSMessage, locale.Error) {
	var status backend.TwilioSMSMessage
	var err locale.Error
	done := false
	for !done {
		time.Sleep(time.Second)
		conf.DB.Do(func(db *periwinkle.Tx) {
			statusptr := backend.GetTwilioSMSMessageBySID(db, messageSID)
			if statusptr == nil {
				return
			}
			status = *statusptr
			switch status.MessageStatus {
			case "delivered":
				status.Delete(db)
				done = true
				return
			case "undelivered", "failed":
				status.Delete(db)
				err = locale.Errorf("TODO")
				done = true
				return
			}
		})
	}
	return status, err
}
Пример #5
0
func getBool(key string, val interface{}) bool {
	b, ok := val.(bool)
	if !ok {
		gotoError(locale.Errorf("value for %q is not a Boolean", key))
	}
	return b
}
Пример #6
0
func getString(key string, val interface{}) string {
	str, ok := val.(string)
	if !ok {
		gotoError(locale.Errorf("value for %q is not a string", key))
	}
	return str
}
Пример #7
0
// this captures both `parameter` and accept-parames/accept-ext, with
// the exception that it converts the accept-ext LHS to lowercase,
// which it shouldn't do.
func parseParameter(lhs, rhs string) (string, string, locale.Error) {
	var err locale.Error
	if !isToken(lhs) {
		return "", "", locale.Errorf("%q is not a valid RFC 7230 token", lhs)
	}
	if rhs[0] == '"' {
		rhs, err = parseQuotedString(rhs)
		if err != nil {
			return "", "", locale.Errorf("%q is not a valid RFC 7230 token or [quoted string]", rhs)
		}
	} else {
		if !isToken(rhs) {
			return "", "", locale.Errorf("%q is not a valid RFC 7230 [token] or quoted string", rhs)
		}
	}
	lhs = strings.ToLower(lhs)
	return lhs, rhs, nil
}
Пример #8
0
// Read an entity from the input stream, using the given content type.
func (req *Request) readEntity(router *Router, reader io.Reader, contenttype string) *Response {
	mimetype, params, uerr := mime.ParseMediaType(contenttype)
	if uerr != nil {
		res := router.responseBadRequest(locale.Errorf("Could not parse Content-Type: %v", locale.UntranslatedError(uerr)))
		return &res
	}
	decoder, foundDecoder := router.Decoders[mimetype]
	if !foundDecoder {
		res := router.responseUnsupportedMediaType(locale.Errorf("Unsupported MIME type: " + mimetype))
		return &res
	}
	entity, err := decoder(reader, params)
	if err != nil {
		res := router.responseUnsupportedMediaType(locale.Errorf("Error reading request body (%s): %v", mimetype, err))
		return &res
	}
	req.Entity = entity
	return nil
}
Пример #9
0
// Panic, but a little nicer
func dbError(err error) {
	// TODO: return better messages for Conflict errors.
	switch e := err.(type) {
	case sqlite3.Error:
		if e.Code == sqlite3.ErrConstraint {
			panic(periwinkle.Conflict{locale.UntranslatedError(e)})
		}
		panic(locale.UntranslatedError(e))
	case *mysql.MySQLError:
		// TODO: this list of error numbers might not be
		// complete, or totally correct.  See
		// https://mariadb.com/kb/en/mariadb/mariadb-error-codes/
		switch e.Number {
		case 1022, 1062, 1169, 1216, 1217, 1451, 1452, 1557, 1761, 1762, 1834:
			panic(periwinkle.Conflict{locale.UntranslatedError(e)})
		}
		panic(locale.UntranslatedError(e))
	default:
		panic(locale.Errorf("Programmer Error: the programmer said this is a database error, but it's not: %s", e))
	}
}
Пример #10
0
// function returns  a phone number and Status
// if successful, returns a new phone number and OK
func NewPhoneNum(cfg *periwinkle.Cfg) (string, locale.Error) {
	// gets url for available numbers
	availNumURL := "https://api.twilio.com/2010-04-01/Accounts/" + cfg.TwilioAccountID + "/AvailablePhoneNumbers/US/Local.json?SmsEnabled=true&MmsEnabled=true"

	// gets url for a new phone number
	newPhoneNumURL := "https://api.twilio.com/2010-04-01/Accounts/" + cfg.TwilioAccountID + "/IncomingPhoneNumbers.json"

	client := &http.Client{}

	req, err := http.NewRequest("GET", availNumURL, nil)
	if err != nil {
		return "", locale.UntranslatedError(err)
	}

	req.SetBasicAuth(cfg.TwilioAccountID, cfg.TwilioAuthToken)

	resp, err := client.Do(req)
	defer resp.Body.Close()
	if err != nil {
		return "", locale.UntranslatedError(err)
	}

	if resp.StatusCode == 302 {
		url, err := resp.Location()
		if err != nil {
			return "", locale.UntranslatedError(err)
		}

		req, err = http.NewRequest("GET", url.String(), nil)
		if err != nil {
			return "", locale.UntranslatedError(err)
		}

		req.SetBasicAuth(cfg.TwilioAccountID, cfg.TwilioAuthToken)
		resp, err = client.Do(req)
		defer resp.Body.Close()
		if err != nil {
			return "", locale.UntranslatedError(err)
		}

		if resp.StatusCode != 200 {
			return "", locale.Errorf("%s", resp.Status)
		}

	} else if resp.StatusCode == 200 {

		//continue

	} else {
		return "", locale.Errorf("%s", resp.Status)
	}

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", locale.UntranslatedError(err)
	}

	availNumber := AvailPhNum{}
	json.Unmarshal(body, &availNumber)

	if len(availNumber.PhoneNumberList) != 0 {

		number := availNumber.PhoneNumberList[0].PhoneNumber

		val := url.Values{}
		val.Set("PhoneNumber", availNumber.PhoneNumberList[0].PhoneNumber)
		val.Set("SmsUrl", "http://twimlets.com/echo?Twiml=%3CResponse%3E%3C%2FResponse%3E")

		req, err = http.NewRequest("POST", newPhoneNumURL, bytes.NewBuffer([]byte(val.Encode())))
		if err != nil {
			return "", locale.UntranslatedError(err)
		}

		req.SetBasicAuth(cfg.TwilioAccountID, cfg.TwilioAuthToken)
		req.Header.Add("Accept", "application/json")
		req.Header.Add("Content-Type", "application/x-www-form-urlencoded")

		resp, err = client.Do(req)
		defer resp.Body.Close()
		if err != nil {
			return "", locale.UntranslatedError(err)
		}

		if resp.StatusCode != 200 && resp.StatusCode != 201 {
			return "", locale.Errorf("%s", resp.Status)
		}

		body, err = ioutil.ReadAll(resp.Body)
		if err != nil {
			return "", locale.UntranslatedError(err)
		}
		return number, nil

	}

	return "", locale.Errorf("There are no available phone numbers!!!")
}
Пример #11
0
)

var MiddlewarePostHack = he.Middleware{
	Outside: func(req he.Request, handle func(he.Request) he.Response) he.Response {
		if req.Method != "POST" {
			return handle(req)
		}

		decoder, ok := req.Entity.(*json.Decoder)
		if !ok {
			return handle(req)
		}
		var entity interface{}
		err := decoder.Decode(&entity)
		if err != nil {
			return rfc7231.StatusUnsupportedMediaType(he.ErrorToNetEntity(415, locale.Errorf("Couldn't parse: %v", err)))
		}

		hash, ok := entity.(map[string]interface{})
		if !ok {
			return handle(req)
		}

		method, ok := hash["_method"].(string)
		delete(hash, "_method")
		if ok {
			req.Method = method
		}

		xsrf_token, ok := hash["_xsrf_token"].(string)
		delete(hash, "_xsrf_token")
Пример #12
0
func Parse(in io.Reader) (cfgptr *periwinkle.Cfg, e locale.Error) {
	defer func() {
		if r := recover(); r != nil {
			cfgptr = nil
			switch err := r.(type) {
			case locale.Error:
				e = err
			default:
				panic(r)
			}
		}
	}()

	// these are the defaults
	hostname, err := os.Hostname()
	if err != nil {
		hostname = "localhost"
	}
	cfg := periwinkle.Cfg{
		Mailstore:            "./Maildir",
		WebUIDir:             "./www",
		Debug:                true,
		TrustForwarded:       true,
		TwilioAccountID:      os.Getenv("TWILIO_ACCOUNTID"),
		TwilioAuthToken:      os.Getenv("TWILIO_TOKEN"),
		GroupDomain:          "localhost",
		WebRoot:              "http://" + hostname + ":8080",
		DB:                   nil, // the default DB is set later
		DefaultDomainHandler: bounceNoHost,
	}

	datstr, err := ioutil.ReadAll(in)
	if err != nil {
		gotoError(locale.UntranslatedError(err))
	}

	var datint interface{}
	err = yaml.Unmarshal(datstr, &datint)
	if err != nil {
		gotoError(locale.UntranslatedError(err))
	}

	datmap, ok := datint.(map[interface{}]interface{})
	if !ok {
		gotoError(locale.Errorf("root element is not a map"))
	}

	var dbdriver string
	var dbsource string

	for key, val := range datmap {
		switch key {
		case "Mailstore":
			cfg.Mailstore = maildir.Maildir(getString(key.(string), val))
		case "WebUIDir":
			cfg.WebUIDir = http.Dir(getString(key.(string), val))
		case "Debug":
			cfg.Debug = getBool(key.(string), val)
		case "TrustForwarded":
			cfg.TrustForwarded = getBool(key.(string), val)
		case "TwilioAccountID":
			cfg.TwilioAccountID = getString(key.(string), val)
		case "TwilioAuthToken":
			cfg.TwilioAuthToken = getString(key.(string), val)
		case "GroupDomain":
			cfg.GroupDomain = getString(key.(string), val)
		case "WebRoot":
			cfg.WebRoot = getString(key.(string), val)
		case "DB":
			m, ok := val.(map[interface{}]interface{})
			if !ok {
				gotoError(locale.Errorf("value for %q is not a map", key.(string)))
			}
			for key, val := range m {
				switch key {
				case "driver":
					dbdriver = getString("DB."+key.(string), val)
				case "source":
					dbsource = getString("DB."+key.(string), val)
				default:
					gotoError(locale.Errorf("unknown field: %v", "DB."+key.(string)))
				}
			}
		default:
			gotoError(locale.Errorf("unknown field: %v", key))
		}
	}

	if dbdriver != "" && dbsource != "" {
		db, err := OpenDB(dbdriver, dbsource, cfg.Debug)
		if err != nil {
			gotoError(err)
		}
		cfg.DB = db
	}

	// Set the default database
	if cfg.DB == nil {
		periwinkle.Logf("DB not configured, trying MySQL periwinkle:periwinkle@localhost/periwinkle ...")
		db, err := OpenDB("mysql", "periwinkle:periwinkle@/periwinkle?charset=utf8&parseTime=True", cfg.Debug)
		if err != nil {
			periwinkle.Logf("Could not connect to MySQL: %v", locale.UntranslatedError(err))
			periwinkle.Logf("No MySQL, trying SQLite3 file:periwinkle.sqlite ...")
			db, err = OpenDB("sqlite3", "file:periwinkle.sqlite?mode=rwc&_txlock=exclusive", cfg.Debug)
			if err != nil {
				periwinkle.Logf("Could not open SQLite3 DB: %v", locale.UntranslatedError(err))
				gotoError(locale.Errorf("Could not connect to database"))
			}
		}
		cfg.DB = db
	}

	domain_handlers.GetHandlers(&cfg)

	return &cfg, nil
}
Пример #13
0
func perrorf(header string, format string, args ...interface{}) locale.Error {
	return ParseError{
		Header:  header,
		Message: locale.Errorf(format, args...),
	}
}