]> diplodocus.org Git - nmh/commitdiff
Added -attendee switch to mhical(1).
authorDavid Levine <levinedl@acm.org>
Sat, 10 Nov 2018 17:35:31 +0000 (12:35 -0500)
committerDavid Levine <levinedl@acm.org>
Sat, 10 Nov 2018 17:35:31 +0000 (12:35 -0500)
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.

docs/contrib/replaliases
docs/pending-release-notes
man/mhical.man
test/mhical/test-mhical
test/repl/test-convert
uip/mhical.c

index efc249c1cc4dc3d433d3e4cde53a2251aa4a2783..077965c1d323c1db772a7d600bff06f8228a701a 100644 (file)
@@ -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 \
index 138a909bb45662649152068e25de06110156af96..d24e1e4a4e07d31746a6e497d18fb320bebba71b 100644 (file)
@@ -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.
index 0aaf6b09b397daca740210f2be211747511df05f..72ee89991e5d0d38823d0a7c550b48d15ba481bc 100644 (file)
@@ -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.
index 72c55f5de4fe379a79ca1c46cc6d6bb8ab3a8dd6..3ebc35f51abf9504db7da371aa3cbc4e78363d4d 100755 (executable)
@@ -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 <requestee1@example.com>\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
index 0cbc13140038b9e302b29a5e3b3d08fb977e79a4..faa1117f1ba87c50fbb35c5018e76d2965e49c38 100755 (executable)
@@ -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
index 8025c02faaae74dd3e474cb83df6a30842558523..078ad37ec66d11c8bad3d27a6807b689ab6584cd 100644 (file)
@@ -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");
         }
     }