#!/usr/bin/awk -f # ex: ft=awk # # awk filter for aerc to parse text/calendar mime-types # # Based on the ical2org.awk script by Eric S Fraga and updated by Guide Van # Hoecke. Adapted to aerc by Koni Marti # BEGIN { UIDS[0]; people_attending[0]; people_partstat[0]; people_rsvp[0]; # use a colon to separate the type of data line from the actual contents FS = ":"; method = "" prodid = "" first = 0 } /^[ ]/ { # assumes continuation lines start with a space if (indescription) { entry = entry gensub("\r", "", "g", gensub("^[ ]", "", 1, $0)); } else if (insummary) { summary = summary gensub("\r", "", "g", gensub("^[ ]", "", 1, $0)) } else if (inattendee) { attendee = attendee gensub("\r", "", "g", gensub("^[ ]", "", 1, $0)) } else if (inorganizer) { organizer = organizer gensub("\r", "", "g", gensub("^[ ]", "", 1, $0)) } else if (inlocation) { location = location unescape(gensub("\r", "", "g", $0), 0); } } /^BEGIN:VEVENT/ { # start of an event: initialize global values used for each event date = ""; entry = "" id = "" indescription = 0; insummary = 0 inattendee = 0 inorganizer = 0 inlocation = 0 in_alarm = 0 location = "" status = "" summary = "" attendee = "" organizer = "" rrend = "" rcount = "" intfreq = "" delete people_attending; delete people_partstat; delete people_rsvp; if (first == 0) { first = 1 if (method != "") print " METHOD " method if (prodid != "") print " PRODID " prodid print "" } } /^BEGIN:VALARM/ { in_alarm = 1 } /^END:VALARM/ { in_alarm = 0 } /^[A-Z]/ { if (attendee != "" && inattendee==1) add_attendee(attendee) if (organizer != "" && inorganizer==1) organizer = find_full_name(organizer) indescription = 0; insummary = 0; inattendee = 0; inorganizer = 0; inlocation = 0; } /^DTSTART;VALUE=DATE/ { date = datestring($2); } /^DTEND;VALUE=DATE/ { end_date = datestring($2); } /^DTSTART[:;][^V]/ { tz = ""; match($0, /TZID=([^:]*)/, a) { tz = a[1]; } date = datetimestring($2, tz); } /^DTEND[:;][^V]/ { tz = ""; match($0, /TZID=([^:]*)/, a) { tz = a[1]; } end_date = datetimestring($2, tz); } /^RRULE:FREQ=(DAILY|WEEKLY|MONTHLY|YEARLY)/ { # TODO: handle BYDAY values for events that repeat weekly for multiple days # (e.g. a "Gym" event) # get the d, w, m or y value freq = tolower(gensub(/.*FREQ=(.).*/, "\\1", 1, $0)) # get the interval, and use 1 if none specified interval = $0 ~ /INTERVAL=/ ? gensub(/.*INTERVAL=([0-9]+).*/, "\\1", 1, $0) : 1 # get the enddate of the rule and use "" if none specified rrend = $0 ~ /UNTIL=/ ? datestring(gensub(/.*UNTIL=([0-9]{8}).*/, "\\1", 1, $0)) : "" rcount = $0 ~ /COUNT=/ ? gensub(/.*COUNT=([0-9]+).*/, "\\1", 1, $0) : "" # build the repetitor value intfreq = " +" interval freq } /^DESCRIPTION/ { if (!in_alarm) { entry = entry gensub("\r", "", "g", gensub($1":", "", 1, $0)); indescription = 1; } } /^SUMMARY/ { if (!in_alarm) { summary = gensub("\r", "", "g", gensub($1":", "", 1, $0)); insummary = 1; } } /^UID/ { if (!in_alarm) { id = gensub("\r", "", "g", $2); } } /^METHOD/ { method = gensub("\r", "", "g", $2); } /^PRODID/ { prodid = gensub("\r", "", "g", $2); } /^ORGANIZER/ { organizer = gensub("\r", "", "g", $0); inorganizer = 1; } /^LOCATION/ { location = unescape(gensub("\r", "", "g", $2), 0); inlocation = 1; } /^STATUS/ { status = gensub("\r", "", "g", $2); } /^ATTENDEE/ { attendee = gensub("\r", "", "g", $0); inattendee = 1; } /^END:VEVENT/ { #output event is_duplicate = (id in UIDS); if(is_duplicate == 0) { print "* SUMMARY " gensub("^[ ]+", "", "g", unescape(summary, 0)) if(length(location)) print " LOCATION " location if(organizer != "") print " ORGANIZER " organizer for (cn in people_attending) { print " ATTENDEE " cn partstat = people_partstat[cn] if (partstat != "") { print " STATUS " partstat } rsvp = people_rsvp[cn] if (rsvp != "") { print " RSVP " rsvp } } print " START " date print " END " end_date if (intfreq != "") { print "" print " RECURRENCE " intfreq if (rcount != "") print " COUNTS " rcount if (rrend != "") print " END DATE " rrend } print "" if(length(entry)>1) print gensub("^[ ]+", "", "g", unescape(entry, 1)); UIDS[id] = 1; } } function unescape(input, preserve_newlines) { ret = gensub("\\\\,", ",", "g", gensub("\\\\;", ";", "g", input)) if (preserve_newlines) ret = gensub("\\\\n", "\n", "g", ret) else ret = gensub("\\\\n", " ", "g", ret) return ret } function datetimestring(input, tz) { spec = match(input, "([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2})([0-9]{2})([0-9]{2}).*[\r]*", a); year = a[1] month = a[2] day = a[3] hour = a[4] min = a[5] sec = a[6] stamp = mktime(year" "month" "day" "hour" "min" "sec); if (input ~ /[0-9]{8}T[0-9]{6}Z/ ) { tz = "UTC" } return strftime("%Y-%m-%d %a %H:%M", stamp)" "tz; } function datestring(input) { spec = gensub("([0-9]{4})([0-9]{2})([0-9]{2}).*[\r]*", "\\1 \\2 \\3 00 00 00", "g", input); stamp = mktime(spec); return strftime("%Y-%m-%d %a", stamp); } function add_attendee(attendee) { CN = find_full_name(attendee) if (CN != "") people_attending[CN] = 1; if (CN != "") { match(attendee, /PARTSTAT=([^;]+)/, m) { people_partstat[CN] = m[1] } match(attendee, /RSVP=([^;]+)/, m) { people_rsvp[CN] = m[1] } } } function extract_email(line) { email = "" match(line,/:[ ]*(mailto|MAILTO):([^;]+)/, m) { email = m[2] } return email } function extract_name(line) { name = "" match(line,/CN="?([^;:"]+)/, m) { name = m[1] } return name } function find_full_name(line) { name = extract_name(line) email = extract_email(line) if (name == "") { if (email == "") { return "" } else { return name } } if (email == "") return name if (email == name) return "<"email">" return name" <"email">" }