mimeutils.c
上传用户:knt0001
上传日期:2022-01-28
资源大小:264k
文件大小:7k
源码类别:

Email客户端

开发平台:

C/C++

  1. /**
  2.     eMail is a command line SMTP client.
  3.     Copyright (C) 2001 - 2008 email by Dean Jones
  4.     Software supplied and written by http://www.cleancode.org
  5.     This file is part of eMail.
  6.     eMail is free software; you can redistribute it and/or modify
  7.     it under the terms of the GNU General Public License as published by
  8.     the Free Software Foundation; either version 2 of the License, or
  9.     (at your option) any later version.
  10.     eMail is distributed in the hope that it will be useful,
  11.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.     GNU General Public License for more details.
  14.     You should have received a copy of the GNU General Public License
  15.     along with eMail; if not, write to the Free Software
  16.     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  17. **/
  18. #if HAVE_CONFIG_H
  19. # include "config.h"
  20. #endif
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23. #include <string.h>
  24. #include <sys/types.h>
  25. #include "email.h"
  26. #include "utils.h"
  27. #include "dstrbuf.h"
  28. #include "dutil.h"
  29. #include "mimeutils.h"
  30. static dstrbuf *
  31. getMimeType(const char *str)
  32. {
  33. dstrbuf *ret = DSB_NEW;
  34. while (*str != ' ' && *str != 't' && *str != '') {
  35. dsbnCat(ret, str, 1);
  36. str++;
  37. }
  38. return ret;
  39. }
  40. /**
  41.  * get the name of the file going to be attached from an absolute path 
  42. **/
  43. dstrbuf *
  44. mimeFilename(const char *in_name)
  45. {
  46. char *nameptr=NULL;
  47. dstrbuf *ret = DSB_NEW;
  48. nameptr = strrchr(in_name, '/');
  49. if (nameptr) {
  50. dsbCopy(ret, ++nameptr);
  51. } else {
  52. dsbCopy(ret, in_name);
  53. }
  54. return ret;
  55. }
  56. /**
  57.  * executes the 'file' command with the -bi options.
  58.  * it redirects stderr to /dev/null.  If the command
  59.  * didn't execute properly, or the type returned is
  60.  * something that does not look like a mime type, then
  61.  * application/unknown is returned.
  62. **/
  63. #define MAGIC_FILE EMAIL_DIR "/mime.types"
  64. dstrbuf *
  65. mimeFiletype(const char *filename)
  66. {
  67. bool found=false;
  68. int i=0, veclen=0;
  69. dstrbuf *type=NULL;
  70. dstrbuf *buf=DSB_NEW;
  71. dvector vec=NULL;
  72. const char *ext=NULL;
  73. dstrbuf *filen=NULL;
  74. FILE *file = fopen(MAGIC_FILE, "r");
  75. if (!file) {
  76. goto exit;
  77. }
  78. filen = mimeFilename(filename);
  79. ext = strrchr(filen->str, '.');
  80. /* If we don't know  the extension, we don't know what type
  81.  * of file it's going to be. Therefore, skip all of this.  */
  82. if (!ext) {
  83. goto exit;
  84. }
  85. /* Get past . in extension name. */
  86. ext++;
  87. while (!feof(file)) {
  88. dsbReadline(buf, file);
  89. if (buf->str[0] == '#' || buf->str[0] == 'n') {
  90. continue;
  91. }
  92. chomp(buf->str);
  93. /* If we still have an allocated type, free it */
  94. if (type) {
  95. dsbDestroy(type);
  96. }
  97. type = getMimeType(buf->str);
  98. if (type->len == 0) {
  99. continue;
  100. }
  101. vec = explode(buf->str, " t");
  102. veclen = dvLength(vec);
  103. /* Start i at 1 since the first element in the
  104.  * vector is the mime type. The exts are after that. */
  105. for (i=1; i < veclen; i++) {
  106. if (strcmp((char *)vec[i], ext) == 0) {
  107. found = true;
  108. break;
  109. }
  110. }
  111. dvDestroy(vec);
  112. if (found) {
  113. /* Found it! */
  114. break;
  115. }
  116. }
  117. exit:
  118. dsbDestroy(filen);
  119. dsbDestroy(buf);
  120. if (file) {
  121. fclose(file);
  122. }
  123. if (!type || type->len == 0) {
  124. type = DSB_NEW;
  125. dsbCopy(type, "application/unknown");
  126. }
  127. return type;
  128. }
  129. /**
  130.  * Makes a boundary for Mime emails 
  131. **/
  132. dstrbuf *
  133. mimeMakeBoundary(void)
  134. {
  135. dstrbuf *buf=DSB_NEW;
  136. dstrbuf *rstr=randomString(15);
  137. dsbPrintf(buf, "=-%s", rstr->str);
  138. return buf;
  139. }
  140. /**
  141.  * This base64 bit of code was taken from a program written by: Bob Trower
  142.  * I didn't see a point in reinvinting the wheel here, so I found the best code for
  143.  * this portion and implimented it to suit the best needs of our program.
  144.  *
  145.  * To find out more about Bob Trower and his b64.c project, go to
  146.  * http://base64.sourceforge.net
  147. **/
  148. #define MAX_B64_LINE 72
  149. /* Our base64 table of chars */
  150. static const char cb64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 
  151.    "abcdefghijklmnopqrstuvwxyz" 
  152.    "0123456789+/";
  153. /**
  154.  * encode 3 8-bit binary bytes as 4 '6-bit' characters
  155. **/
  156. static void
  157. mimeB64EncodeBlock(const u_char in[3], u_char out[4], int len)
  158. {
  159. out[0] = cb64[in[0] >> 2];
  160. out[1] = cb64[((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4)];
  161. out[2] = (u_char) (len > 1 ? cb64[((in[1] & 0x0f) << 2) | 
  162.  ((in[2] & 0xc0) >> 6)] : '=');
  163. out[3] = (u_char) (len > 2 ? cb64[in[2] & 0x3f] : '=');
  164. }
  165. /**
  166.  * Encode_file will encode file infile placing it 
  167.  * in file outfile including padding and EOL of rn properly
  168. **/
  169. int
  170. mimeB64EncodeFile(FILE *infile, dstrbuf *outbuf)
  171. {
  172. u_char in[3], out[4];
  173. int i, len, blocksout = 0;
  174. while (!feof(infile)) {
  175. len = 0;
  176. for (i = 0; i < 3; i++) {
  177. in[i] = (u_char) getc(infile);
  178. if (!feof(infile)) {
  179. len++;
  180. } else {
  181. in[i] = 0;
  182. }
  183. }
  184. if (len) {
  185. mimeB64EncodeBlock(in, out, len);
  186. dsbnCat(outbuf, (char *)out, 4);
  187. blocksout++;
  188. }
  189. if (blocksout >= (MAX_B64_LINE / 4) || feof(infile)) {
  190. if (blocksout) {
  191. dsbCat(outbuf, "rn");
  192. }
  193. blocksout = 0;
  194. }
  195. if (ferror(infile)) {
  196. return -1;
  197. }
  198. }
  199. return 0;
  200. }
  201. /**
  202.  * Encode a string into base64.
  203.  */
  204. dstrbuf *
  205. mimeB64EncodeString(const u_char *inbuf, size_t len, bool maxline)
  206. {
  207. u_int i=0, j=0, blk_size=0, blocksout=0;
  208. dstrbuf *retbuf = dsbNew(100);
  209. u_char block[3], encblock[4];
  210. /* Loop through the entire string encoding 3 8-bit chunks. */
  211. while (i < len) {
  212. blk_size = 0;
  213. for (j=0; j < 3; j++) {
  214. if (i < len) {
  215. block[j] = inbuf[i++];
  216. blk_size++;
  217. } else {
  218. block[j] = 0;
  219. }
  220. }
  221. mimeB64EncodeBlock(block, encblock, blk_size);
  222. dsbnCat(retbuf, (char *)encblock, 4);
  223. blocksout++;
  224. if (maxline && (blocksout >= (MAX_B64_LINE / 4) || i == len)) {
  225. dsbPrintf(retbuf, "rn");
  226. blocksout = 0;
  227. }
  228. }
  229. return retbuf;
  230. }
  231. /* RFC 2045 standard line length not counting CRLF */
  232. #define QP_MAX_LINE_LEN 76
  233. /* Max size of a buffer including CRLF and NUL */
  234. #define MAX_QP_BUF 79
  235. /**
  236.  * RFC 2045 says:
  237.  * chars 9 - 32 (if not trailing end-of-line)
  238.  * chars 33 - 60
  239.  * chars 62 - 126
  240.  * can be represented as-is.  All others 
  241.  * should be encoded.
  242. **/
  243. static int
  244. qpIsEncodable(int c)
  245. {
  246. if (((c >= 9) && (c <= 60)) || ((c >= 62) && (c <= 126))) {
  247. return 0;
  248. }
  249. return 1;
  250. }
  251. static void
  252. qpStdout(int ch, int *curr_len, dstrbuf *out, bool wrap)
  253. {
  254. if ((*curr_len == (QP_MAX_LINE_LEN - 1)) && wrap) {
  255. dsbPrintf(out, "=rn");
  256. *curr_len = 0;
  257. }
  258. dsbPrintf(out, "%c", ch);
  259. (*curr_len)++;
  260. }
  261. static void
  262. qpEncout(int ch, int *curr_len, dstrbuf *out, bool wrap)
  263. {
  264. if (((*curr_len + 3) >= QP_MAX_LINE_LEN) && wrap) {
  265. dsbPrintf(out, "=rn");
  266. *curr_len = 0;
  267. }
  268. dsbPrintf(out, "=%02X", ch);
  269. *curr_len += 3;
  270. }
  271. /**
  272.  * Encode a quoted printable string.
  273. **/
  274. dstrbuf *
  275. mimeQpEncodeString(const u_char *str, bool wrap)
  276. {
  277. int line_len=0;
  278. dstrbuf *out = DSB_NEW;
  279. for (; *str != ''; str++) {
  280. if (line_len == (QP_MAX_LINE_LEN - 1) && wrap) {
  281. dsbPrintf(out, "=rn");
  282. line_len = 0;
  283. }
  284. switch (*str) {
  285. case ' ':
  286. case 't':
  287. if ((str[1] == 'r') || (str[1] == 'n')) {
  288. qpEncout(*str, &line_len, out, wrap);
  289. } else {
  290. qpStdout(*str, &line_len, out, wrap);
  291. }
  292. break;
  293. case 'r':
  294. str++;          /* Get to newline */
  295. case 'n':
  296. dsbPrintf(out, "rn");
  297. line_len = 0;
  298. break;
  299. default:
  300. if (qpIsEncodable(*str)) {
  301. qpEncout(*str, &line_len, out, wrap);
  302. } else {
  303. qpStdout(*str, &line_len, out, wrap);
  304. }
  305. break;
  306. }
  307. }
  308. return out;
  309. }