Beispiel #1
0
func hydrateNestedComponent(v reflect.Value, component *token) error {

	// create a new object to hold the property value
	var vnew, varr = newValue(v)
	if err := hydrateComponent(vnew, component); err != nil {
		return utils.NewError(hydrateNestedComponent, "unable to decode component", component, err)
	}

	if varr {
		// for arrays, append the new value into the array structure
		voldval := dereferencePointerValue(v)
		if !voldval.CanSet() {
			return utils.NewError(hydrateNestedComponent, "unable to set array value", v, nil)
		} else {
			voldval.Set(reflect.Append(voldval, vnew))
		}
	} else if !v.CanSet() {
		return utils.NewError(hydrateNestedComponent, "unable to set pointer value", v, nil)
	} else {
		// everything else should be a pointer, set it directly
		v.Set(vnew)
	}

	return nil

}
Beispiel #2
0
func (c *Calendar) ValidateICalValue() error {

	for i, e := range c.Events {

		if e == nil {
			continue // skip nil events
		}

		if err := e.ValidateICalValue(); err != nil {
			msg := fmt.Sprintf("event %d failed validation", i)
			return utils.NewError(c.ValidateICalValue, msg, c, err)
		}

		if e.DateStart == nil && c.Method == "" {
			msg := fmt.Sprintf("no value for method and no start date defined on event %d", i)
			return utils.NewError(c.ValidateICalValue, msg, c, nil)
		}

	}

	if c.UsingTimeZone() && !c.UsingGlobalTimeZone() {
		for i, t := range c.TimeZones {
			if t == nil || t.Id != c.TimeZoneId {
				msg := fmt.Sprintf("timezone ID does not match timezone %d", i)
				return utils.NewError(c.ValidateICalValue, msg, c, nil)
			}
		}
	}

	return nil

}
Beispiel #3
0
// decodes the duration of time from iCalendar format
func (d *Duration) DecodeICalValue(value string) error {
	var seconds int64
	var isPast = strings.HasPrefix(value, "-P")
	var matches = durationRegEx.FindAllStringSubmatch(value, -1)
	for _, match := range matches {
		var multiplier int64
		ivalue, err := strconv.ParseInt(match[1], 10, 64)
		if err != nil {
			return utils.NewError(d.DecodeICalValue, "unable to decode duration value "+match[1], d, nil)
		}
		switch match[2] {
		case "S":
			multiplier = 1
		case "M":
			multiplier = 60
		case "H":
			multiplier = 60 * 60
		case "D":
			multiplier = 60 * 60 * 24
		case "W":
			multiplier = 60 * 60 * 24 * 7
		default:
			return utils.NewError(d.DecodeICalValue, "unable to decode duration segment "+match[2], d, nil)
		}
		seconds = seconds + multiplier*ivalue
	}
	d.d = time.Duration(seconds) * time.Second
	if isPast {
		d.d = -d.d
	}
	return nil
}
Beispiel #4
0
// attempts to fetch an event on the remote CalDAV server
func (c *Client) QueryEvents(path string, query *cent.CalendarQuery) (events []*components.Event, oerr error) {
	ms := new(cent.Multistatus)
	if req, err := c.Server().WebDAV().NewRequest("REPORT", path, query); err != nil {
		oerr = utils.NewError(c.QueryEvents, "unable to create request", c, err)
	} else if resp, err := c.WebDAV().Do(req); err != nil {
		oerr = utils.NewError(c.QueryEvents, "unable to execute request", c, err)
	} else if resp.StatusCode == http.StatusNotFound {
		return // no events if not found
	} else if resp.StatusCode != webdav.StatusMulti {
		err := new(entities.Error)
		msg := fmt.Sprintf("unexpected server response %s", resp.Status)
		resp.Decode(err)
		oerr = utils.NewError(c.QueryEvents, msg, c, err)
	} else if err := resp.Decode(ms); err != nil {
		msg := "unable to decode response"
		oerr = utils.NewError(c.QueryEvents, msg, c, err)
	} else {
		for i, r := range ms.Responses {
			for j, p := range r.PropStats {
				if p.Prop == nil || p.Prop.CalendarData == nil {
					continue
				} else if cal, err := p.Prop.CalendarData.CalendarComponent(); err != nil {
					msg := fmt.Sprintf("unable to decode property %d of response %d", j, i)
					oerr = utils.NewError(c.QueryEvents, msg, c, err)
					return
				} else {
					events = append(events, cal.Events...)
				}
			}
		}
	}
	return
}
Beispiel #5
0
// returns an error if the server does not support WebDAV
func (c *Client) ValidateServer(path string) error {
	if features, err := c.Features(path); err != nil {
		return utils.NewError(c.ValidateServer, "feature detection failed", c, err)
	} else if len(features) <= 0 {
		return utils.NewError(c.ValidateServer, "no DAV headers found", c, err)
	} else {
		return nil
	}
}
Beispiel #6
0
// fetches a list of WebDAV features supported by the server
// returns an error if the server does not support DAV
func (c *Client) Features(path string) ([]string, error) {
	if req, err := c.Server().NewRequest("OPTIONS", path); err != nil {
		return []string{}, utils.NewError(c.Features, "unable to create request", c, err)
	} else if resp, err := c.Do(req); err != nil {
		return []string{}, utils.NewError(c.Features, "unable to execute request", c, err)
	} else {
		return resp.Features(), nil
	}
}
Beispiel #7
0
// checks if a resource exists given a particular path
func (c *Client) Exists(path string) (bool, error) {
	if req, err := c.Server().NewRequest("HEAD", path); err != nil {
		return false, utils.NewError(c.Exists, "unable to create request", c, err)
	} else if resp, err := c.Do(req); err != nil {
		return false, utils.NewError(c.Exists, "unable to execute request", c, err)
	} else {
		return resp.StatusCode != nhttp.StatusNotFound, nil
	}
}
Beispiel #8
0
// fetches a list of CalDAV features and checks if a certain one is supported by the server
// returns an error if the server does not support DAV
func (c *Client) ValidateServer(path string) error {
	if found, err := c.SupportsFeature("access", path); err != nil {
		return utils.NewError(c.SupportsFeature, "feature detection failed", c, err)
	} else if !found {
		return utils.NewError(c.SupportsFeature, "calendar access feature missing", c, nil)
	} else {
		return nil
	}
}
Beispiel #9
0
// creates or updates one or more events on the remote CalDAV server
func (c *Client) PutEvents(path string, events ...*components.Event) error {
	if len(events) <= 0 {
		return utils.NewError(c.PutEvents, "no calendar events provided", c, nil)
	} else if cal := components.NewCalendar(events...); events[0] == nil {
		return utils.NewError(c.PutEvents, "icalendar event must not be nil", c, nil)
	} else if err := c.PutCalendars(path, cal); err != nil {
		return utils.NewError(c.PutEvents, "unable to put calendar", c, err)
	}
	return nil
}
Beispiel #10
0
func (c *CalendarData) CalendarComponent() (*components.Calendar, error) {
	cal := new(components.Calendar)
	if content := strings.TrimSpace(c.Content); content == "" {
		return nil, utils.NewError(c.CalendarComponent, "no calendar data to decode", c, nil)
	} else if err := icalendar.Unmarshal(content, cal); err != nil {
		return nil, utils.NewError(c.CalendarComponent, "decoding calendar data failed", c, err)
	} else {
		return cal, nil
	}
}
Beispiel #11
0
func hydrateComponent(v reflect.Value, component *token) error {
	if tag, err := extractTagFromValue(v); err != nil {
		return utils.NewError(hydrateComponent, "error extracting tag from value", component, err)
	} else if tag != component.name {
		msg := fmt.Sprintf("expected %s and found %s", tag, component.name)
		return utils.NewError(hydrateComponent, msg, component, nil)
	} else if err := hydrateProperties(v, component); err != nil {
		return utils.NewError(hydrateComponent, "unable to hydrate properties", component, err)
	}
	return nil
}
Beispiel #12
0
// decodes the geo value from the iCalendar specification
func (g *Geo) DecodeICalValue(value string) error {
	if latlng := strings.Split(value, " "); len(latlng) < 2 {
		return utils.NewError(g.DecodeICalValue, "geo value must have both a latitude and longitude component", g, nil)
	} else if lat, err := strconv.ParseFloat(latlng[0], 64); err != nil {
		return utils.NewError(g.DecodeICalValue, "unable to decode latitude component", g, err)
	} else if lng, err := strconv.ParseFloat(latlng[1], 64); err != nil {
		return utils.NewError(g.DecodeICalValue, "unable to decode latitude component", g, err)
	} else {
		*g = Geo{coords: []float64{lat, lng}}
		return nil
	}
}
Beispiel #13
0
// creates or updates one or more calendars on the remote CalDAV server
func (c *Client) PutCalendars(path string, calendars ...*components.Calendar) error {
	if req, err := c.Server().NewRequest("PUT", path, calendars); err != nil {
		return utils.NewError(c.PutCalendars, "unable to encode request", c, err)
	} else if resp, err := c.Do(req); err != nil {
		return utils.NewError(c.PutCalendars, "unable to execute request", c, err)
	} else if resp.StatusCode != http.StatusCreated && resp.StatusCode != http.StatusNoContent {
		err := new(entities.Error)
		resp.WebDAV().Decode(err)
		msg := fmt.Sprintf("unexpected server response %s", resp.Status)
		return utils.NewError(c.PutCalendars, msg, c, err)
	}
	return nil
}
Beispiel #14
0
// creates a new CalDAV request object
func NewRequest(method string, urlstr string, icaldata ...interface{}) (*Request, error) {
	if buffer, err := icalToReadCloser(icaldata...); err != nil {
		return nil, utils.NewError(NewRequest, "unable to encode icalendar data", icaldata, err)
	} else if r, err := http.NewRequest(method, urlstr, buffer); err != nil {
		return nil, utils.NewError(NewRequest, "unable to create request", urlstr, err)
	} else {
		if buffer != nil {
			// set the content type to XML if we have a body
			r.Native().Header.Set("Content-Type", "text/calendar; charset=UTF-8")
		}
		return (*Request)(r), nil
	}
}
Beispiel #15
0
// deletes a resource if it exists on a particular path
func (c *Client) Delete(path string) error {
	if req, err := c.Server().NewRequest("DELETE", path); err != nil {
		return utils.NewError(c.Delete, "unable to create request", c, err)
	} else if resp, err := c.Do(req); err != nil {
		return utils.NewError(c.Delete, "unable to execute request", c, err)
	} else if resp.StatusCode != nhttp.StatusNoContent && resp.StatusCode != nhttp.StatusNotFound {
		err := new(entities.Error)
		resp.Decode(err)
		msg := fmt.Sprintf("unexpected server response %s", resp.Status)
		return utils.NewError(c.Delete, msg, c, err)
	} else {
		return nil
	}
}
Beispiel #16
0
// decodes the datetime params from the iCalendar specification
func (d *DateTime) DecodeICalParams(params properties.Params) error {
	layout := DateTimeFormatString
	value := d.t.Format(layout)
	if name, found := params[properties.TimeZoneIdPropertyName]; !found {
		return nil
	} else if loc, err := time.LoadLocation(name); err != nil {
		return utils.NewError(d.DecodeICalValue, "unable to parse timezone", d, err)
	} else if t, err := time.ParseInLocation(layout, value, loc); err != nil {
		return utils.NewError(d.DecodeICalValue, "unable to parse datetime value", d, err)
	} else {
		d.t = t
		return nil
	}
}
Beispiel #17
0
// creates a new calendar collection on a given path
func (c *Client) MakeCalendar(path string) error {
	if req, err := c.Server().NewRequest("MKCALENDAR", path); err != nil {
		return utils.NewError(c.MakeCalendar, "unable to create request", c, err)
	} else if resp, err := c.Do(req); err != nil {
		return utils.NewError(c.MakeCalendar, "unable to execute request", c, err)
	} else if resp.StatusCode != http.StatusCreated {
		err := new(entities.Error)
		resp.Decode(err)
		msg := fmt.Sprintf("unexpected server response %s", resp.Status)
		return utils.NewError(c.MakeCalendar, msg, c, err)
	} else {
		return nil
	}
}
Beispiel #18
0
// decodes a CalDAV iCalendar response into the provided interface
func (r *Response) Decode(into interface{}) error {
	if body := r.Body; body == nil {
		return nil
	} else if encoded, err := ioutil.ReadAll(body); err != nil {
		return utils.NewError(r.Decode, "unable to read response body", r, err)
	} else {
		// log.Printf("IN: %+v", string(encoded))
		if err := icalendar.Unmarshal(string(encoded), into); err != nil {
			return utils.NewError(r.Decode, "unable to decode response body", r, err)
		} else {
			return nil
		}
	}
}
Beispiel #19
0
func hydrateProperties(v reflect.Value, component *token) error {

	vdref := dereferencePointerValue(v)
	vtype := vdref.Type()
	vkind := vdref.Kind()

	if vkind != reflect.Struct {
		return utils.NewError(hydrateProperties, "unable to hydrate properties of non-struct", v, nil)
	}

	n := vtype.NumField()
	for i := 0; i < n; i++ {

		prop := properties.PropertyFromStructField(vtype.Field(i))
		if prop == nil {
			continue // skip if field is ignored
		}

		vfield := vdref.Field(i)

		// first try to hydrate property values
		if properties, ok := component.properties[prop.Name]; ok {
			for _, prop := range properties {
				if err := hydrateProperty(vfield, prop); err != nil {
					msg := fmt.Sprintf("unable to hydrate property %s", prop.Name)
					return utils.NewError(hydrateProperties, msg, v, err)
				}
			}
		}

		// then try to hydrate components
		vtemp, _ := newValue(vfield)
		if tag, err := extractTagFromValue(vtemp); err != nil {
			msg := fmt.Sprintf("unable to extract tag from property %s", prop.Name)
			return utils.NewError(hydrateProperties, msg, v, err)
		} else if components, ok := component.components[tag]; ok {
			for _, comp := range components {
				if err := hydrateNestedComponent(vfield, comp); err != nil {
					msg := fmt.Sprintf("unable to hydrate component %s", prop.Name)
					return utils.NewError(hydrateProperties, msg, v, err)
				}
			}
		}
	}

	return nil

}
Beispiel #20
0
// decodes encoded icalendar data into a native interface
func Unmarshal(encoded string, into interface{}) error {
	if component, err := tokenize(encoded); err != nil {
		return utils.NewError(Unmarshal, "unable to tokenize encoded data", encoded, err)
	} else {
		return hydrateValue(reflect.ValueOf(into), component)
	}
}
Beispiel #21
0
// encodes a list of datetime values for the iCalendar specification
func (ds *DateTimes) DecodeICalValue(value string) error {
	csv := new(CSV)
	if err := csv.DecodeICalValue(value); err != nil {
		return utils.NewError(ds.DecodeICalValue, "unable to decode datetime list as CSV", ds, err)
	}
	for i, value := range *csv {
		d := new(DateTime)
		if err := d.DecodeICalValue(value); err != nil {
			msg := fmt.Sprintf("unable to decode datetime at index %d", i)
			return utils.NewError(ds.DecodeICalValue, msg, ds, err)
		} else {
			*ds = append(*ds, d)
		}
	}
	return nil
}
Beispiel #22
0
// executes an HTTP request
func (c *Client) Do(req *Request) (*Response, error) {
	if resp, err := c.Native().Do((*http.Request)(req)); err != nil {
		return nil, utils.NewError(c.Do, "unable to execute HTTP request", c, err)
	} else {
		return NewResponse(resp), nil
	}
}
Beispiel #23
0
// validates the URL for iCalendar format
func (u *Url) ValidateICalValue() error {
	if _, err := url.Parse(u.u.String()); err != nil {
		return utils.NewError(u.ValidateICalValue, "invalid URL object", u, err)
	} else {
		return nil
	}
}
Beispiel #24
0
func csvToInts(value string) (ints []int, err error) {
	csv := new(CSV)
	if ierr := csv.DecodeICalValue(value); err != nil {
		err = utils.NewError(csvToInts, "unable to decode CSV value", value, ierr)
		return
	}
	for _, v := range *csv {
		if i, ierr := strconv.ParseInt(v, 10, 64); err != nil {
			err = utils.NewError(csvToInts, "unable to parse int value "+v, value, ierr)
			return
		} else {
			ints = append(ints, int(i))
		}
	}
	return
}
Beispiel #25
0
// creates a reference to a CalDAV server
func NewServer(baseUrlStr string) (*Server, error) {
	if s, err := webdav.NewServer(baseUrlStr); err != nil {
		return nil, utils.NewError(NewServer, "unable to create WebDAV server", baseUrlStr, err)
	} else {
		return (*Server)(s), nil
	}
}
Beispiel #26
0
// executes a CalDAV request
func (c *Client) Do(req *Request) (*Response, error) {
	if resp, err := c.WebDAV().Do((*webdav.Request)(req)); err != nil {
		return nil, utils.NewError(c.Do, "unable to execute CalDAV request", c, err)
	} else {
		return NewResponse(resp), nil
	}
}
Beispiel #27
0
// validates the datetime value against the iCalendar specification
func (d *DateTime) ValidateICalValue() error {

	loc := d.t.Location()

	if loc == time.Local {
		msg := "DateTime location may not Local, please use UTC or explicit Location"
		return utils.NewError(d.ValidateICalValue, msg, d, nil)
	}

	if loc.String() == "" {
		msg := "DateTime location must have a valid name"
		return utils.NewError(d.ValidateICalValue, msg, d, nil)
	}

	return nil
}
Beispiel #28
0
// attempts to fetch an event on the remote CalDAV server
func (c *Client) GetEvents(path string) ([]*components.Event, error) {
	cal := new(components.Calendar)
	if req, err := c.Server().NewRequest("GET", path); err != nil {
		return nil, utils.NewError(c.GetEvents, "unable to create request", c, err)
	} else if resp, err := c.Do(req); err != nil {
		return nil, utils.NewError(c.GetEvents, "unable to execute request", c, err)
	} else if resp.StatusCode != http.StatusOK {
		err := new(entities.Error)
		resp.WebDAV().Decode(err)
		msg := fmt.Sprintf("unexpected server response %s", resp.Status)
		return nil, utils.NewError(c.GetEvents, msg, c, err)
	} else if err := resp.Decode(cal); err != nil {
		return nil, utils.NewError(c.GetEvents, "unable to decode response", c, err)
	} else {
		return cal.Events, nil
	}
}
Beispiel #29
0
// decodes the recurrence rule value from the iCalendar specification
func (r *RecurrenceRule) DecodeICalValue(value string) error {

	matches := rruleParamRegExp.FindAllStringSubmatch(value, -1)
	if len(matches) <= 0 {
		return utils.NewError(r.DecodeICalValue, "no recurrence rules found", r, nil)
	}

	for _, match := range matches {
		if err := r.decodeICalValue(match[1], match[2]); err != nil {
			msg := fmt.Sprintf("unable to decode %s value", match[1])
			return utils.NewError(r.DecodeICalValue, msg, r, err)
		}
	}

	return nil

}
Beispiel #30
0
// decodes the URL from iCalendar format
func (u *Url) DecodeICalValue(value string) error {
	if parsed, err := url.Parse(value); err != nil {
		return utils.NewError(u.ValidateICalValue, "unable to parse url", u, err)
	} else {
		u.u = *parsed
		return nil
	}
}