📄 sendlib.c
字号:
/* * Copyright (C) 1996-2002 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. */ #define _SENDLIB_C 1#if HAVE_CONFIG_H# include "config.h"#endif#include "mutt.h"#include "mutt_curses.h"#include "rfc2047.h"#include "rfc2231.h"#include "mx.h"#include "mime.h"#include "mailbox.h"#include "copy.h"#include "pager.h"#include "charset.h"#include "mutt_crypt.h"#include "mutt_idna.h"#include <string.h>#include <stdlib.h>#include <unistd.h>#include <errno.h>#include <ctype.h>#include <sys/stat.h>#include <signal.h>#include <sys/wait.h>#include <fcntl.h>#ifdef HAVE_SYSEXITS_H#include <sysexits.h>#else /* Make sure EX_OK is defined <philiph@pobox.com> */#define EX_OK 0#endif/* If you are debugging this file, comment out the following line. *//*#define NDEBUG*/#ifdef NDEBUG#define assert(x)#else#include <assert.h>#endifextern char RFC822Specials[];#define DISPOSITION(X) X==DISPATTACH?"attachment":"inline"const char MimeSpecials[] = "@.,;:<>[]\\\"()?/= \t";char B64Chars[64] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};static char MsgIdPfx = 'A';static void transform_to_7bit (BODY *a, FILE *fpin);static void encode_quoted (FGETCONV * fc, FILE *fout, int istext){ int c, linelen = 0; char line[77], savechar; while ((c = fgetconv (fc)) != EOF) { /* Wrap the line if needed. */ if (linelen == 76 && ((istext && c != '\n') || !istext)) { /* If the last character is "quoted", then be sure to move all three * characters to the next line. Otherwise, just move the last * character... */ if (line[linelen-3] == '=') { line[linelen-3] = 0; fputs (line, fout); fputs ("=\n", fout); line[linelen] = 0; line[0] = '='; line[1] = line[linelen-2]; line[2] = line[linelen-1]; linelen = 3; } else { savechar = line[linelen-1]; line[linelen-1] = '='; line[linelen] = 0; fputs (line, fout); fputc ('\n', fout); line[0] = savechar; linelen = 1; } } /* Escape lines that begin with/only contain "the message separator". */ if (linelen == 4 && !mutt_strncmp ("From", line, 4)) { strfcpy (line, "=46rom", sizeof (line)); linelen = 6; } else if (linelen == 4 && !mutt_strncmp ("from", line, 4)) { strfcpy (line, "=66rom", sizeof (line)); linelen = 6; } else if (linelen == 1 && line[0] == '.') { strfcpy (line, "=2E", sizeof (line)); linelen = 3; } if (c == '\n' && istext) { /* Check to make sure there is no trailing space on this line. */ if (linelen > 0 && (line[linelen-1] == ' ' || line[linelen-1] == '\t')) { if (linelen < 74) { sprintf (line+linelen-1, "=%2.2X", (unsigned char) line[linelen-1]); fputs (line, fout); } else { int savechar = line[linelen-1]; line[linelen-1] = '='; line[linelen] = 0; fputs (line, fout); fprintf (fout, "\n=%2.2X", (unsigned char) savechar); } } else { line[linelen] = 0; fputs (line, fout); } fputc ('\n', fout); linelen = 0; } else if (c != 9 && (c < 32 || c > 126 || c == '=')) { /* Check to make sure there is enough room for the quoted character. * If not, wrap to the next line. */ if (linelen > 73) { line[linelen++] = '='; line[linelen] = 0; fputs (line, fout); fputc ('\n', fout); linelen = 0; } sprintf (line+linelen,"=%2.2X", (unsigned char) c); linelen += 3; } else { /* Don't worry about wrapping the line here. That will happen during * the next iteration when I'll also know what the next character is. */ line[linelen++] = c; } } /* Take care of anything left in the buffer */ if (linelen > 0) { if (line[linelen-1] == ' ' || line[linelen-1] == '\t') { /* take care of trailing whitespace */ if (linelen < 74) sprintf (line+linelen-1, "=%2.2X", (unsigned char) line[linelen-1]); else { savechar = line[linelen-1]; line[linelen-1] = '='; line[linelen] = 0; fputs (line, fout); fputc ('\n', fout); sprintf (line, "=%2.2X", (unsigned char) savechar); } } else line[linelen] = 0; fputs (line, fout); }}static char b64_buffer[3];static short b64_num;static short b64_linelen;static void b64_flush(FILE *fout){ short i; if(!b64_num) return; if(b64_linelen >= 72) { fputc('\n', fout); b64_linelen = 0; } for(i = b64_num; i < 3; i++) b64_buffer[i] = '\0'; fputc(B64Chars[(b64_buffer[0] >> 2) & 0x3f], fout); b64_linelen++; fputc(B64Chars[((b64_buffer[0] & 0x3) << 4) | ((b64_buffer[1] >> 4) & 0xf) ], fout); b64_linelen++; if(b64_num > 1) { fputc(B64Chars[((b64_buffer[1] & 0xf) << 2) | ((b64_buffer[2] >> 6) & 0x3) ], fout); b64_linelen++; if(b64_num > 2) { fputc(B64Chars[b64_buffer[2] & 0x3f], fout); b64_linelen++; } } while(b64_linelen % 4) { fputc('=', fout); b64_linelen++; } b64_num = 0;} static void b64_putc(char c, FILE *fout){ if(b64_num == 3) b64_flush(fout); b64_buffer[b64_num++] = c;} static void encode_base64 (FGETCONV * fc, FILE *fout, int istext){ int ch, ch1 = EOF; b64_num = b64_linelen = 0; while ((ch = fgetconv (fc)) != EOF) { if (istext && ch == '\n' && ch1 != '\r') b64_putc('\r', fout); b64_putc(ch, fout); ch1 = ch; } b64_flush(fout); fputc('\n', fout);}static void encode_8bit (FGETCONV *fc, FILE *fout, int istext){ int ch; while ((ch = fgetconv (fc)) != EOF) fputc (ch, fout);} int mutt_write_mime_header (BODY *a, FILE *f){ PARAMETER *p; char buffer[STRING]; char *t; char *fn; int len; int tmplen; int encode; fprintf (f, "Content-Type: %s/%s", TYPE (a), a->subtype); if (a->parameter) { len = 25 + mutt_strlen (a->subtype); /* approximate len. of content-type */ for(p = a->parameter; p; p = p->next) { char *tmp; if(!p->value) continue; fputc (';', f); buffer[0] = 0; tmp = safe_strdup (p->value); encode = rfc2231_encode_string (&tmp); rfc822_cat (buffer, sizeof (buffer), tmp, MimeSpecials); /* Dirty hack to make messages readable by Outlook Express * for the Mac: force quotes around the boundary parameter * even when they aren't needed. */ if (!ascii_strcasecmp (p->attribute, "boundary") && !strcmp (buffer, tmp)) snprintf (buffer, sizeof (buffer), "\"%s\"", tmp); FREE (&tmp); tmplen = mutt_strlen (buffer) + mutt_strlen (p->attribute) + 1; if (len + tmplen + 2 > 76) { fputs ("\n\t", f); len = tmplen + 8; } else { fputc (' ', f); len += tmplen + 1; } fprintf (f, "%s%s=%s", p->attribute, encode ? "*" : "", buffer); } } fputc ('\n', f); if (a->description) fprintf(f, "Content-Description: %s\n", a->description); fprintf (f, "Content-Disposition: %s", DISPOSITION (a->disposition)); if (a->use_disp) { if(!(fn = a->d_filename)) fn = a->filename; if (fn) { char *tmp; /* Strip off the leading path... */ if ((t = strrchr (fn, '/'))) t++; else t = fn; buffer[0] = 0; tmp = safe_strdup (t); encode = rfc2231_encode_string (&tmp); rfc822_cat (buffer, sizeof (buffer), tmp, MimeSpecials); FREE (&tmp); fprintf (f, "; filename%s=%s", encode ? "*" : "", buffer); } } fputc ('\n', f); if (a->encoding != ENC7BIT) fprintf(f, "Content-Transfer-Encoding: %s\n", ENCODING (a->encoding)); /* Do NOT add the terminator here!!! */ return (ferror (f) ? -1 : 0);}# define write_as_text_part(a) (mutt_is_text_part(a) \ || ((WithCrypto & APPLICATION_PGP)\ && mutt_is_application_pgp(a)))int mutt_write_mime_body (BODY *a, FILE *f){ char *p, boundary[SHORT_STRING]; char send_charset[SHORT_STRING]; FILE *fpin; BODY *t; FGETCONV *fc; if (a->type == TYPEMULTIPART) { /* First, find the boundary to use */ if (!(p = mutt_get_parameter ("boundary", a->parameter))) { dprint (1, (debugfile, "mutt_write_mime_body(): no boundary parameter found!\n")); mutt_error _("No boundary parameter found! [report this error]"); return (-1); } strfcpy (boundary, p, sizeof (boundary)); for (t = a->parts; t ; t = t->next) { fprintf (f, "\n--%s\n", boundary); if (mutt_write_mime_header (t, f) == -1) return -1; fputc ('\n', f); if (mutt_write_mime_body (t, f) == -1) return -1; } fprintf (f, "\n--%s--\n", boundary); return (ferror (f) ? -1 : 0); } /* This is pretty gross, but it's the best solution for now... */ if ((WithCrypto & APPLICATION_PGP) && a->type == TYPEAPPLICATION && mutt_strcmp (a->subtype, "pgp-encrypted") == 0) { fputs ("Version: 1\n", f); return 0; } if ((fpin = fopen (a->filename, "r")) == NULL) { dprint(1,(debugfile, "write_mime_body: %s no longer exists!\n",a->filename)); mutt_error (_("%s no longer exists!"), a->filename); return -1; } if (a->type == TYPETEXT && (!a->noconv)) fc = fgetconv_open (fpin, Charset, mutt_get_body_charset (send_charset, sizeof (send_charset), a), 0); else fc = fgetconv_open (fpin, 0, 0, 0); if (a->encoding == ENCQUOTEDPRINTABLE) encode_quoted (fc, f, write_as_text_part (a)); else if (a->encoding == ENCBASE64) encode_base64 (fc, f, write_as_text_part (a)); else if (a->type == TYPETEXT && (!a->noconv)) encode_8bit (fc, f, write_as_text_part (a)); else mutt_copy_stream (fpin, f); fgetconv_close (&fc); fclose (fpin); return (ferror (f) ? -1 : 0);}#undef write_as_text_part#define BOUNDARYLEN 16void mutt_generate_boundary (PARAMETER **parm){ char rs[BOUNDARYLEN + 1]; char *p = rs; int i; rs[BOUNDARYLEN] = 0; for (i=0;i<BOUNDARYLEN;i++) *p++ = B64Chars[LRAND() % sizeof (B64Chars)]; *p = 0; mutt_set_parameter ("boundary", rs, parm);}typedef struct{ int from; int whitespace; int dot; int linelen; int was_cr;}CONTENT_STATE;static void update_content_info (CONTENT *info, CONTENT_STATE *s, char *d, size_t dlen){ int from = s->from; int whitespace = s->whitespace; int dot = s->dot; int linelen = s->linelen; int was_cr = s->was_cr; if (!d) /* This signals EOF */ { if (was_cr) info->binary = 1; if (linelen > info->linemax) info->linemax = linelen; return; } for (; dlen; d++, dlen--) { char ch = *d; if (was_cr) { was_cr = 0; if (ch != '\n') { info->binary = 1; } else { if (whitespace) info->space = 1; if (dot) info->dot = 1; if (linelen > info->linemax) info->linemax = linelen; whitespace = 0; dot = 0; linelen = 0; continue; } } linelen++; if (ch == '\n') { info->crlf++; if (whitespace) info->space = 1; if (dot) info->dot = 1; if (linelen > info->linemax) info->linemax = linelen; whitespace = 0; linelen = 0; dot = 0; } else if (ch == '\r') { info->crlf++; info->cr = 1; was_cr = 1; continue; } else if (ch & 0x80) info->hibin++; else if (ch == '\t' || ch == '\f') { info->ascii++; whitespace++; } else if (ch < 32 || ch == 127) info->lobin++; else { if (linelen == 1) { if ((ch == 'F') || (ch == 'f')) from = 1; else from = 0; if (ch == '.') dot = 1; else dot = 0; } else if (from) { if (linelen == 2 && ch != 'r') from = 0; else if (linelen == 3 && ch != 'o') from = 0; else if (linelen == 4) { if (ch == 'm') info->from = 1; from = 0; } } if (ch == ' ') whitespace++; info->ascii++; } if (linelen > 1) dot = 0; if (ch != ' ' && ch != '\t') whitespace = 0; } s->from = from; s->whitespace = whitespace; s->dot = dot; s->linelen = linelen; s->was_cr = was_cr; }/* Define as 1 if iconv sometimes returns -1(EILSEQ) instead of transcribing. */#define BUGGY_ICONV 1/* * Find the best charset conversion of the file from fromcode into one * of the tocodes. If successful, set *tocode and CONTENT *info and * return the number of characters converted inexactly. If no * conversion was possible, return -1. * * We convert via UTF-8 in order to avoid the condition -1(EINVAL), * which would otherwise prevent us from knowing the number of inexact * conversions. Where the candidate target charset is UTF-8 we avoid * doing the second conversion because iconv_open("UTF-8", "UTF-8") * fails with some libraries. *
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -