A => README.md +45 -0
@@ 0,0 1,45 @@
+icsmailer
+=========
+
+In OSS, it appears nobody wants to be responsible for sending email invitations.
+icsmailer does this for you.
+
+Features
+========
+
+icsmailer is designed to watch a calendar collection and send invites to
+attendees when it detects changes.
+
+- The collection can be either a directory full of calendar events or a WebDAV calendar
+- A database of state is maintained to provide resiliance and record invitation state
+- Email responses (accept/decline/reschedule) are understood and update the database
+- Can be run as a service or on-demand
+- Emails can be handled as either piped data, or file handles
+- Default behavior for reacting to changes configured in config file (email everyone, only changed, no-one) for running as server
+- Per-event reaction handling is interactive when run on-demand
+- PGP signing
+
+
+Non-features
+============
+
+- Event changes (e.g. reacting to reschedule events)
+- Encrypted emails (must be decrypted before icsmailer)
+
+
+Design
+======
+
+icsmailer stands on the shoulders of:
+
+- https://github.com/arran4/golang-ical
+- https://github.com/timshannon/bolthold
+- https://github.com/jordan-wright/email
+
+Alts
+-----
+
+- https://github.com/prologic/bitcask
+- https://github.com/emersion/go-message
+
+
A => go.mod +8 -0
@@ 0,0 1,8 @@
+module ser1.net/icsmailer
+
+go 1.16
+
+require (
+ github.com/arran4/golang-ical v0.0.0-20210601225245-48fd351b08e7
+ github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible
+)
A => go.sum +14 -0
@@ 0,0 1,14 @@
+github.com/arran4/golang-ical v0.0.0-20210601225245-48fd351b08e7 h1:oOgavmDMGCnNtwZwNoXuK3jCcpF3I96Do9/5qPeSCr8=
+github.com/arran4/golang-ical v0.0.0-20210601225245-48fd351b08e7/go.mod h1:3Fo6aCavD4wY7KNzi6z9D6e20a6FdqD/tIaHlU7GnMI=
+github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible h1:jdpOPRN1zP63Td1hDQbZW73xKmzDvZHzVdNYxhnTMDA=
+github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible/go.mod h1:1c7szIrayyPPB/987hsnvNzLushdWf4o/79s3P08L8A=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
A => main.go +31 -0
@@ 0,0 1,31 @@
+package main
+
+import (
+ "fmt"
+ "github.com/arran4/golang-ical"
+ "github.com/cosiner/flag"
+ "github.com/jordan-wright/email"
+ "os"
+)
+
+// TODO send one -- send an email for a specific event
+// TODO send all -- process calendar and send emails for everything not already sent
+// TODO version -- print version
+// TODO stats -- print DB & calendar statistics
+// TODO -Z -- do not record action to DB
+// TODO -N -- NOP do nothing
+// TODO -S -- do not send emails (but record changes in DB as if they were sent)
+// TODO -C -- send only to changed attendees
+// TODO -D -- debug (verbose output)
+// TODO -e -- input is an email
+// TODO -d <path> -- database path
+// TODO -c <path> -- calendar path
+// TODO Replace plain text DB with real embedded DB
+func main() {
+ s := os.Stdin
+ cal, err := ics.ParseCalendar(s)
+ if err != nil {
+ panic(err)
+ }
+ fmt.Println(cal.Serialize())
+}
A => test.ics +34 -0
@@ 0,0 1,34 @@
+BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//PIMUTILS.ORG//NONSGML khal / icalendar //EN
+BEGIN:VTIMEZONE
+TZID:America/Chicago
+BEGIN:DAYLIGHT
+DTSTART;VALUE=DATE-TIME:20190310T030000
+TZNAME:CDT
+TZOFFSETFROM:-0600
+TZOFFSETTO:-0500
+END:DAYLIGHT
+BEGIN:STANDARD
+DTSTART;VALUE=DATE-TIME:20191103T010000
+TZNAME:CST
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0600
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+SUMMARY:Meet Elizabeth Montgomery for martinis
+DTSTART;TZID=America/Chicago;VALUE=DATE-TIME:20190827T081500
+DTEND;TZID=America/Chicago;VALUE=DATE-TIME:20190827T090000
+DTSTAMP;VALUE=DATE-TIME:20190816T143301Z
+UID:VEYKFDTSIJZZ22DKRVHFE3N3T2GKR4X6ZBJV
+SEQUENCE:0
+CATEGORIES:
+LOCATION:That place by the thing
+BEGIN:VALARM
+ACTION:DISPLAY
+DESCRIPTION:
+TRIGGER:-PT1H
+END:VALARM
+END:VEVENT
+END:VCALENDAR