From 29798bd68fc0b892fce0fe49ec8859485e3b531b Mon Sep 17 00:00:00 2001 From: Eduardo Chappa Date: Fri, 22 Dec 2017 22:31:48 -0700 Subject: * Fix parsing of date for DTSTART and DTEND. The parser only recognized DATE-TIME format, now it recognizes DATE format. Reported by Holger Trapp. * Add escape parser to event location (switch "\," to "," etc.) * Start work to support reply of invitations, but then I realize that I need to start work in sending event invitations before I do that, so I will. --- alpine/mailpart.c | 1 + alpine/mailview.c | 2 +- libtool | 2 +- pith/Makefile | 35 +++++++------- pith/ical.c | 136 ++++++++++++++++++++++++++++++++++++++++++++++-------- pith/ical.h | 1 + pith/mailview.c | 16 +++++++ pith/pine.hlp | 2 +- po/Makefile.in | 8 ++-- 9 files changed, 159 insertions(+), 44 deletions(-) diff --git a/alpine/mailpart.c b/alpine/mailpart.c index 49ea053b..b7d2d3e2 100644 --- a/alpine/mailpart.c +++ b/alpine/mailpart.c @@ -2962,6 +2962,7 @@ display_vcalendar_att(long int msgno, ATTACH_S *a, int flags) } if(vesy->location){ + ical_remove_escapes(&vesy->location); utf8_snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%s%s", _("Location: "), vesy->location); so_puts(in_store, tmp_20k_buf); diff --git a/alpine/mailview.c b/alpine/mailview.c index c22f40a4..a51565ca 100644 --- a/alpine/mailview.c +++ b/alpine/mailview.c @@ -2167,7 +2167,7 @@ url_local_fragment(char *fragment) int ical_send_reply(char *url) { - ical_compose_reply(url + strlen("x-alpine-ical:")); +// ical_compose_reply(url + strlen("x-alpine-ical:")); return 2; } diff --git a/libtool b/libtool index ae869e54..9a48e8fe 100755 --- a/libtool +++ b/libtool @@ -1,7 +1,7 @@ #! /bin/sh # libtool - Provide generalized library-building support services. -# Generated automatically by config.status (alpine) 2.21.99 +# Generated automatically by config.status (alpine) 2.21.9 # Libtool was configured on host linux.suse: # NOTE: Changes made to this file will be lost: look at ltmain.sh. # diff --git a/pith/Makefile b/pith/Makefile index 166f5117..d9f3594a 100644 --- a/pith/Makefile +++ b/pith/Makefile @@ -121,21 +121,22 @@ libpith_a_AR = $(AR) $(ARFLAGS) libpith_a_LIBADD = am_libpith_a_OBJECTS = ablookup.$(OBJEXT) abdlc.$(OBJEXT) \ addrbook.$(OBJEXT) addrstring.$(OBJEXT) adrbklib.$(OBJEXT) \ - bldaddr.$(OBJEXT) charset.$(OBJEXT) color.$(OBJEXT) \ - conf.$(OBJEXT) context.$(OBJEXT) copyaddr.$(OBJEXT) \ - detoken.$(OBJEXT) detach.$(OBJEXT) editorial.$(OBJEXT) \ - escapes.$(OBJEXT) filter.$(OBJEXT) flag.$(OBJEXT) \ - folder.$(OBJEXT) handle.$(OBJEXT) help.$(OBJEXT) \ - helpindx.$(OBJEXT) hist.$(OBJEXT) icache.$(OBJEXT) \ - imap.$(OBJEXT) init.$(OBJEXT) keyword.$(OBJEXT) ldap.$(OBJEXT) \ - list.$(OBJEXT) mailcap.$(OBJEXT) mailcmd.$(OBJEXT) \ - mailindx.$(OBJEXT) maillist.$(OBJEXT) mailview.$(OBJEXT) \ - margin.$(OBJEXT) mimedesc.$(OBJEXT) mimetype.$(OBJEXT) \ - msgno.$(OBJEXT) newmail.$(OBJEXT) news.$(OBJEXT) \ - pattern.$(OBJEXT) pipe.$(OBJEXT) readfile.$(OBJEXT) \ - remote.$(OBJEXT) reply.$(OBJEXT) rfc2231.$(OBJEXT) \ - save.$(OBJEXT) search.$(OBJEXT) sequence.$(OBJEXT) \ - send.$(OBJEXT) sort.$(OBJEXT) state.$(OBJEXT) status.$(OBJEXT) \ + bldaddr.$(OBJEXT) body.$(OBJEXT) charset.$(OBJEXT) \ + color.$(OBJEXT) conf.$(OBJEXT) context.$(OBJEXT) \ + copyaddr.$(OBJEXT) detoken.$(OBJEXT) detach.$(OBJEXT) \ + editorial.$(OBJEXT) escapes.$(OBJEXT) filter.$(OBJEXT) \ + flag.$(OBJEXT) folder.$(OBJEXT) handle.$(OBJEXT) \ + help.$(OBJEXT) helpindx.$(OBJEXT) hist.$(OBJEXT) \ + icache.$(OBJEXT) ical.$(OBJEXT) imap.$(OBJEXT) init.$(OBJEXT) \ + keyword.$(OBJEXT) ldap.$(OBJEXT) list.$(OBJEXT) \ + mailcap.$(OBJEXT) mailcmd.$(OBJEXT) mailindx.$(OBJEXT) \ + maillist.$(OBJEXT) mailview.$(OBJEXT) margin.$(OBJEXT) \ + mimedesc.$(OBJEXT) mimetype.$(OBJEXT) msgno.$(OBJEXT) \ + newmail.$(OBJEXT) news.$(OBJEXT) pattern.$(OBJEXT) \ + pipe.$(OBJEXT) readfile.$(OBJEXT) remote.$(OBJEXT) \ + reply.$(OBJEXT) rfc2231.$(OBJEXT) save.$(OBJEXT) \ + search.$(OBJEXT) sequence.$(OBJEXT) send.$(OBJEXT) \ + sort.$(OBJEXT) state.$(OBJEXT) status.$(OBJEXT) \ store.$(OBJEXT) stream.$(OBJEXT) string.$(OBJEXT) \ strlst.$(OBJEXT) takeaddr.$(OBJEXT) tempfile.$(OBJEXT) \ text.$(OBJEXT) thread.$(OBJEXT) adjtime.$(OBJEXT) \ @@ -431,9 +432,9 @@ top_srcdir = .. SUBDIRS = osdep charconv noinst_LIBRARIES = libpith.a BUILT_SOURCES = helptext.h helptext.c -libpith_a_SOURCES = ablookup.c abdlc.c addrbook.c addrstring.c adrbklib.c bldaddr.c charset.c \ +libpith_a_SOURCES = ablookup.c abdlc.c addrbook.c addrstring.c adrbklib.c bldaddr.c body.c charset.c \ color.c conf.c context.c copyaddr.c detoken.c detach.c editorial.c escapes.c \ - filter.c flag.c folder.c handle.c help.c helpindx.c hist.c icache.c imap.c init.c \ + filter.c flag.c folder.c handle.c help.c helpindx.c hist.c icache.c ical.c imap.c init.c \ keyword.c ldap.c list.c mailcap.c mailcmd.c mailindx.c maillist.c mailview.c \ margin.c mimedesc.c mimetype.c msgno.c newmail.c news.c pattern.c pipe.c \ readfile.c remote.c reply.c rfc2231.c save.c search.c sequence.c send.c sort.c \ diff --git a/pith/ical.c b/pith/ical.c index 8364d384..b3fe67e2 100644 --- a/pith/ical.c +++ b/pith/ical.c @@ -231,6 +231,57 @@ ICAL_PROP_S alarm_prop[] = { /* Finally, here begins the code. */ +/* Return code: + 0 - if no errors + -1 - if an error occured + Args: a pointer to the text. If there is an error, the text is not modified. + */ +int +ical_remove_escapes(char **textp) +{ + char *text, *s, *t; + int rv = 0; + int escaped; + + if(textp == NULL) return 0; + + t = cpystr(*textp); /* work on a copy of the text */ + /* the variable text below points to the beginning of the filtered text */ + for (text = s = t, escaped = 0; rv == 0 && *s != '\0'; s++){ + if(*s == '\\' && escaped == 0){ + escaped = 1; + continue; + } + if(escaped){ + switch(*s){ + case '\\': + case ',': + case ';': + *t++ = *s; + break; + + case 'n': + case 'N': + *t++ = '\n'; + break; + default: rv = -1; + break; + } + escaped = 0; + } + else *t++ = *s; + } + *t = '\0'; /* tie off filtered text */ + t = text; /* reset t to the beginning */ + if(rv == -1) + fs_give((void **) &t); + else{ + strncpy(*textp, t, strlen(t)); /* overwrite given text with filtered text */ + (*textp)[strlen(t)] = '\0'; + } + return rv; +} + void ical_debug(char *fcn, char *text) { char piece[50]; @@ -1602,31 +1653,43 @@ ical_parse_duration(char *value, ICAL_DURATION_S *ic_d) return rv; } -/* return -1 if any error, 0 if no error */ +/* return -1 if any error, + 0 if value has the DATE-TIME form + 1 if value has the DATE form only + */ int ical_parse_date(char *value, struct tm *t) { - int i; + int i, rv; struct tm Tm; - if(t == NULL) return -1; + rv = -1; + if(t == NULL) return rv; memset((void *)&Tm, 0, sizeof(struct tm)); - if(value == NULL) return -1; + if(value == NULL) return rv; + rv = 0; /* assume DATE-TIME format */ /* a simple check for the format of the string */ for(i = 0; isdigit(value[i]); i++); - if (i != 8 || value[i++] != 'T') return -1; - for(; isdigit(value[i]); i++); - if(i != 15 || (value[i] != '\0' && (value[i] != 'Z' || value[i+1] != '\0'))) - return -1; + if (i == 8 && value[i] == '\0') + rv = 1; + else + if (i != 8 || value[i++] != 'T') return -1; + if(rv == 0) { + for(; isdigit(value[i]); i++); + if(i != 15 || (value[i] != '\0' && (value[i] != 'Z' || value[i+1] != '\0'))) + return -1; + } Tm.tm_year = ical_get_number_value(value, 0, 4) - 1900; Tm.tm_mon = ical_get_number_value(value, 4, 6) - 1; Tm.tm_mday = ical_get_number_value(value, 6, 8); - Tm.tm_hour = ical_get_number_value(value, 9, 11); - Tm.tm_min = ical_get_number_value(value, 11, 13); - Tm.tm_sec = ical_get_number_value(value, 13, 15); + if(rv == 0){ + Tm.tm_hour = ical_get_number_value(value, 9, 11); + Tm.tm_min = ical_get_number_value(value, 11, 13); + Tm.tm_sec = ical_get_number_value(value, 13, 15); + } *t = Tm; return (t->tm_mon > 11 || t->tm_mon < 0 @@ -1634,7 +1697,7 @@ ical_parse_date(char *value, struct tm *t) || t->tm_hour > 23 || t->tm_hour < 0 || t->tm_min > 59 || t->tm_min < 0 || t->tm_sec > 60 || t->tm_sec < 0) - ? - 1 : 0; + ? - 1 : rv; } void @@ -1962,10 +2025,27 @@ ical_vevent_summary(VCALENDAR_S *vcal) if((icl = (ICLINE_S *) vevent->prop[EvDtstart]) != NULL){ struct tm ic_date; char tmp[200]; + int icd; /* ical date return value */ + memset((void *)&ic_date, 0, sizeof(struct tm)); - ical_parse_date(icl->value, &ic_date); - ic_date.tm_wday = ical_day_of_week(ic_date); - our_strftime(tmp, sizeof(tmp), "%a %x %I:%M %p", &ic_date); + icd = ical_parse_date(icl->value, &ic_date); + if(icd >= 0){ + ic_date.tm_wday = ical_day_of_week(ic_date); + switch(icd){ + case 0: /* DATE-TIME */ + our_strftime(tmp, sizeof(tmp), "%a %x %I:%M %p", &ic_date); + break; + case 1: /* DATE */ + our_strftime(tmp, sizeof(tmp), "%a %x", &ic_date); + break; + default: alpine_panic("Unhandled ical date format"); + break; + } + } + else{ + strncpy(tmp, _("Error while parsing event date"), sizeof(tmp)); + tmp[sizeof(tmp) - 1] = '\0'; + } rv->evstart = cpystr(icl->value ? tmp : _("Unknown Start Date")); } /* end of if dtstart */ @@ -2012,11 +2092,27 @@ ical_vevent_summary(VCALENDAR_S *vcal) else if((icl = (ICLINE_S *) vevent->prop[EvDtend]) != NULL){ struct tm ic_date; char tmp[200]; + int icd; memset((void *)&ic_date, 0, sizeof(struct tm)); - ical_parse_date(icl->value, &ic_date); - ic_date.tm_wday = ical_day_of_week(ic_date); - our_strftime(tmp, sizeof(tmp), "%a %x %I:%M %p", &ic_date); + icd = ical_parse_date(icl->value, &ic_date); + if(icd >= 0){ + ic_date.tm_wday = ical_day_of_week(ic_date); + switch(icd){ + case 0: /* DATE-TIME */ + our_strftime(tmp, sizeof(tmp), "%a %x %I:%M %p", &ic_date); + break; + case 1: /* DATE */ + our_strftime(tmp, sizeof(tmp), "%a %x", &ic_date); + break; + default: alpine_panic("Unhandled ical date format"); + break; + } + } + else{ + strncpy(tmp, _("Error while parsing event date"), sizeof(tmp)); + tmp[sizeof(tmp) - 1] = '\0'; + } rv->evend = cpystr(icl->value ? tmp : _("Unknown End Date")); } /* end of if dtend */ @@ -2095,7 +2191,7 @@ ical_vevent_summary(VCALENDAR_S *vcal) v = cpystr(icl->value); /* process a copy of icl->value */ for(i = 1, escaped = 0, s = v; s && *s; s++){ - if(*s == '\\'){ escaped = 1; continue; } + if(*s == '\\' && escaped == 0){ escaped = 1; continue; } if(escaped){ if(!(*s == '\\' || *s == ',' || *s == 'n' || *s == 'N' || *s == ';')){ free_vevent_summary(&rv); @@ -2111,7 +2207,7 @@ ical_vevent_summary(VCALENDAR_S *vcal) rv->description = fs_get((i+1)*sizeof(char *)); i = 0; for (s = t = u = v, escaped = 0; *t != '\0'; t++){ - if(*t == '\\'){ escaped = 1; continue; } + if(*t == '\\' && escaped == 0){ escaped = 1; continue; } if(escaped){ switch(*t){ case '\\': diff --git a/pith/ical.h b/pith/ical.h index 04d0cc08..7ff5865a 100644 --- a/pith/ical.h +++ b/pith/ical.h @@ -9,6 +9,7 @@ int ical_first_of_month(int, int); /* args: month, year - in that order */ int ical_day_of_week(struct tm); /* args: a time structure */ int ical_parse_date(char *, struct tm *); int ical_parse_duration(char *, ICAL_DURATION_S *); +int ical_remove_escapes(char **); VEVENT_SUMMARY_S *ical_vevent_summary(VCALENDAR_S *); void free_vevent_summary(VEVENT_SUMMARY_S **); diff --git a/pith/mailview.c b/pith/mailview.c index 1d71e7a0..dcdd183d 100644 --- a/pith/mailview.c +++ b/pith/mailview.c @@ -312,6 +312,7 @@ format_calendar_vevent(VCALENDAR_S *vcal, ATTACH_S *a, HANDLE_S **handlesp, int } /* end of if(organizer) */ if(vesy->location){ + ical_remove_escapes(&vesy->location); utf8_snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%s%s%s", padding, _("Location: "), vesy->location); gf_puts(tmp_20k_buf, pc); @@ -483,10 +484,25 @@ format_calendar(long int msgno, BODY *body, HANDLE_S **handlesp, int flgs, int w for(a = ps_global->atmts; a->description != NULL; a++){ if(MIME_VCALENDAR(a->body->type, a->body->subtype)){ b = mail_body (ps_global->mail_stream, msgno, a->number); + if(b == NULL){ + gf_puts(_("Error fetching calendar body part"), pc); + gf_puts(NEWLINE, pc); + continue; + } if(b->sparep == NULL){ b64text = mail_fetch_body(ps_global->mail_stream, msgno, a->number, &callen, 0); + if(b64text == NULL){ + gf_puts(_("Error fetching calendar text"), pc); + gf_puts(NEWLINE, pc); + continue; + } b64text[callen] = '\0'; /* chop off cookie */ caltext = rfc822_base64(b64text, strlen(b64text), &callen); + if(caltext == NULL){ + gf_puts(_("Error in calendar base64 encoding"), pc); + gf_puts(NEWLINE, pc); + continue; + } vcal = ical_parse_text(caltext); b->sparep = create_body_sparep(iCalType, (void *) vcal); } diff --git a/pith/pine.hlp b/pith/pine.hlp index 0fa01415..ef58c44d 100644 --- a/pith/pine.hlp +++ b/pith/pine.hlp @@ -140,7 +140,7 @@ with help text for the config screen and the composer that didn't have any reasonable place to be called from. Dummy change to get revision in pine.hlp ============= h_revision ================= -Alpine Commit 240 2017-12-09 16:20:34 +Alpine Commit 243 2017-12-22 22:31:03 ============= h_news ================= diff --git a/po/Makefile.in b/po/Makefile.in index 9041c567..ab48d37d 100644 --- a/po/Makefile.in +++ b/po/Makefile.in @@ -11,7 +11,7 @@ # Origin: gettext-0.16 PACKAGE = alpine -VERSION = 2.21.99 +VERSION = 2.21.9 PACKAGE_BUGREPORT = chappa@washington.edu SHELL = /bin/sh @@ -34,12 +34,12 @@ INSTALL_DATA = ${INSTALL} -m 644 # We use $(mkdir_p). # In automake <= 1.9.x, $(mkdir_p) is defined either as "mkdir -p --" or as # "$(mkinstalldirs)" or as "$(install_sh) -d". For these automake versions, -# ${SHELL} /run/media/echappa/Work/alpine/alpinegit/install-sh does not start with $(SHELL), so we add it. +# ${SHELL} /run/media/chappa/Work/alpine/alpinegit/install-sh does not start with $(SHELL), so we add it. # In automake >= 1.10, $(MKDIR_P) is derived from ${MKDIR_P}, which is defined # either as "/path/to/mkdir -p" or ".../install-sh -c -d". For these automake # versions, $(mkinstalldirs) and $(install_sh) are unused. -mkinstalldirs = $(SHELL) ${SHELL} /run/media/echappa/Work/alpine/alpinegit/install-sh -d -install_sh = $(SHELL) ${SHELL} /run/media/echappa/Work/alpine/alpinegit/install-sh +mkinstalldirs = $(SHELL) ${SHELL} /run/media/chappa/Work/alpine/alpinegit/install-sh -d +install_sh = $(SHELL) ${SHELL} /run/media/chappa/Work/alpine/alpinegit/install-sh MKDIR_P = /usr/bin/mkdir -p mkdir_p = $(MKDIR_P) -- cgit v1.2.3-70-g09d2