📄 sendlib.c
字号:
* We assume that the output from iconv is never more than 4 times as * long as the input for any pair of charsets we might be interested * in. */static size_t convert_file_to (FILE *file, const char *fromcode, int ncodes, const char **tocodes, int *tocode, CONTENT *info){#ifdef HAVE_ICONV iconv_t cd1, *cd; char bufi[256], bufu[512], bufo[4 * sizeof (bufi)]; ICONV_CONST char *ib, *ub; char *ob; size_t ibl, obl, ubl, ubl1, n, ret; int i; CONTENT *infos; CONTENT_STATE *states; size_t *score; cd1 = mutt_iconv_open ("UTF-8", fromcode, 0); if (cd1 == (iconv_t)(-1)) return -1; cd = safe_calloc (ncodes, sizeof (iconv_t)); score = safe_calloc (ncodes, sizeof (size_t)); states = safe_calloc (ncodes, sizeof (CONTENT_STATE)); infos = safe_calloc (ncodes, sizeof (CONTENT)); for (i = 0; i < ncodes; i++) if (ascii_strcasecmp (tocodes[i], "UTF-8")) cd[i] = mutt_iconv_open (tocodes[i], "UTF-8", 0); else /* Special case for conversion to UTF-8 */ cd[i] = (iconv_t)(-1), score[i] = (size_t)(-1); rewind (file); ibl = 0; for (;;) { /* Try to fill input buffer */ n = fread (bufi + ibl, 1, sizeof (bufi) - ibl, file); ibl += n; /* Convert to UTF-8 */ ib = bufi; ob = bufu, obl = sizeof (bufu); n = iconv (cd1, ibl ? &ib : 0, &ibl, &ob, &obl); assert (n == (size_t)(-1) || !n || ICONV_NONTRANS); if (n == (size_t)(-1) && ((errno != EINVAL && errno != E2BIG) || ib == bufi)) { assert (errno == EILSEQ || (errno == EINVAL && ib == bufi && ibl < sizeof (bufi))); ret = (size_t)(-1); break; } ubl1 = ob - bufu; /* Convert from UTF-8 */ for (i = 0; i < ncodes; i++) if (cd[i] != (iconv_t)(-1) && score[i] != (size_t)(-1)) { ub = bufu, ubl = ubl1; ob = bufo, obl = sizeof (bufo); n = iconv (cd[i], (ibl || ubl) ? &ub : 0, &ubl, &ob, &obl); if (n == (size_t)(-1)) { assert (errno == E2BIG || (BUGGY_ICONV && (errno == EILSEQ || errno == ENOENT))); score[i] = (size_t)(-1); } else { score[i] += n; update_content_info (&infos[i], &states[i], bufo, ob - bufo); } } else if (cd[i] == (iconv_t)(-1) && score[i] == (size_t)(-1)) /* Special case for conversion to UTF-8 */ update_content_info (&infos[i], &states[i], bufu, ubl1); if (ibl) /* Save unused input */ memmove (bufi, ib, ibl); else if (!ubl1 && ib < bufi + sizeof (bufi)) { ret = 0; break; } } if (!ret) { /* Find best score */ ret = (size_t)(-1); for (i = 0; i < ncodes; i++) { if (cd[i] == (iconv_t)(-1) && score[i] == (size_t)(-1)) { /* Special case for conversion to UTF-8 */ *tocode = i; ret = 0; break; } else if (cd[i] == (iconv_t)(-1) || score[i] == (size_t)(-1)) continue; else if (ret == (size_t)(-1) || score[i] < ret) { *tocode = i; ret = score[i]; if (!ret) break; } } if (ret != (size_t)(-1)) { memcpy (info, &infos[*tocode], sizeof(CONTENT)); update_content_info (info, &states[*tocode], 0, 0); /* EOF */ } } for (i = 0; i < ncodes; i++) if (cd[i] != (iconv_t)(-1)) iconv_close (cd[i]); iconv_close (cd1); FREE (&cd); FREE (&infos); FREE (&score); FREE (&states); return ret;#else return -1;#endif /* !HAVE_ICONV */}/* * Find the first of the fromcodes that gives a valid conversion and * the best charset conversion of the file into one of the tocodes. If * successful, set *fromcode and *tocode to dynamically allocated * strings, set CONTENT *info, and return the number of characters * converted inexactly. If no conversion was possible, return -1. * * Both fromcodes and tocodes may be colon-separated lists of charsets. * However, if fromcode is zero then fromcodes is assumed to be the * name of a single charset even if it contains a colon. */static size_t convert_file_from_to (FILE *file, const char *fromcodes, const char *tocodes, char **fromcode, char **tocode, CONTENT *info){ char *fcode; char **tcode; const char *c, *c1; size_t ret; int ncodes, i, cn; /* Count the tocodes */ ncodes = 0; for (c = tocodes; c; c = c1 ? c1 + 1 : 0) { if ((c1 = strchr (c, ':')) == c) continue; ++ncodes; } /* Copy them */ tcode = safe_malloc (ncodes * sizeof (char *)); for (c = tocodes, i = 0; c; c = c1 ? c1 + 1 : 0, i++) { if ((c1 = strchr (c, ':')) == c) continue; tcode[i] = mutt_substrdup (c, c1); } ret = (size_t)(-1); if (fromcode) { /* Try each fromcode in turn */ for (c = fromcodes; c; c = c1 ? c1 + 1 : 0) { if ((c1 = strchr (c, ':')) == c) continue; fcode = mutt_substrdup (c, c1); ret = convert_file_to (file, fcode, ncodes, (const char **)tcode, &cn, info); if (ret != (size_t)(-1)) { *fromcode = fcode; *tocode = tcode[cn]; tcode[cn] = 0; break; } FREE (&fcode); } } else { /* There is only one fromcode */ ret = convert_file_to (file, fromcodes, ncodes, (const char **)tcode, &cn, info); if (ret != (size_t)(-1)) { *tocode = tcode[cn]; tcode[cn] = 0; } } /* Free memory */ for (i = 0; i < ncodes; i++) FREE (&tcode[i]); FREE (tcode); /* __FREE_CHECKED__ */ return ret;}/* * Analyze the contents of a file to determine which MIME encoding to use. * Also set the body charset, sometimes, or not. */CONTENT *mutt_get_content_info (const char *fname, BODY *b){ CONTENT *info; CONTENT_STATE state; FILE *fp = NULL; char *tocode; char buffer[100]; char chsbuf[STRING]; size_t r; struct stat sb; if(b && !fname) fname = b->filename; if (stat (fname, &sb) == -1) { mutt_error (_("Can't stat %s: %s"), fname, strerror (errno)); return NULL; } if (!S_ISREG(sb.st_mode)) { mutt_error (_("%s isn't a regular file."), fname); return NULL; } if ((fp = fopen (fname, "r")) == NULL) { dprint (1, (debugfile, "mutt_get_content_info: %s: %s (errno %d).\n", fname, strerror (errno), errno)); return (NULL); } info = safe_calloc (1, sizeof (CONTENT)); memset (&state, 0, sizeof (state)); if (b != NULL && b->type == TYPETEXT && (!b->noconv && !b->force_charset)) { char *chs = mutt_get_parameter ("charset", b->parameter); if (Charset && (chs || SendCharset) && convert_file_from_to (fp, Charset, chs ? chs : SendCharset, 0, &tocode, info) != (size_t)(-1)) { if (!chs) { mutt_canonical_charset (chsbuf, sizeof (chsbuf), tocode); mutt_set_parameter ("charset", chsbuf, &b->parameter); } FREE (&tocode); safe_fclose (&fp); return info; } } rewind (fp); while ((r = fread (buffer, 1, sizeof(buffer), fp))) update_content_info (info, &state, buffer, r); update_content_info (info, &state, 0, 0); safe_fclose (&fp); if (b != NULL && b->type == TYPETEXT && (!b->noconv && !b->force_charset)) mutt_set_parameter ("charset", (!info->hibin ? "us-ascii" : Charset && !mutt_is_us_ascii (Charset) ? Charset : "unknown-8bit"), &b->parameter); return info;}/* Given a file with path ``s'', see if there is a registered MIME type. * returns the major MIME type, and copies the subtype to ``d''. First look * for ~/.mime.types, then look in a system mime.types if we can find one. * The longest match is used so that we can match `ps.gz' when `gz' also * exists. */int mutt_lookup_mime_type (BODY *att, const char *path){ FILE *f; char *p, *q, *ct; char buf[LONG_STRING]; char subtype[STRING], xtype[STRING]; int count; int szf, sze, cur_sze; int type; *subtype = '\0'; *xtype = '\0'; type = TYPEOTHER; cur_sze = 0; szf = mutt_strlen (path); for (count = 0 ; count < 3 ; count++) { /* * can't use strtok() because we use it in an inner loop below, so use * a switch statement here instead. */ switch (count) { case 0: snprintf (buf, sizeof (buf), "%s/.mime.types", NONULL(Homedir)); break; case 1: strfcpy (buf, SYSCONFDIR"/mime.types", sizeof(buf)); break; case 2: strfcpy (buf, PKGDATADIR"/mime.types", sizeof (buf)); break; default: dprint (1, (debugfile, "mutt_lookup_mime_type: Internal error, count = %d.\n", count)); goto bye; /* shouldn't happen */ } if ((f = fopen (buf, "r")) != NULL) { while (fgets (buf, sizeof (buf) - 1, f) != NULL) { /* weed out any comments */ if ((p = strchr (buf, '#'))) *p = 0; /* remove any leading space. */ ct = buf; SKIPWS (ct); /* position on the next field in this line */ if ((p = strpbrk (ct, " \t")) == NULL) continue; *p++ = 0; SKIPWS (p); /* cycle through the file extensions */ while ((p = strtok (p, " \t\n"))) { sze = mutt_strlen (p); if ((sze > cur_sze) && (szf >= sze) && (mutt_strcasecmp (path + szf - sze, p) == 0 || ascii_strcasecmp (path + szf - sze, p) == 0) && (szf == sze || path[szf - sze - 1] == '.')) { /* get the content-type */ if ((p = strchr (ct, '/')) == NULL) { /* malformed line, just skip it. */ break; } *p++ = 0; for (q = p; *q && !ISSPACE (*q); q++) ; mutt_substrcpy (subtype, p, q, sizeof (subtype)); if ((type = mutt_check_mime_type (ct)) == TYPEOTHER) strfcpy (xtype, ct, sizeof (xtype)); cur_sze = sze; } p = NULL; } } fclose (f); } } bye: if (type != TYPEOTHER || *xtype != '\0') { att->type = type; mutt_str_replace (&att->subtype, subtype); mutt_str_replace (&att->xtype, xtype); } return (type);}void mutt_message_to_7bit (BODY *a, FILE *fp){ char temp[_POSIX_PATH_MAX]; char *line = NULL; FILE *fpin = NULL; FILE *fpout = NULL; struct stat sb; if (!a->filename && fp) fpin = fp; else if (!a->filename || !(fpin = fopen (a->filename, "r"))) { mutt_error (_("Could not open %s"), a->filename ? a->filename : "(null)"); return; } else { a->offset = 0; if (stat (a->filename, &sb) == -1) { mutt_perror ("stat"); fclose (fpin); } a->length = sb.st_size; } mutt_mktemp (temp); if (!(fpout = safe_fopen (temp, "w+"))) { mutt_perror ("fopen"); goto cleanup; } fseeko (fpin, a->offset, 0); a->parts = mutt_parse_messageRFC822 (fpin, a); transform_to_7bit (a->parts, fpin); mutt_copy_hdr (fpin, fpout, a->offset, a->offset + a->length, CH_MIME | CH_NONEWLINE | CH_XMIT, NULL); fputs ("MIME-Version: 1.0\n", fpout); mutt_write_mime_header (a->parts, fpout); fputc ('\n', fpout); mutt_write_mime_body (a->parts, fpout); cleanup: FREE (&line); if (fpin && !fp) fclose (fpin); if (fpout) fclose (fpout); else return; a->encoding = ENC7BIT; a->d_filename = a->filename; if (a->filename && a->unlink) unlink (a->filename); a->filename = safe_strdup (temp); a->unlink = 1; if(stat (a->filename, &sb) == -1) { mutt_perror ("stat"); return; } a->length = sb.st_size; mutt_free_body (&a->parts); a->hdr->content = NULL;}static void transform_to_7bit (BODY *a, FILE *fpin){ char buff[_POSIX_PATH_MAX]; STATE s; struct stat sb; memset (&s, 0, sizeof (s)); for (; a; a = a->next) { if (a->type == TYPEMULTIPART) { if (a->encoding != ENC7BIT) a->encoding = ENC7BIT; transform_to_7bit (a->parts, fpin); } else if (mutt_is_message_type(a->type, a->subtype)) { mutt_message_to_7bit (a, fpin); } else { a->noconv = 1; a->force_charset = 1; mutt_mktemp (buff); if ((s.fpout = safe_fopen (buff, "w")) == NULL) { mutt_perror ("fopen"); return; } s.fpin = fpin; mutt_decode_attachment (a, &s); fclose (s.fpout); a->d_filename = a->filename; a->filename = safe_strdup (buff); a->unlink = 1; if (stat (a->filename, &sb) == -1) { mutt_perror ("stat"); return; } a->length = sb.st_size; mutt_update_encoding (a); if (a->encoding == ENC8BIT) a->encoding = ENCQUOTEDPRINTABLE; else if(a->encoding == ENCBINARY) a->encoding = ENCBASE64; } }}/* determine which Content-Transfer-Encoding to use */static void mutt_set_encoding (BODY *b, CONTENT *info){ char send_charset[SHORT_STRING]; if (b->type == TYPETEXT) { char *chsname = mutt_get_body_charset (send_charset, sizeof (send_charset), b); if ((info->lobin && ascii_strncasecmp (chsname, "iso-2022", 8)) || info->linemax > 990 || (info->from && option (OPTENCODEFROM))) b->encoding = ENCQUOTEDPRINTABLE; else if (info->hibin) b->encoding = option (OPTALLOW8BIT) ? ENC8BIT : ENCQUOTEDPRINTABLE; else b->encoding = ENC7BIT; } else if (b->type == TYPEMESSAGE || b->type == TYPEMULTIPART) { if (info->lobin || info->hibin) { if (option (OPTALLOW8BIT) && !info->lobin) b->encoding = ENC8BIT; else mutt_message_to_7bit (b, NULL); } else b->encoding = ENC7BIT; } else if (b->type == TYPEAPPLICATION && ascii_strcasecmp (b->subtype, "pgp-keys") == 0) b->encoding = ENC7BIT; else#if 0 if (info->lobin || info->hibin || info->binary || info->linemax > 990 || info->cr || (/* option (OPTENCODEFROM) && */ info->from))#endif { /* Determine which encoding is smaller */ if (1.33 * (float)(info->lobin+info->hibin+info->ascii) < 3.0 * (float)(info->lobin + info->hibin) + (float)info->ascii) b->encoding = ENCBASE64; else b->encoding = ENCQUOTEDPRINTABLE; }#if 0 else b->encoding = ENC7BIT;#endif}void mutt_stamp_attachment(BODY *a){ a->stamp = time(NULL);}/* Get a body's character set */char *mutt_get_body_charset (char *d, size_t dlen, BODY *b){ char *p = NULL; if (b && b->type != TYPETEXT) return NULL; if (b) p = mutt_get_parameter ("charset", b->parameter); if (p) mutt_canonical_charset (d, dlen, NONULL(p)); else strfcpy (d, "us-ascii", dlen); return d;}/* Assumes called from send mode where BODY->filename points to actual file */void mutt_update_encoding (BODY *a){ CONTENT *info; char chsbuff[STRING]; /* override noconv when it's us-ascii */ if (mutt_is_us_ascii (mutt_get_body_charset (chsbuff, sizeof (chsbuff), a))) a->noconv = 0; if (!a->force_charset && !a->noconv) mutt_delete_parameter ("charset", &a->parameter);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -