// Panic, but a little nicer func programmerError(str string) { panic(locale.Errorf("Programmer Error: %s", locale.Sprintf(str))) }
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 }
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 }
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 }
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 }
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 }
// 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 }
// 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 }
// 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)) } }
// 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!!!") }
) 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")
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 }
func perrorf(header string, format string, args ...interface{}) locale.Error { return ParseError{ Header: header, Message: locale.Errorf(format, args...), } }