diff options
| -rw-r--r-- | icalproxy.go | 54 |
1 files changed, 54 insertions, 0 deletions
diff --git a/icalproxy.go b/icalproxy.go index 0a3ea36..152eed6 100644 --- a/icalproxy.go +++ b/icalproxy.go | |||
| @@ -5,6 +5,7 @@ import ( | |||
| 5 | "log" | 5 | "log" |
| 6 | "net/http" | 6 | "net/http" |
| 7 | "net/url" | 7 | "net/url" |
| 8 | "strings" | ||
| 8 | "time" | 9 | "time" |
| 9 | 10 | ||
| 10 | "github.com/emersion/go-ical" | 11 | "github.com/emersion/go-ical" |
| @@ -15,10 +16,16 @@ func main() { | |||
| 15 | cfg := loadConfig() | 16 | cfg := loadConfig() |
| 16 | printConfig(&cfg) | 17 | printConfig(&cfg) |
| 17 | 18 | ||
| 19 | amsTz, err := time.LoadLocation("Europe/Amsterdam") | ||
| 20 | if err != nil { | ||
| 21 | log.Fatalln("Failed to load time zone", err) | ||
| 22 | } | ||
| 23 | |||
| 18 | handler := handler{ | 24 | handler := handler{ |
| 19 | calURL: url.URL(cfg.CalendarURL.v), | 25 | calURL: url.URL(cfg.CalendarURL.v), |
| 20 | ignore: cfg.Ignore, | 26 | ignore: cfg.Ignore, |
| 21 | tokens: cfg.UserTokens, | 27 | tokens: cfg.UserTokens, |
| 28 | amsTz: amsTz, | ||
| 22 | } | 29 | } |
| 23 | 30 | ||
| 24 | mux := http.ServeMux{} | 31 | mux := http.ServeMux{} |
| @@ -40,6 +47,7 @@ type handler struct { | |||
| 40 | ignore ignoreRules | 47 | ignore ignoreRules |
| 41 | tokens map[string]userToken | 48 | tokens map[string]userToken |
| 42 | calURL url.URL | 49 | calURL url.URL |
| 50 | amsTz *time.Location | ||
| 43 | } | 51 | } |
| 44 | 52 | ||
| 45 | func (h handler) makeTokenURL(token string) string { | 53 | func (h handler) makeTokenURL(token string) string { |
| @@ -72,6 +80,7 @@ func (h handler) handle(w http.ResponseWriter, r *http.Request) { | |||
| 72 | } | 80 | } |
| 73 | 81 | ||
| 74 | filter(h.ignore, cal.Component) | 82 | filter(h.ignore, cal.Component) |
| 83 | skewMidnightDeadlines(h.amsTz, cal.Component) | ||
| 75 | 84 | ||
| 76 | if err = ical.NewEncoder(w).Encode(cal); err != nil { | 85 | if err = ical.NewEncoder(w).Encode(cal); err != nil { |
| 77 | log.Println("Error writing calendar:", err) | 86 | log.Println("Error writing calendar:", err) |
| @@ -108,6 +117,51 @@ func filter(ignore ignoreRules, c *ical.Component) { | |||
| 108 | c.Children = c.Children[:j] | 117 | c.Children = c.Children[:j] |
| 109 | } | 118 | } |
| 110 | 119 | ||
| 120 | // We often see events which are scheduled for exactly 'end of day', i.e. | ||
| 121 | // 23:59:59, with no difference between the start/end time. Unfortunately, | ||
| 122 | // these are not shown properly in two open-source Android calendar apps, so we | ||
| 123 | // monkey-hack the event to start at 23:30 and add a note to the description :) | ||
| 124 | func skewMidnightDeadlines(ams *time.Location, c *ical.Component) { | ||
| 125 | for _, child := range c.Children { | ||
| 126 | if child.Name == ical.CompEvent { | ||
| 127 | if summary := child.Props.Get(ical.PropSummary); summary != nil && | ||
| 128 | strings.HasSuffix(summary.Value, " - Due") { | ||
| 129 | |||
| 130 | // Modify the start time of the event | ||
| 131 | startTime, stErr := c.Props.DateTime(ical.PropDateTimeStart, ams) | ||
| 132 | endTime, etErr := c.Props.DateTime(ical.PropDateTimeEnd, ams) | ||
| 133 | if stErr != nil || etErr != nil || startTime.IsZero() || | ||
| 134 | endTime.IsZero() || !startTime.Equal(endTime) || | ||
| 135 | startTime.Hour() != 23 || startTime.Minute() != 59 || | ||
| 136 | startTime.Second() != 59 { | ||
| 137 | continue | ||
| 138 | } | ||
| 139 | newStartTime := time.Date(startTime.Year(), startTime.Month(), | ||
| 140 | startTime.Day(), 23, 30, 0, 0, ams) | ||
| 141 | child.Props.SetDateTime(ical.PropDateTimeStart, newStartTime) | ||
| 142 | |||
| 143 | // Update the event description to notify about the change | ||
| 144 | descProp := child.Props.Get(ical.PropDescription) | ||
| 145 | if descProp == nil { | ||
| 146 | descProp = ical.NewProp(ical.PropDescription) | ||
| 147 | } | ||
| 148 | |||
| 149 | curText, err := descProp.Text() | ||
| 150 | if err != nil { | ||
| 151 | // forget about editing the text, at least we 'fixed' the | ||
| 152 | // event time :) | ||
| 153 | continue | ||
| 154 | } | ||
| 155 | curText = "+++ ICALPROXY: DEADLINE MOVED FROM 23:59:59 TO" + | ||
| 156 | "23:30:00 (Europe/Amsterdam) +++\n\n" + curText | ||
| 157 | descProp.SetText(curText) | ||
| 158 | |||
| 159 | child.Props.Set(descProp) | ||
| 160 | } | ||
| 161 | } | ||
| 162 | } | ||
| 163 | } | ||
| 164 | |||
| 111 | func userOK(tokens map[string]userToken, id string, token []byte) bool { | 165 | func userOK(tokens map[string]userToken, id string, token []byte) bool { |
| 112 | info, ok := tokens[id] | 166 | info, ok := tokens[id] |
| 113 | if !ok { | 167 | if !ok { |