diff --git a/src/calanonsync/calanonsync.go b/src/calanonsync/calanonsync.go index f5f67f0..460d2ea 100644 --- a/src/calanonsync/calanonsync.go +++ b/src/calanonsync/calanonsync.go @@ -1,155 +1,11 @@ package main import ( - "bytes" - "encoding/xml" "fmt" - "io" "log" - "net/http" - "net/http/cookiejar" - "strings" - "text/template" "time" ) -type FolderId struct { - Id string `xml:",attr"` - ChangeKey string `xml:",attr"` -} - -type CalendarItem struct { - Subject string - UID string - Start time.Time - End time.Time -} - -type EWSCalendar struct { - httpClient *http.Client - url string - username string - password string -} - -func NewEWSCalendar(url, username, password string) *EWSCalendar { - // Prepare a cookie jar, since EWS uses some. - jar, err := cookiejar.New(nil) - if err != nil { - panic(err) - } - return &EWSCalendar{ - httpClient: &http.Client{ - Jar: jar, - }, - url: url, - username: username, - password: password, - } -} - -func (e *EWSCalendar) prepareRequest(body io.Reader) (req *http.Request, err error) { - req, err = http.NewRequest(http.MethodPost, e.url, body) - req.Header.Set("Content-Type", "text/xml") - req.Header.Set("Accept", "text/xml") - req.SetBasicAuth(e.username, e.password) - return -} - -func (e *EWSCalendar) getCalendarFolderID() (id *FolderId, err error) { - req, err := e.prepareRequest(strings.NewReader(folderIdRequest)) - if err != nil { - return - } - - resp, err := e.httpClient.Do(req) - if err != nil { - return - } - - if resp.StatusCode != http.StatusOK { - err = fmt.Errorf("unexpected status when querying folderID: %d", resp.StatusCode) - return - } - - d := xml.NewDecoder(resp.Body) - defer resp.Body.Close() - - for { - var t xml.Token - t, err = d.Token() - if err == io.EOF { - err = nil - return - } else if err != nil { - return - } - - switch t := t.(type) { - case xml.StartElement: - if t.Name.Local == "FolderId" { - id = &FolderId{} - err = d.DecodeElement(id, &t) - // The first one is enough - return - } - } - } -} - -func (e *EWSCalendar) getCalendarItems(folder *FolderId, start, end time.Time) (items []CalendarItem, err error) { - b := &bytes.Buffer{} - model := struct { - FolderId *FolderId - StartDate string - EndDate string - }{folder, start.Format(time.RFC3339), end.Format(time.RFC3339)} - - err = calendarQuery.Execute(b, &model) - if err != nil { - return - } - - req, err := e.prepareRequest(b) - if err != nil { - return - } - - resp, err := e.httpClient.Do(req) - if err != nil { - return - } - - if resp.StatusCode != http.StatusOK { - err = fmt.Errorf("unexpected status when querying calendar items: %d", resp.StatusCode) - return - } - - d := xml.NewDecoder(resp.Body) - defer resp.Body.Close() - - for { - var t xml.Token - t, err = d.Token() - if err == io.EOF { - err = nil - return - } else if err != nil { - return - } - - switch t := t.(type) { - case xml.StartElement: - if t.Name.Local == "CalendarItem" { - item := CalendarItem{} - err = d.DecodeElement(&item, &t) - items = append(items, item) - } - } - } - return -} - func main() { s := LoadSettings() @@ -181,49 +37,3 @@ func main() { item.HRef, item.UID(), item.Summary(), item.Start(), item.End()) } } - -const folderIdRequest = ` - - - - - - - - AllProperties - - - - - - -` - -var calendarQuery = template.Must(template.New("calendarQuery").Parse(` - - - - - - - - IdOnly - - - - - - - - - - - - - - - - - - -`)) diff --git a/src/calanonsync/ews.go b/src/calanonsync/ews.go new file mode 100644 index 0000000..7002687 --- /dev/null +++ b/src/calanonsync/ews.go @@ -0,0 +1,196 @@ +package main + +import ( + "bytes" + "encoding/xml" + "fmt" + "io" + "net/http" + "net/http/cookiejar" + "strings" + "text/template" + "time" +) + +type FolderId struct { + Id string `xml:",attr"` + ChangeKey string `xml:",attr"` +} + +type CalendarItem struct { + Subject string + UID string + Start time.Time + End time.Time +} + +type EWSCalendar struct { + httpClient *http.Client + url string + username string + password string +} + +func NewEWSCalendar(url, username, password string) *EWSCalendar { + // Prepare a cookie jar, since EWS uses some. + jar, err := cookiejar.New(nil) + if err != nil { + panic(err) + } + return &EWSCalendar{ + httpClient: &http.Client{ + Jar: jar, + }, + url: url, + username: username, + password: password, + } +} + +func (e *EWSCalendar) prepareRequest(body io.Reader) (req *http.Request, err error) { + req, err = http.NewRequest(http.MethodPost, e.url, body) + req.Header.Set("Content-Type", "text/xml") + req.Header.Set("Accept", "text/xml") + req.SetBasicAuth(e.username, e.password) + return +} + +func (e *EWSCalendar) getCalendarFolderID() (id *FolderId, err error) { + req, err := e.prepareRequest(strings.NewReader(folderIdRequest)) + if err != nil { + return + } + + resp, err := e.httpClient.Do(req) + if err != nil { + return + } + + if resp.StatusCode != http.StatusOK { + err = fmt.Errorf("unexpected status when querying folderID: %d", resp.StatusCode) + return + } + + d := xml.NewDecoder(resp.Body) + defer resp.Body.Close() + + for { + var t xml.Token + t, err = d.Token() + if err == io.EOF { + err = nil + return + } else if err != nil { + return + } + + switch t := t.(type) { + case xml.StartElement: + if t.Name.Local == "FolderId" { + id = &FolderId{} + err = d.DecodeElement(id, &t) + // The first one is enough + return + } + } + } +} + +func (e *EWSCalendar) getCalendarItems(folder *FolderId, start, end time.Time) (items []CalendarItem, err error) { + b := &bytes.Buffer{} + model := struct { + FolderId *FolderId + StartDate string + EndDate string + }{folder, start.Format(time.RFC3339), end.Format(time.RFC3339)} + + err = calendarQuery.Execute(b, &model) + if err != nil { + return + } + + req, err := e.prepareRequest(b) + if err != nil { + return + } + + resp, err := e.httpClient.Do(req) + if err != nil { + return + } + + if resp.StatusCode != http.StatusOK { + err = fmt.Errorf("unexpected status when querying calendar items: %d", resp.StatusCode) + return + } + + d := xml.NewDecoder(resp.Body) + defer resp.Body.Close() + + for { + var t xml.Token + t, err = d.Token() + if err == io.EOF { + err = nil + return + } else if err != nil { + return + } + + switch t := t.(type) { + case xml.StartElement: + if t.Name.Local == "CalendarItem" { + item := CalendarItem{} + err = d.DecodeElement(&item, &t) + items = append(items, item) + } + } + } + return +} + +const folderIdRequest = ` + + + + + + + + AllProperties + + + + + + +` + +var calendarQuery = template.Must(template.New("calendarQuery").Parse(` + + + + + + + + IdOnly + + + + + + + + + + + + + + + + + + +`))