summaryrefslogtreecommitdiff
path: root/pith/mailview.c
diff options
context:
space:
mode:
authorEduardo Chappa <chappa@washington.edu>2013-05-31 17:08:22 -0600
committerEduardo Chappa <chappa@washington.edu>2013-05-31 17:08:22 -0600
commit81e994d7907f850506ddc248f84761a54995e58c (patch)
tree3bc4993b48ddeec45dee51323437200ab975887c /pith/mailview.c
parent077522d7e058133f9de99d0d74481566b21c5a98 (diff)
downloadalpine-81e994d7907f850506ddc248f84761a54995e58c.tar.xz
* Fix not allow remote execution by adding PIPE_NOSHELL to the opening of a url by
a browser.
Diffstat (limited to 'pith/mailview.c')
-rw-r--r--pith/mailview.c465
1 files changed, 445 insertions, 20 deletions
diff --git a/pith/mailview.c b/pith/mailview.c
index 40728aab..5df0dbdb 100644
--- a/pith/mailview.c
+++ b/pith/mailview.c
@@ -52,7 +52,11 @@ static char rcsid[] = "$Id: mailview.c 1266 2009-07-14 18:39:12Z hubert@u.washin
#include "../pith/escapes.h"
#include "../pith/keyword.h"
#include "../pith/smime.h"
-
+#include "../pith/osdep/color.h"
+#include "../pico/osdep/color.h"
+#include "../pico/estruct.h"
+#include "../pico/pico.h"
+#include "../pico/efunc.h"
#define FBUF_LEN (50)
@@ -282,9 +286,17 @@ format_body(long int msgno, BODY *body, HANDLE_S **handlesp, HEADER_S *hp, int f
if((flgs & FM_DISPLAY)
&& !(flgs & FM_NOCOLOR)
&& pico_usingcolor()
+ && ps_global->VAR_SPECIAL_TEXT_FORE_COLOR
+ && ps_global->VAR_SPECIAL_TEXT_BACK_COLOR){
+ gf_link_filter(gf_line_test, gf_line_test_opt(color_this_text, NULL));
+ }
+
+ if((flgs & FM_DISPLAY)
+ && !(flgs & FM_NOCOLOR)
+ && pico_usingcolor()
&& ps_global->VAR_SIGNATURE_FORE_COLOR
&& ps_global->VAR_SIGNATURE_BACK_COLOR){
- gf_link_filter(gf_line_test, gf_line_test_opt(color_signature, &is_in_sig));
+ gf_link_filter(gf_quote_test, gf_line_test_opt(color_signature, &is_in_sig));
}
if((flgs & FM_DISPLAY)
@@ -292,8 +304,10 @@ format_body(long int msgno, BODY *body, HANDLE_S **handlesp, HEADER_S *hp, int f
&& pico_usingcolor()
&& ps_global->VAR_QUOTE1_FORE_COLOR
&& ps_global->VAR_QUOTE1_BACK_COLOR){
- gf_link_filter(gf_line_test, gf_line_test_opt(color_a_quote, NULL));
+ gf_link_filter(gf_quote_test, gf_line_test_opt(color_a_quote, NULL));
}
+ else
+ gf_link_filter(gf_quote_test,gf_line_test_opt(select_quote, NULL));
if(!(flgs & FM_NOWRAP)){
wrapflags = (flgs & FM_DISPLAY) ? (GFW_HANDLES|GFW_SOFTHYPHEN) : GFW_NONE;
@@ -1098,27 +1112,88 @@ int
color_signature(long int linenum, char *line, LT_INS_S **ins, void *is_in_sig)
{
struct variable *vars = ps_global->vars;
- int *in_sig_block;
+ int *in_sig_block, i, j,same_qstr = 0, plb;
COLOR_PAIR *col = NULL;
+ static char GLine[NSTRING] = {'\0'};
+ static char PLine[NSTRING] = {'\0'};
+ static char PPLine[NSTRING] = {'\0'};
+ char NLine[NSTRING] = {'\0'};
+ char rqstr[NSTRING] = {'\0'};
+ char *p, *q;
+ static char *buf, buf2[NSTRING] = {'\0'};
+ QSTRING_S *qs;
+ static int qstrlen = 0;
if(is_in_sig == NULL)
return 0;
+ if (linenum > 0){
+ strncpy(PLine, GLine, sizeof(PLine));
+ PLine[sizeof(PLine)-1] = '\0';
+ }
+
+ if(p = strchr(tmp_20k_buf, '\015')) *p = '\0';
+ strncpy(NLine, tmp_20k_buf, sizeof(NLine));
+ NLine[sizeof(NLine) - 1] = '\0';
+ if (p) *p = '\015';
+
+ strncpy(GLine, line, sizeof(GLine));
+ GLine[sizeof(GLine) - 1] = '\0';
+
+ ps_global->list_qstr = default_qstr(ps_global->prefix && *ps_global->prefix
+ ? (void *) ps_global->prefix : (void *) ">", 0);
+ plb = line_isblank(ps_global->list_qstr, PLine, GLine, PPLine, NSTRING);
+ qs = do_quote_match(ps_global->list_qstr, GLine, NLine, PLine, rqstr, NSTRING, plb);
+ if(linenum > 0)
+ strncpy(PPLine, PLine, NSTRING);
+ strncpy(buf2, rqstr, NSTRING);
+ i = buf2 && buf2[0] ? strlen(buf2) : 0;
+ free_qs(&qs);
+
+ /* determine if buf and buf2 are the same quote string */
+ if (!struncmp(buf, buf2, qstrlen)){
+ for (j = qstrlen; buf2[j] && isspace((unsigned char)buf2[j]); j++);
+ if (!buf2[j] || buf2[j] == '|' || (buf2[j] == '*' && buf2[j+1] != '>'))
+ same_qstr++;
+ }
+
in_sig_block = (int *) is_in_sig;
- if(!strcmp(line, SIGDASHES))
- *in_sig_block = START_SIG_BLOCK;
- else if(*line == '\0')
+ if (*in_sig_block != OUT_SIG_BLOCK){
+ if (line && *line && (strlen(line) >= qstrlen) && same_qstr)
+ line += qstrlen;
+ else if (strlen(line) < qstrlen)
+ line += i;
+ else if (!same_qstr)
+ *in_sig_block = OUT_SIG_BLOCK;
+ }
+ else
+ line += i;
+
+ if(!strcmp(line, SIGDASHES) || !strcmp(line, "--")){
+ *in_sig_block = START_SIG_BLOCK;
+ buf = (char *) fs_get((i + 1)*sizeof(char));
+ buf = cpystr(buf2);
+ qstrlen = i;
+ }
+ else if(*line == '\0'){
/*
* Suggested by Eduardo: allow for a blank line right after
* the sigdashes.
*/
*in_sig_block = (*in_sig_block == START_SIG_BLOCK)
? IN_SIG_BLOCK : OUT_SIG_BLOCK;
+ }
else
*in_sig_block = (*in_sig_block != OUT_SIG_BLOCK)
? IN_SIG_BLOCK : OUT_SIG_BLOCK;
+ if (*in_sig_block == OUT_SIG_BLOCK){
+ qstrlen = 0; /* reset back in case there's another paragraph */
+ if (buf)
+ fs_give((void **)&buf);
+ }
+
if(*in_sig_block != OUT_SIG_BLOCK
&& VAR_SIGNATURE_FORE_COLOR && VAR_SIGNATURE_BACK_COLOR
&& (col = new_color_pair(VAR_SIGNATURE_FORE_COLOR,
@@ -1482,18 +1557,78 @@ color_headers(long int linenum, char *line, LT_INS_S **ins, void *local)
return(0);
}
+int
+incomplete_url(char *up, int n, int delim)
+{
+ char *line, *line2;
+ int rv = 0, len;
+
+ if(*(up + n) != '\0')
+ return 0;
+
+ if(delim > 0)
+ return 1;
+
+ if(F_ON(F_VIEW_LONG_URL, ps_global)){
+ line = up;
+ if(!strncmp(line, "http://", 7))
+ line += 7;
+ else if(!strncmp(line, "https://", 8))
+ line += 8;
+ if(strchr(line, '/') != NULL && (line = strrchr(line, '/')) != NULL){
+ line++;
+ line2 = strrchr(line, '.');
+ rv = (strpbrk(line,"+#?=&") != NULL)
+ || (!line2 || line-line2 > 4);
+ }
+ }
+ return rv;
+}
+
int
url_hilite(long int linenum, char *line, LT_INS_S **ins, void *local)
{
register char *lp, *up = NULL, *urlp = NULL,
*weburlp = NULL, *mailurlp = NULL;
- int n, n1, n2, n3, l;
+ char *use_this_line, c, *begin_line, *end_line;
+ static int scannextline, delim = -1;
+ int n, n1, n2, n3, l, len;
+ int we_clear = 0, newhandle = 1, tie_off = 0;
char buf[256], color[256];
HANDLE_S *h;
URL_HILITE_S *uh;
- for(lp = line; ; lp = up + n){
+ uh = (URL_HILITE_S *) local;
+ if((uh && uh->handlesp && ((h = *(uh->handlesp)) == NULL) || h->key == 0) ||
+ (!line || !*line) || linenum == 0)
+ scannextline = 0; /* initialize scannextline */
+
+ if(scannextline != 0){
+ up = rfc1738_scan(line, &n1);
+
+ /* if we found a url in the current line, but it is not at the beginning of
+ * the next line, or if there is no url in this line, we check if the url
+ * in the previous line continues in this line.
+ */
+
+ if(line != up){
+ if(*uh->handlesp == NULL)
+ h = new_handle(uh->handlesp);
+ for(h = *uh->handlesp; h->next; h = h->next); /* get last handle */
+ len = h->h.url.path ? strlen(h->h.url.path) : 0;
+ use_this_line = (char *) fs_get((len + strlen(line) + 1)*sizeof(char));
+ sprintf(use_this_line,"%s%s", (h->h.url.path ? h->h.url.path : ""), line);
+ we_clear++;
+ newhandle = 0;
+ }
+ else
+ use_this_line = line;
+ }
+ else
+ use_this_line = line;
+
+ for(lp = use_this_line; ; lp = up + n){
/* scan for all of them so we can choose the first */
if(F_ON(F_VIEW_SEL_URL,ps_global))
urlp = rfc1738_scan(lp, &n1);
@@ -1503,6 +1638,10 @@ url_hilite(long int linenum, char *line, LT_INS_S **ins, void *local)
mailurlp = mail_addr_scan(lp, &n3);
if(urlp || weburlp || mailurlp){
+ if(scannextline == 0){
+ newhandle++;
+ delim = -1;
+ }
up = urlp ? urlp :
weburlp ? weburlp : mailurlp;
if(up == urlp && weburlp && weburlp < up)
@@ -1511,7 +1650,16 @@ url_hilite(long int linenum, char *line, LT_INS_S **ins, void *local)
up = mailurlp;
if(up == urlp){
+ if(delim < 0)
+ delim = up > use_this_line && *(up - 1) == '<';
n = n1;
+ if(incomplete_url(up,n, delim))
+ scannextline++;
+ else{
+ if(scannextline)
+ tie_off++;
+ scannextline = 0;
+ }
weburlp = mailurlp = NULL;
}
else if(up == weburlp){
@@ -1528,36 +1676,58 @@ url_hilite(long int linenum, char *line, LT_INS_S **ins, void *local)
uh = (URL_HILITE_S *) local;
- h = new_handle(uh->handlesp);
- h->type = URL;
- h->h.url.path = (char *) fs_get((n + 10) * sizeof(char));
- snprintf(h->h.url.path, n+10, "%s%.*s",
+ if(tie_off){
+ tie_off = 0; /* do only once */
+ begin_line = line;
+ end_line = line + n - strlen(h->h.url.path);
+ fs_give((void **)&h->h.url.path);
+ c = *(use_this_line + n);
+ *(use_this_line+n) = '\0';
+ h->h.url.path = cpystr(use_this_line);
+ *(use_this_line+n) = c;
+ }
+ else{
+ if(newhandle){
+ h = new_handle(uh->handlesp);
+ h->type = URL;
+ }
+ begin_line = newhandle ? (we_clear ? line + strlen(line) - strlen(up)
+ : up) : line;
+ end_line = newhandle ? begin_line + n : line + strlen(line);
+ if(scannextline && h->h.url.path)
+ fs_give((void **)&h->h.url.path);
+ h->h.url.path = (char *) fs_get((n + 10) * sizeof(char));
+ snprintf(h->h.url.path, n+10, "%s%.*s",
weburlp ? "http://" : (mailurlp ? "mailto:" : ""), n, up);
- h->h.url.path[n+10-1] = '\0';
+ h->h.url.path[n+10-1] = '\0';
+ }
if(handle_start_color(color, sizeof(color), &l, uh->hdr_color))
- ins = gf_line_test_new_ins(ins, up, color, l);
+ ins = gf_line_test_new_ins(ins, begin_line, color, l);
else if(F_OFF(F_SLCTBL_ITEM_NOBOLD, ps_global))
- ins = gf_line_test_new_ins(ins, up, url_embed(TAG_BOLDON), 2);
+ ins = gf_line_test_new_ins(ins, begin_line, url_embed(TAG_BOLDON), 2);
buf[0] = TAG_EMBED;
buf[1] = TAG_HANDLE;
snprintf(&buf[3], sizeof(buf)-3, "%d", h->key);
buf[sizeof(buf)-1] = '\0';
buf[2] = strlen(&buf[3]);
- ins = gf_line_test_new_ins(ins, up, buf, (int) buf[2] + 3);
+ ins = gf_line_test_new_ins(ins, begin_line, buf, (int) buf[2] + 3);
/* in case it was the current selection */
- ins = gf_line_test_new_ins(ins, up + n, url_embed(TAG_INVOFF), 2);
+ ins = gf_line_test_new_ins(ins, end_line, url_embed(TAG_INVOFF), 2);
if(scroll_handle_end_color(color, sizeof(color), &l, uh->hdr_color))
- ins = gf_line_test_new_ins(ins, up + n, color, l);
+ ins = gf_line_test_new_ins(ins, end_line, color, l);
else
- ins = gf_line_test_new_ins(ins, up + n, url_embed(TAG_BOLDOFF), 2);
+ ins = gf_line_test_new_ins(ins, end_line, url_embed(TAG_BOLDOFF), 2);
urlp = weburlp = mailurlp = NULL;
}
+ if(we_clear)
+ fs_give((void **)&use_this_line);
+
return(0);
}
@@ -1678,6 +1848,77 @@ pad_to_right_edge(long int linenum, char *line, LT_INS_S **ins, void *local)
}
+/* This filter gives a quote string of a line. It sends its reply back to the
+ calling filter in the tmp_20k_buf variable. This filter replies with
+ the full quote string including tailing spaces if any. It is the
+ responsibility of the calling filter to figure out if thos spaces are
+ useful for that filter or if they should be removed before doing any
+ useful work. For example, color_a_quote does not require the trailing
+ spaces, but gf_wrap does.
+ */
+int
+select_quote(long linenum, char *line, LT_INS_S **ins, void *local)
+{
+ int i, plb, *code;
+ char rqstr[NSTRING] = {'\0'}, buf[NSTRING] = {'\0'};
+ char GLine[NSTRING] = {'\0'}, PLine[NSTRING] = {'\0'};
+ char PPLine[NSTRING] = {'\0'}, NLine[NSTRING] = {'\0'};
+ static char GLine1[NSTRING] = {'\0'};
+ static char PLine1[NSTRING] = {'\0'};
+ static char PPLine1[NSTRING] = {'\0'};
+ static char GLine2[NSTRING] = {'\0'};
+ static char PLine2[NSTRING] = {'\0'};
+ static char PPLine2[NSTRING] = {'\0'};
+ QSTRING_S *qs;
+ int buflen = NSTRING < SIZEOF_20KBUF ? NSTRING - 1: SIZEOF_20KBUF - 1;
+ int who, raw;
+
+ code = (int *)local;
+ who = code ? (*code & COLORAQUO) : 0; /* may I ask who is calling? */
+ raw = code ? (*code & RAWSTRING) : 0; /* return raw string */
+ strncpy(GLine, (who ? GLine1 : GLine2), buflen);
+ strncpy(PLine, (who ? PLine1 : PLine2), buflen);
+ strncpy(PPLine, (who ? PPLine1 : PPLine2), buflen);
+
+ if (linenum > 0)
+ strncpy(PLine, GLine, buflen);
+
+ strncpy(NLine, tmp_20k_buf, buflen);
+
+ if (line)
+ strncpy(GLine, line, buflen);
+ else
+ GLine[0] = '\0';
+
+ ps_global->list_qstr = default_qstr(ps_global->prefix && *ps_global->prefix
+ ? (void *) ps_global->prefix : (void *) ">", 0);
+ plb = line_isblank(ps_global->list_qstr, PLine, GLine, PPLine, NSTRING);
+
+ qs = do_quote_match(ps_global->list_qstr, GLine, NLine, PLine, rqstr, NSTRING, plb);
+ if (raw)
+ strncpy(buf, rqstr, NSTRING);
+ else
+ flatten_qstring(qs, buf, NSTRING);
+ if(qs)
+ record_quote_string(qs);
+ free_qs(&qs);
+
+ /* do not paint an extra level for a line with a >From string at the
+ * begining of it
+ */
+ if (buf[0]){
+ i = strlen(buf);
+ if (strlen(line) >= i + 6 && !strncmp(line+i-1,">From ", 6))
+ buf[i - 1] = '\0';
+ }
+ strncpy(tmp_20k_buf, buf, buflen);
+ if (linenum > 0)
+ strncpy((who ? PPLine1 : PPLine2), PLine, buflen);
+ strncpy((who ? GLine1 : GLine2), GLine, buflen);
+ strncpy((who ? PLine1 : PLine2), PLine, buflen);
+ return 1;
+}
+
#define UES_LEN 12
#define UES_MAX 32
@@ -2503,6 +2744,190 @@ hdr_color(char *fieldname, char *value, SPEC_COLOR_S *speccolor)
return(color_pair);
}
+void
+interval_free(IVAL_S **ival)
+{
+ if (!(*ival))
+ return;
+
+ if ((*ival)->next)
+ interval_free(&((*ival)->next));
+
+ fs_give((void **)(ival));
+}
+
+IVAL_S *
+compute_interval (char *string, int endm)
+{
+ IVAL_S *ival = NULL;
+ regmatch_t pmatch;
+
+ if(ps_global->paterror == 0 &&
+ regexec(&ps_global->colorpat, string + endm, 1, &pmatch, 0) == 0){
+ ival = (IVAL_S *) fs_get(sizeof(IVAL_S));
+ ival->start = endm + pmatch.rm_so;
+ ival->end = endm + pmatch.rm_eo;
+ ival->next = compute_interval(string, ival->end);
+ }
+ return ival;
+}
+
+void
+regex_pattern(char **plist)
+{
+ int i = 0, j = 0, len = 0;
+ char *pattern = NULL;
+ regex_t preg;
+
+ if(ps_global->paterror == 0)
+ regfree(&ps_global->colorpat);
+
+ if(plist && *plist && *plist){
+ for (i = 0; plist[i] && plist[i][0]; i++)
+ len += strlen(plist[i]) + 1;
+ pattern = (char *) fs_get(len * sizeof(char));
+ *pattern = '\0';
+ for (j = 0; j < i; j++){
+ strcat(pattern, plist[j]);
+ strcat(pattern, (j < i - 1) ? "|" : "");
+ }
+ if ((ps_global->paterror = regcomp(&preg, pattern, REG_EXTENDED)) != 0)
+ regfree(&preg);
+ else
+ ps_global->colorpat = preg;
+ }
+ if(pattern)
+ fs_give((void **)&pattern);
+}
+
+LT_INS_S **
+insert_color_special_text(LT_INS_S **ins, char **p, IVAL_S *ival, int last_end,
+ COLOR_PAIR *col)
+{
+ struct variable *vars = ps_global->vars;
+
+ if (ival){
+ *p += ival->start - last_end;
+ ins = gf_line_test_new_ins(ins, *p, color_embed(col->fg, col->bg),
+ (2 * RGBLEN) + 4);
+ *p += ival->end - ival->start;
+ ins = gf_line_test_new_ins(ins, *p, color_embed(VAR_NORM_FORE_COLOR,
+ VAR_NORM_BACK_COLOR), (2 * RGBLEN) + 4);
+ ins = insert_color_special_text(ins, p, ival->next, ival->end, col);
+ }
+ return ins;
+}
+
+int
+length_color(char *p, int begin_color)
+{
+ int len = 0, done = begin_color ? 0 : -1;
+ char *orig = p;
+
+ while (*p && done <= 0){
+ switch(*p++){
+ case TAG_HANDLE :
+ p += *p + 1;
+ done++;
+ break;
+
+ case TAG_FGCOLOR :
+ case TAG_BGCOLOR :
+ p += RGBLEN;
+ if (!begin_color)
+ done++;
+ break;
+
+ default :
+ break;
+ }
+ }
+ len = p - orig;
+ return len;
+}
+
+int
+any_color_in_string(char *p)
+{
+ int rv = 0;
+ char *orig = p;
+ while (*p && !rv)
+ if (*p++ == TAG_EMBED)
+ rv = p - orig;
+ return rv;
+}
+
+void
+remove_spaces_ival(IVAL_S **ivalp, char *p)
+{
+ IVAL_S *ival;
+ int i;
+ if (!ivalp || !*ivalp)
+ return;
+ ival = *ivalp;
+ for (i = 0; isspace((unsigned char) p[ival->start + i]); i++);
+ if (ival->start + i < ival->end) /* do not do this if match only spaces */
+ ival->start += i;
+ else
+ return;
+ for (i = 0; isspace((unsigned char) p[ival->end - i - 1]); i++);
+ ival->end -= i;
+ if (ival->next)
+ remove_spaces_ival(&(ival->next), p);
+}
+
+int
+color_this_text(long linenum, char *line, LT_INS_S **ins, void *local)
+{
+ struct variable *vars = ps_global->vars;
+ COLOR_PAIR *col = NULL;
+ char *p;
+ int i = 0;
+ static char *pattern = NULL;
+
+/* select_quote(linenum, line, ins, (void *) &i);
+ for (i = 0; tmp_20k_buf[i] != '\0'; i++); */
+ p = line + i;
+
+ if(VAR_SPECIAL_TEXT_FORE_COLOR && VAR_SPECIAL_TEXT_BACK_COLOR
+ && (col = new_color_pair(VAR_SPECIAL_TEXT_FORE_COLOR,
+ VAR_SPECIAL_TEXT_BACK_COLOR))
+ && !pico_is_good_colorpair(col))
+ free_color_pair(&col);
+
+ if(ps_global->VAR_SPECIAL_TEXT && *ps_global->VAR_SPECIAL_TEXT
+ && **ps_global->VAR_SPECIAL_TEXT && col){
+ IVAL_S *ival;
+ int done = 0, begin_color = 0;
+
+ while (!done){
+ if (i = any_color_in_string(p)){
+ begin_color = (begin_color + 1) % 2;
+ if (begin_color){
+ p[i - 1] = '\0';
+ ival = compute_interval(p, 0);
+ remove_spaces_ival(&ival, p);
+ p[i - 1] = TAG_EMBED;
+ ins = insert_color_special_text(ins, &p, ival, 0, col);
+ }
+ for (;*p++ != TAG_EMBED; );
+ p += length_color(p, begin_color);
+ }
+ else{
+ ival = compute_interval(p, 0);
+ remove_spaces_ival(&ival, p);
+ ins = insert_color_special_text(ins, &p, ival, 0, col);
+ done++;
+ }
+ interval_free(&ival);
+ if (!*p)
+ done++;
+ }
+ free_color_pair(&col);
+ }
+
+ return 0;
+}
/*
* The argument fieldname is something like "Subject:..." or "Subject".