From: David Levine Date: Sat, 10 Nov 2018 17:35:31 +0000 (-0500) Subject: Added -attendee switch to mhical(1). X-Git-Url: https://diplodocus.org/git/nmh/commitdiff_plain/b13d382fa17b1983a6fe07facee43e1e2a916e57?ds=inline;hp=-c Added -attendee switch to mhical(1). This allows the user to select which of their attendee addresses they are responding about, when they have more than one in the invitation. Added corresponding -a switch to calaccept, etc., functions in replaliases. Updated mhical to retain DESCRIPTION lines. Gmail puts a link to the event DESCRIPTION line along with a message to no edit that section, though it seems to accept responses if the DESCRIPTION line was removed. Incremented mhical version number to 0.5. --- b13d382fa17b1983a6fe07facee43e1e2a916e57 diff --git a/docs/contrib/replaliases b/docs/contrib/replaliases index efc249c1..077965c1 100644 --- a/docs/contrib/replaliases +++ b/docs/contrib/replaliases @@ -19,6 +19,7 @@ if [ -z "$PARINIT" ]; then export PARINIT fi + #### Reply, including text/html (converted to text/plain) and #### text/plain parts. #### @@ -57,24 +58,75 @@ rtm() { } +#### Internal function for use by calendar response functions below. +#### Pulls "-a address" out of command line arguments. +mhical_attendee() { + mhical_prev= + mhical_attendee= + for arg in "$@"; do + test "$mhical_prev" = -a && mhical_attendee="$arg" + mhical_prev="$arg" + done + unset arg + unset mhical_prev + echo "$mhical_attendee" +} + + #### accept a calendar request +#### usage: calaccept [-a address] [repl switches] +#### -a specifies attendee, see mhical(1) +#### Other arguments passed to repl(1). calaccept() { + if [ "$1" = -a ]; then + attendee=' -attendee '`mhical_attendee "$@"` + shift; shift + else + attendee= + fi \repl -noformat -editor mhbuild \ - -convertargs text/calendar '-reply accept -contenttype' "$@" + -convertargs text/calendar "-reply accept -contenttype${attendee}" \ + "$@" + unset attendee } + #### decline a calendar request +#### usage: caldecline [-a address] [repl switches] +#### -a specifies attendee, see mhical(1) +#### Other arguments passed to repl(1). caldecline() { + if [ "$1" = -a ]; then + attendee=' -attendee '`mhical_attendee "$@"` + shift; shift + else + attendee= + fi \repl -noformat -editor mhbuild \ - -convertargs text/calendar '-reply decline -contenttype' "$@" + -convertargs text/calendar "-reply decline -contenttype${attendee}" \ + "$@" + unset attendee } + #### reply as tentative to a calendar request +#### usage: caltentative [-a address] [repl switches] +#### -a specifies attendee, see mhical(1) +#### Other arguments passed to repl(1). caltentative() { + if [ "$1" = -a ]; then + attendee=' -attendee '`mhical_attendee "$@"` + shift; shift + else + attendee= + fi \repl -noformat -editor mhbuild \ - -convertargs text/calendar '-reply tentative -contenttype' "$@" + -convertargs text/calendar "-reply tentative -contenttype${attendee}" \ + "$@" + unset attendee } + #### cancel a calendar request calcancel() { \repl -noformat -editor mhbuild \ diff --git a/docs/pending-release-notes b/docs/pending-release-notes index 138a909b..d24e1e4a 100644 --- a/docs/pending-release-notes +++ b/docs/pending-release-notes @@ -19,3 +19,5 @@ DEPRECATED FEATURES BUG FIXES --------- +- An -attendee switch has been added to mhical(1), for use when more than one + (or zero) attendees match a user's mailbox. diff --git a/man/mhical.man b/man/mhical.man index 0aaf6b09..72ee8999 100644 --- a/man/mhical.man +++ b/man/mhical.man @@ -17,6 +17,8 @@ mhical \- nmh's manipulator of iCalendar event requests .RB [[ \-reply .IR "accept" " | " "decline" " | " "tentative" "] |" .BR \-cancel ] +.RB [ \-attendee +.IR address ] .RB [ \-contenttype ] .RB [ \-infile .IR infile ] @@ -102,6 +104,13 @@ action parameter must be one of .IR "decline" ", or" .IR "tentative" . Delegation is not supported. +.PP +If one of your mailboxes matches more than one attendee in the request, the +.B \-attendee +switch must be used to select the one to use in the reply. The +.B \-attendee +switch can also be used to specify the attendee address if no attendees match +any of your mailboxes. .SS Cancel The .B \-cancel @@ -154,6 +163,7 @@ is checked. .SH "SEE ALSO" .IR mhbuild (1), .IR mh\-format (5), +.IR mh\-profile (5), .IR tzset (3), .IR repl (1) .SH DEFAULTS @@ -166,3 +176,9 @@ is checked. .B mhical supports only a very limited subset of RRULE formats. Specifically, only a frequency of YEARLY and an interval of 1 are supported. +.PP +.B mhical +produces output with just newlines instead of carriage return-newline +combinations. This is intentional, to fit with typical +.B nmh +convention. diff --git a/test/mhical/test-mhical b/test/mhical/test-mhical index 72c55f5d..3ebc35f5 100755 --- a/test/mhical/test-mhical +++ b/test/mhical/test-mhical @@ -41,6 +41,7 @@ Usage: mhical [switches] -(forma)t string -infile -outfile + -attendee -[no]contenttype -unfold -debug @@ -335,7 +336,7 @@ start_test "accept of request" cat >"$expected" <<'EOF' BEGIN:VCALENDAR METHOD:REPLY -PRODID:nmh mhical v0.1 +PRODID:nmh mhical v0.5 VERSION:2.0 BEGIN:VTIMEZONE TZID:Eastern Standard Time @@ -421,12 +422,115 @@ mhical -reply accept <"$MH_TEST_DIR/test1.ics" | egrep -v '^DTSTAMP:' \ >"$MH_TEST_DIR/test1.txt" check "$expected" "$MH_TEST_DIR/test1.txt" + +# check accept of request with -attendee +start_test "accept of request with -attendee" +cat >"$expected" <<'EOF' +BEGIN:VCALENDAR +METHOD:REPLY +PRODID:nmh mhical v0.5 +VERSION:2.0 +BEGIN:VTIMEZONE +TZID:Eastern Standard Time +BEGIN:STANDARD +DTSTART:16010101T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=1SU;BYMONTH=11 +END:STANDARD +BEGIN:DAYLIGHT +DTSTART:16010101T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=2SU;BYMONTH=3 +END:DAYLIGHT +END:VTIMEZONE +BEGIN:VEVENT +ORGANIZER;CN=Requester:MAILTO:requester@example.com +ATTENDEE;PARTSTAT=ACCEPTED;CN=Requestee1:MAILTO:requestee1@example.com +SUMMARY;LANGUAGE=en-US:Accepted: test request +DTSTART;TZID=Eastern Standard Time:20150105T090000 +DTEND;TZID=Eastern Standard Time:20150105T093000 +UID:0123456789 +CLASS:PUBLIC +PRIORITY:5 +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +LOCATION;LANGUAGE=en-US: +END:VEVENT +END:VCALENDAR +EOF + +cp "$MH" "${MH}.save" +printf 'Alternate-Mailboxes: RequesteeToo \n' >> "$MH" +mhical -reply accept -attendee requestee1@example.com <"$MH_TEST_DIR/test1.ics" \ + | egrep -v '^DTSTAMP:' >"$MH_TEST_DIR/test1.txt" +check "$expected" "$MH_TEST_DIR/test1.txt" + + +# check accept of request with other -attendee +start_test "accept of request with other -attendee" +cat >"$expected" <<'EOF' +BEGIN:VCALENDAR +METHOD:REPLY +PRODID:nmh mhical v0.5 +VERSION:2.0 +BEGIN:VTIMEZONE +TZID:Eastern Standard Time +BEGIN:STANDARD +DTSTART:16010101T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=1SU;BYMONTH=11 +END:STANDARD +BEGIN:DAYLIGHT +DTSTART:16010101T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=2SU;BYMONTH=3 +END:DAYLIGHT +END:VTIMEZONE +BEGIN:VEVENT +ORGANIZER;CN=Requester:MAILTO:requester@example.com +ATTENDEE;PARTSTAT=ACCEPTED;CN=Requestee2:MAILTO:requestee2@example.com +SUMMARY;LANGUAGE=en-US:Accepted: test request +DTSTART;TZID=Eastern Standard Time:20150105T090000 +DTEND;TZID=Eastern Standard Time:20150105T093000 +UID:0123456789 +CLASS:PUBLIC +PRIORITY:5 +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +LOCATION;LANGUAGE=en-US: +END:VEVENT +END:VCALENDAR +EOF + +mhical -reply accept -attendee requestee2@example.com <"$MH_TEST_DIR/test1.ics" \ + | egrep -v '^DTSTAMP:' >"$MH_TEST_DIR/test1.txt" +check "$expected" "$MH_TEST_DIR/test1.txt" + + +# check accept of request without required -attendee +start_test "accept of request without required -attendee" +cat >"$expected" <<'EOF' +mhical: Multiple attendees match your address, re-run with -attendee switch +EOF + +mhical -reply accept <"$MH_TEST_DIR/test1.ics" 2>"$MH_TEST_DIR/test1.txt" \ + && false +check "$expected" "$MH_TEST_DIR/test1.txt" +mv "${MH}.save" "$MH" + + # check accept of multiple vevent requests in single vcalendar start_test "accept of multiple vevent requests in single vcalendar" cat >"$expected" <<'EOF' BEGIN:VCALENDAR METHOD:REPLY -PRODID:nmh mhical v0.1 +PRODID:nmh mhical v0.5 VERSION:2.0 BEGIN:VTIMEZONE TZID:Eastern Standard Time @@ -560,7 +664,7 @@ start_test "decline of request" cat >"$expected" <<'EOF' BEGIN:VCALENDAR METHOD:REPLY -PRODID:nmh mhical v0.1 +PRODID:nmh mhical v0.5 VERSION:2.0 BEGIN:VEVENT ORGANIZER;CN=Requester:MAILTO:requester@example.com @@ -622,7 +726,7 @@ start_test "response of tentative to request, and -nocontenttype" cat >"$expected" <<'EOF' BEGIN:VCALENDAR METHOD:REPLY -PRODID:nmh mhical v0.1 +PRODID:nmh mhical v0.5 VERSION:2.0 BEGIN:VEVENT ORGANIZER;CN=Requester:MAILTO:requester@example.com @@ -687,7 +791,7 @@ Content-Type: text/calendar; method="CANCEL"; charset="UTF-8" BEGIN:VCALENDAR METHOD:CANCEL -PRODID:nmh mhical v0.1 +PRODID:nmh mhical v0.5 VERSION:2.0 BEGIN:VEVENT ORGANIZER;CN=Requestee2:MAILTO:requestee2@example.com diff --git a/test/repl/test-convert b/test/repl/test-convert index 0cbc1314..faa1117f 100755 --- a/test/repl/test-convert +++ b/test/repl/test-convert @@ -280,7 +280,7 @@ Content-Type: text/calendar; method="REPLY"; charset="UTF-8" BEGIN:VCALENDAR METHOD:REPLY -PRODID:nmh mhical v0.1 +PRODID:nmh mhical v0.5 VERSION:2.0 BEGIN:VTIMEZONE TZID:Eastern Standard Time diff --git a/uip/mhical.c b/uip/mhical.c index 8025c02f..078ad37e 100644 --- a/uip/mhical.c +++ b/uip/mhical.c @@ -34,7 +34,7 @@ typedef enum act { ACT_CANCEL } act; -static void convert_to_reply (contentline *, act); +static int convert_to_reply (contentline *, act, char *); static void convert_to_cancellation (contentline *); static void convert_common (contentline *, act); static void dump_unfolded (FILE *, contentline *); @@ -51,6 +51,7 @@ static char *fold (char *, int); X("format string", 5, FMTSW) \ X("infile", 0, INFILESW) \ X("outfile", 0, OUTFILESW) \ + X("attendee", 0, ATTENDEESW) \ X("contenttype", 0, CONTENTTYPESW) \ X("nocontenttype", 0, NCONTENTTYPESW) \ X("unfold", 0, UNFOLDSW) \ @@ -81,6 +82,7 @@ main (int argc, char *argv[]) act action = ACT_NONE; char *infile = NULL, *outfile = NULL; FILE *inputfile = NULL, *outputfile = NULL; + char *attendee = NULL; bool contenttype = false; bool unfold = false; vevent *v, *nextvevent; @@ -161,6 +163,12 @@ main (int argc, char *argv[]) outfile = *cp == '-' ? mh_xstrdup(cp) : path (cp, TFILE); continue; + case ATTENDEESW: + if (! (cp = *argp++) || (*cp == '-' && cp[1])) + die("missing argument to %s", argp[-2]); + attendee = cp; + continue; + case CONTENTTYPESW: contenttype = true; continue; @@ -225,9 +233,12 @@ main (int argc, char *argv[]) if (action == ACT_CANCEL) { convert_to_cancellation (v->contentlines); } else { - convert_to_reply (v->contentlines, action); + parser_status += + convert_to_reply (v->contentlines, action, attendee); + } + if (parser_status == 0) { + output (outputfile, v->contentlines, contenttype); } - output (outputfile, v->contentlines, contenttype); } free_contentlines (v->contentlines); @@ -250,13 +261,15 @@ main (int argc, char *argv[]) free (outfile); } - return parser_status; + return parser_status > 0 ? 1 : 0; } /* * - Change METHOD from REQUEST to REPLY. * - Change PRODID. - * - Remove all ATTENDEE lines for other users (based on ismymbox ()). + * - Remove all ATTENDEE lines for other users (based on ismymbox()). + * If more than one address matches ismymbox(), the attendee argument, + * from the -attendee switch, must be used to select one. * - For the user's ATTENDEE line: * - Remove ROLE and RSVP parameters. * - Change PARTSTAT value to indicate reply action, e.g., ACCEPTED, @@ -264,14 +277,13 @@ main (int argc, char *argv[]) * - Insert action at beginning of SUMMARY value. * - Remove all X- lines. * - Update DTSTAMP with current timestamp. - * - Remove all DESCRIPTION lines. * - Excise VALARM sections. */ -static void -convert_to_reply (contentline *clines, act action) +static int +convert_to_reply (contentline *clines, act action, char *attendee) { char *partstat = NULL; - bool found_my_attendee_line = false; + unsigned int found_my_attendee_line = 0; contentline *node; convert_common (clines, action); @@ -314,8 +326,9 @@ convert_to_reply (contentline *clines, act action) /* Need to flush getname after use. */ while (getname ("")) { continue; } - if (ismymbox (mn)) { - found_my_attendee_line = true; + if (ismymbox (mn) && + (attendee == NULL || ! strcasecmp(mn->m_text, attendee))) { + ++found_my_attendee_line; for (p = node->params; p && p->param_name; p = p->next) { value_list *v; @@ -337,7 +350,7 @@ convert_to_reply (contentline *clines, act action) } } - if (! found_my_attendee_line) { + if (found_my_attendee_line == 0) { /* Generate and attach an ATTENDEE line for me. */ contentline *node; @@ -352,16 +365,13 @@ convert_to_reply (contentline *clines, act action) add_param_value (new_node, mh_xstrdup (getfullname ())); new_node->value = concat ("MAILTO:", getlocalmbox (), NULL); } + } else if (found_my_attendee_line > 1) { + inform("Multiple attendees match your address, " + "re-run with -attendee switch"); + return 1; } - /* Call find_contentline () with node as argument to find multiple - matching contentlines. */ - for (node = clines; - (node = find_contentline (node, "DESCRIPTION", 0)); - node = node->next) { - /* ACCEPT, at least, replies don't seem to have DESCRIPTIONS. */ - remove_contentline (node); - } + return 0; } /* @@ -410,7 +420,7 @@ convert_common (contentline *clines, act action) if ((node = find_contentline (clines, "PRODID", 0))) { free (node->value); - node->value = mh_xstrdup ("nmh mhical v0.1"); + node->value = mh_xstrdup ("nmh mhical v0.5"); } if ((node = find_contentline (clines, "VERSION", 0))) { @@ -421,8 +431,8 @@ convert_common (contentline *clines, act action) if (strcmp (node->value, "2.0")) { inform("supports the Version 2.0 specified by RFC 5545 " - "but iCalendar object has Version %s, continuing...", - node->value); + "but iCalendar object has Version %s, continuing...", + node->value); node->value = mh_xstrdup ("2.0"); } }