📄 handler.c
字号:
/* * Copyright (C) 1996-2000 Michael R. Elkins <me@mutt.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #if HAVE_CONFIG_H# include "config.h"#endif#include <stdlib.h>#include <string.h>#include <unistd.h>#include <ctype.h>#include <sys/wait.h>#include <sys/stat.h>#include "mutt.h"#include "mutt_curses.h"#include "rfc1524.h"#include "keymap.h"#include "mime.h"#include "copy.h"#include "charset.h"#include "mutt_crypt.h"#define BUFI_SIZE 1000#define BUFO_SIZE 2000typedef int (*handler_t) (BODY *, STATE *);int Index_hex[128] = { -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1, -1,-1,-1,-1, -1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1};int Index_64[128] = { -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63, 52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1,-1,-1,-1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14, 15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1, -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40, 41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1};static void state_prefix_put (const char *d, size_t dlen, STATE *s){ if (s->prefix) while (dlen--) state_prefix_putc (*d++, s); else fwrite (d, dlen, 1, s->fpout);}void mutt_convert_to_state(iconv_t cd, char *bufi, size_t *l, STATE *s){ char bufo[BUFO_SIZE]; ICONV_CONST char *ib; char *ob; size_t ibl, obl; if (!bufi) { if (cd != (iconv_t)(-1)) { ob = bufo, obl = sizeof (bufo); iconv (cd, 0, 0, &ob, &obl); if (ob != bufo) state_prefix_put (bufo, ob - bufo, s); } return; } if (cd == (iconv_t)(-1)) { state_prefix_put (bufi, *l, s); *l = 0; return; } ib = bufi, ibl = *l; for (;;) { ob = bufo, obl = sizeof (bufo); mutt_iconv (cd, &ib, &ibl, &ob, &obl, 0, "?"); if (ob == bufo) break; state_prefix_put (bufo, ob - bufo, s); } memmove (bufi, ib, ibl); *l = ibl;}void mutt_decode_xbit (STATE *s, long len, int istext, iconv_t cd){ int c, ch; char bufi[BUFI_SIZE]; size_t l = 0; if (istext) { state_set_prefix(s); while ((c = fgetc(s->fpin)) != EOF && len--) { if(c == '\r' && len) { if((ch = fgetc(s->fpin)) == '\n') { c = ch; len--; } else ungetc(ch, s->fpin); } bufi[l++] = c; if (l == sizeof (bufi)) mutt_convert_to_state (cd, bufi, &l, s); } mutt_convert_to_state (cd, bufi, &l, s); mutt_convert_to_state (cd, 0, 0, s); state_reset_prefix (s); } else mutt_copy_bytes (s->fpin, s->fpout, len);}static int qp_decode_triple (char *s, char *d){ /* soft line break */ if (*s == '=' && !(*(s+1))) return 1; /* quoted-printable triple */ if (*s == '=' && isxdigit ((unsigned char) *(s+1)) && isxdigit ((unsigned char) *(s+2))) { *d = (hexval (*(s+1)) << 4) | hexval (*(s+2)); return 0; } /* something else */ return -1;}static void qp_decode_line (char *dest, char *src, size_t *l, int last){ char *d, *s; char c; int kind; int soft = 0; /* decode the line */ for (d = dest, s = src; *s;) { switch ((kind = qp_decode_triple (s, &c))) { case 0: *d++ = c; s += 3; break; /* qp triple */ case -1: *d++ = *s++; break; /* single character */ case 1: soft = 1; s++; break; /* soft line break */ } } if (!soft && last == '\n') *d++ = '\n'; *d = '\0'; *l = d - dest;}/* * Decode an attachment encoded with quoted-printable. * * Why doesn't this overflow any buffers? First, it's guaranteed * that the length of a line grows when you _en_-code it to * quoted-printable. That means that we always can store the * result in a buffer of at most the _same_ size. * * Now, we don't special-case if the line we read with fgets() * isn't terminated. We don't care about this, since STRING > 78, * so corrupted input will just be corrupted a bit more. That * implies that STRING+1 bytes are always sufficient to store the * result of qp_decode_line. * * Finally, at soft line breaks, some part of a multibyte character * may have been left over by mutt_convert_to_state(). This shouldn't * be more than 6 characters, so STRING + 7 should be sufficient * memory to store the decoded data. * * Just to make sure that I didn't make some off-by-one error * above, we just use STRING*2 for the target buffer's size. * */void mutt_decode_quoted (STATE *s, long len, int istext, iconv_t cd){ char line[STRING]; char decline[2*STRING]; size_t l = 0; size_t linelen; /* number of input bytes in `line' */ size_t l3; int last; /* store the last character in the input line */ if (istext) state_set_prefix(s); while (len > 0) { last = 0; /* * It's ok to use a fixed size buffer for input, even if the line turns * out to be longer than this. Just process the line in chunks. This * really shouldn't happen according the MIME spec, since Q-P encoded * lines are at most 76 characters, but we should be liberal about what * we accept. */ if (fgets (line, MIN ((ssize_t)sizeof (line), len + 1), s->fpin) == NULL) break; linelen = strlen(line); len -= linelen; /* * inspect the last character we read so we can tell if we got the * entire line. */ last = linelen ? line[linelen - 1] : 0; /* chop trailing whitespace if we got the full line */ if (last == '\n') { while (linelen > 0 && ISSPACE (line[linelen-1])) linelen--; line[linelen]=0; } /* decode and do character set conversion */ qp_decode_line (decline + l, line, &l3, last); l += l3; mutt_convert_to_state (cd, decline, &l, s); } mutt_convert_to_state (cd, 0, 0, s); state_reset_prefix(s);}void mutt_decode_base64 (STATE *s, long len, int istext, iconv_t cd){ char buf[5]; int c1, c2, c3, c4, ch, cr = 0, i; char bufi[BUFI_SIZE]; size_t l = 0; buf[4] = 0; if (istext) state_set_prefix(s); while (len > 0) { for (i = 0 ; i < 4 && len > 0 ; len--) { if ((ch = fgetc (s->fpin)) == EOF) break; if (ch >= 0 && ch < 128 && (base64val(ch) != -1 || ch == '=')) buf[i++] = ch; } if (i != 4) { dprint (2, (debugfile, "%s:%d [mutt_decode_base64()]: " "didn't get a multiple of 4 chars.\n", __FILE__, __LINE__)); break; } c1 = base64val (buf[0]); c2 = base64val (buf[1]); ch = (c1 << 2) | (c2 >> 4); if (cr && ch != '\n') bufi[l++] = '\r'; cr = 0; if (istext && ch == '\r') cr = 1; else bufi[l++] = ch; if (buf[2] == '=') break; c3 = base64val (buf[2]); ch = ((c2 & 0xf) << 4) | (c3 >> 2); if (cr && ch != '\n') bufi[l++] = '\r'; cr = 0; if (istext && ch == '\r') cr = 1; else bufi[l++] = ch; if (buf[3] == '=') break; c4 = base64val (buf[3]); ch = ((c3 & 0x3) << 6) | c4; if (cr && ch != '\n') bufi[l++] = '\r'; cr = 0; if (istext && ch == '\r') cr = 1; else bufi[l++] = ch; if (l + 8 >= sizeof (bufi)) mutt_convert_to_state (cd, bufi, &l, s); } if (cr) bufi[l++] = '\r'; mutt_convert_to_state (cd, bufi, &l, s); mutt_convert_to_state (cd, 0, 0, s); state_reset_prefix(s);}unsigned char decode_byte (char ch){ if (ch == 96) return 0; return ch - 32;}void mutt_decode_uuencoded (STATE *s, long len, int istext, iconv_t cd){ char tmps[SHORT_STRING]; char linelen, c, l, out; char *pt; char bufi[BUFI_SIZE]; size_t k = 0; if(istext) state_set_prefix(s); while(len > 0) { if ((fgets(tmps, sizeof(tmps), s->fpin)) == NULL) return; len -= mutt_strlen(tmps); if ((!mutt_strncmp (tmps, "begin", 5)) && ISSPACE (tmps[5])) break; } while(len > 0) { if ((fgets(tmps, sizeof(tmps), s->fpin)) == NULL) return; len -= mutt_strlen(tmps); if (!mutt_strncmp (tmps, "end", 3)) break; pt = tmps; linelen = decode_byte (*pt); pt++; for (c = 0; c < linelen;) { for (l = 2; l <= 6; l += 2) { out = decode_byte (*pt) << l; pt++; out |= (decode_byte (*pt) >> (6 - l)); bufi[k++] = out; c++; if (c == linelen) break; } mutt_convert_to_state (cd, bufi, &k, s); pt++; } } mutt_convert_to_state (cd, bufi, &k, s); mutt_convert_to_state (cd, 0, 0, s); state_reset_prefix(s);}/* ---------------------------------------------------------------------------- * A (not so) minimal implementation of RFC1563. */#define IndentSize (4) enum { RICH_PARAM=0, RICH_BOLD, RICH_UNDERLINE, RICH_ITALIC, RICH_NOFILL, RICH_INDENT, RICH_INDENT_RIGHT, RICH_EXCERPT, RICH_CENTER, RICH_FLUSHLEFT, RICH_FLUSHRIGHT, RICH_COLOR, RICH_LAST_TAG };static struct { const char *tag_name; int index;} EnrichedTags[] = { { "param", RICH_PARAM }, { "bold", RICH_BOLD }, { "italic", RICH_ITALIC }, { "underline", RICH_UNDERLINE }, { "nofill", RICH_NOFILL }, { "excerpt", RICH_EXCERPT }, { "indent", RICH_INDENT }, { "indentright", RICH_INDENT_RIGHT }, { "center", RICH_CENTER }, { "flushleft", RICH_FLUSHLEFT }, { "flushright", RICH_FLUSHRIGHT }, { "flushboth", RICH_FLUSHLEFT }, { "color", RICH_COLOR }, { "x-color", RICH_COLOR }, { NULL, -1 }};struct enriched_state{ char *buffer; char *line; char *param; size_t buff_len; size_t line_len; size_t line_used; size_t line_max; size_t indent_len; size_t word_len; size_t buff_used; size_t param_used; size_t param_len; int tag_level[RICH_LAST_TAG]; int WrapMargin; STATE *s;};static void enriched_wrap (struct enriched_state *stte){ int x; int extra; if (stte->line_len) { if (stte->tag_level[RICH_CENTER] || stte->tag_level[RICH_FLUSHRIGHT]) { /* Strip trailing white space */ size_t y = stte->line_used - 1; while (y && ISSPACE (stte->line[y])) { stte->line[y] = '\0'; y--; stte->line_used--; stte->line_len--; } if (stte->tag_level[RICH_CENTER]) { /* Strip leading whitespace */ y = 0; while (stte->line[y] && ISSPACE (stte->line[y])) y++; if (y) { size_t z; for (z = y ; z <= stte->line_used; z++) { stte->line[z - y] = stte->line[z]; } stte->line_len -= y; stte->line_used -= y; } } } extra = stte->WrapMargin - stte->line_len - stte->indent_len - (stte->tag_level[RICH_INDENT_RIGHT] * IndentSize); if (extra > 0) { if (stte->tag_level[RICH_CENTER]) { x = extra / 2; while (x) { state_putc (' ', stte->s); x--; } } else if (stte->tag_level[RICH_FLUSHRIGHT]) { x = extra-1; while (x) { state_putc (' ', stte->s); x--; } } } state_puts (stte->line, stte->s); } state_putc ('\n', stte->s); stte->line[0] = '\0'; stte->line_len = 0; stte->line_used = 0; stte->indent_len = 0; if (stte->s->prefix) { state_puts (stte->s->prefix, stte->s); stte->indent_len += mutt_strlen (stte->s->prefix); } if (stte->tag_level[RICH_EXCERPT]) { x = stte->tag_level[RICH_EXCERPT]; while (x) { if (stte->s->prefix) { state_puts (stte->s->prefix, stte->s); stte->indent_len += mutt_strlen (stte->s->prefix); } else { state_puts ("> ", stte->s); stte->indent_len += mutt_strlen ("> "); } x--; } } else stte->indent_len = 0; if (stte->tag_level[RICH_INDENT]) { x = stte->tag_level[RICH_INDENT] * IndentSize; stte->indent_len += x; while (x) { state_putc (' ', stte->s); x--; } }}static void enriched_flush (struct enriched_state *stte, int wrap){ if (!stte->tag_level[RICH_NOFILL] && (stte->line_len + stte->word_len > (stte->WrapMargin - (stte->tag_level[RICH_INDENT_RIGHT] * IndentSize) - stte->indent_len))) enriched_wrap (stte); if (stte->buff_used) { stte->buffer[stte->buff_used] = '\0'; stte->line_used += stte->buff_used; if (stte->line_used > stte->line_max) { stte->line_max = stte->line_used; safe_realloc (&stte->line, stte->line_max + 1); } strcat (stte->line, stte->buffer); /* __STRCAT_CHECKED__ */ stte->line_len += stte->word_len; stte->word_len = 0; stte->buff_used = 0; } if (wrap) enriched_wrap(stte);}static void enriched_putc (int c, struct enriched_state *stte){ if (stte->tag_level[RICH_PARAM]) { if (stte->tag_level[RICH_COLOR]) { if (stte->param_used + 1 >= stte->param_len) safe_realloc (&stte->param, (stte->param_len += STRING)); stte->param[stte->param_used++] = c; } return; /* nothing to do */ } /* see if more space is needed (plus extra for possible rich characters) */ if (stte->buff_len < stte->buff_used + 3) { stte->buff_len += LONG_STRING; safe_realloc (&stte->buffer, stte->buff_len + 1); } if ((!stte->tag_level[RICH_NOFILL] && ISSPACE (c)) || c == '\0' ) { if (c == '\t') stte->word_len += 8 - (stte->line_len + stte->word_len) % 8; else stte->word_len++; stte->buffer[stte->buff_used++] = c; enriched_flush (stte, 0); } else { if (stte->s->flags & M_DISPLAY) { if (stte->tag_level[RICH_BOLD]) { stte->buffer[stte->buff_used++] = c; stte->buffer[stte->buff_used++] = '\010'; stte->buffer[stte->buff_used++] = c; } else if (stte->tag_level[RICH_UNDERLINE]) { stte->buffer[stte->buff_used++] = '_'; stte->buffer[stte->buff_used++] = '\010'; stte->buffer[stte->buff_used++] = c; } else if (stte->tag_level[RICH_ITALIC]) { stte->buffer[stte->buff_used++] = c; stte->buffer[stte->buff_used++] = '\010'; stte->buffer[stte->buff_used++] = '_';
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -