5 files changed, 132 insertions(+), 0 deletions(-)

A => README.md
A => go.mod
A => go.sum
A => main.go
A => test.ics
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