export PARINIT
fi
+
#### Reply, including text/html (converted to text/plain) and
#### text/plain parts.
####
}
+#### 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 \
-(forma)t string
-infile
-outfile
+ -attendee
-[no]contenttype
-unfold
-debug
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
>"$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
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
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
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
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 *);
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) \
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;
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;
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);
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,
* - 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);
/* 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;
}
}
- if (! found_my_attendee_line) {
+ if (found_my_attendee_line == 0) {
/* Generate and attach an ATTENDEE line for me. */
contentline *node;
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;
}
/*
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))) {
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");
}
}