rmail.c
上传用户:xu_441
上传日期:2007-01-04
资源大小:1640k
文件大小:10k
源码类别:

Email客户端

开发平台:

Unix_Linux

  1. /*
  2.  * Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers.
  3.  * All rights reserved.
  4.  * Copyright (c) 1988, 1993
  5.  * The Regents of the University of California.  All rights reserved.
  6.  *
  7.  * By using this file, you agree to the terms and conditions set
  8.  * forth in the LICENSE file which can be found at the top level of
  9.  * the sendmail distribution.
  10.  *
  11.  */
  12. #ifndef lint
  13. static char copyright[] =
  14. "@(#) Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers.n
  15. All rights reserved.n
  16.      Copyright (c) 1988, 1993n
  17. The Regents of the University of California.  All rights reserved.n";
  18. #endif /* ! lint */
  19. #ifndef lint
  20. static char id[] = "@(#)$Id: rmail.c,v 8.33 1999/08/31 21:03:55 ca Exp $";
  21. #endif /* ! lint */
  22. /*
  23.  * RMAIL -- UUCP mail server.
  24.  *
  25.  * This program reads the >From ... remote from ... lines that UUCP is so
  26.  * fond of and turns them into something reasonable.  It then execs sendmail
  27.  * with various options built from these lines.
  28.  *
  29.  * The expected syntax is:
  30.  *
  31.  *  <user> := [-a-z0-9]+
  32.  *  <date> := ctime format
  33.  *  <site> := [-a-z0-9!]+
  34.  * <blank line> := "^n$"
  35.  *  <from> := "From" <space> <user> <space> <date>
  36.  *   [<space> "remote from" <space> <site>]
  37.  *    <forward> := ">" <from>
  38.  *     msg := <from> <forward>* <blank-line> <body>
  39.  *
  40.  * The output of rmail(8) compresses the <forward> lines into a single
  41.  * from path.
  42.  *
  43.  * The err(3) routine is included here deliberately to make this code
  44.  * a bit more portable.
  45.  */
  46. #include <sys/param.h>
  47. #include <sys/stat.h>
  48. #include <sys/wait.h>
  49. #include <ctype.h>
  50. #include <fcntl.h>
  51. #ifdef BSD4_4
  52. # define FORK vfork
  53. # include <paths.h>
  54. #else /* BSD4_4 */
  55. # define FORK fork
  56. # ifndef _PATH_SENDMAIL
  57. #  define _PATH_SENDMAIL "/usr/lib/sendmail"
  58. # endif /* ! _PATH_SENDMAIL */
  59. #endif /* BSD4_4 */
  60. #include <stdio.h>
  61. #include <stdlib.h>
  62. #include <string.h>
  63. #include <unistd.h>
  64. #ifdef EX_OK
  65. # undef EX_OK /* unistd.h may have another use for this */
  66. #endif /* EX_OK */
  67. #include <sysexits.h>
  68. #ifndef MAX
  69. # define MAX(a, b) ((a) < (b) ? (b) : (a))
  70. #endif /* ! MAX */
  71. #ifndef __P
  72. # ifdef __STDC__
  73. #  define __P(protos) protos
  74. # else /* __STDC__ */
  75. #  define __P(protos) ()
  76. #  define const
  77. # endif /* __STDC__ */
  78. #endif /* ! __P */
  79. #if defined(BSD4_4) || defined(linux) || SOLARIS >= 20600 || (SOLARIS < 10000 && SOLARIS >= 206)
  80. # define HASSNPRINTF 1
  81. #endif /* defined(BSD4_4) || defined(linux) || SOLARIS >= 20600 || (SOLARIS < 10000 && SOLARIS >= 206) */
  82. #if defined(sun) && !defined(BSD) && !defined(SOLARIS) && !defined(__svr4__) && !defined(__SVR4)
  83. # define memmove(d, s, l) (bcopy((s), (d), (l)))
  84. #endif /* defined(sun) && !defined(BSD) && !defined(SOLARIS) && !defined(__svr4__) && !defined(__SVR4) */
  85. #if !HASSNPRINTF
  86. extern int snprintf __P((char *, size_t, const char *, ...));
  87. #endif /* !HASSNPRINTF */
  88. #if defined(BSD4_4) || defined(__osf__) || defined(__GNU_LIBRARY__) || defined(IRIX64) || defined(IRIX5) || defined(IRIX6)
  89. # ifndef HASSTRERROR
  90. #  define HASSTRERROR 1
  91. # endif /* ! HASSTRERROR */
  92. #endif /* defined(BSD4_4) || defined(__osf__) || defined(__GNU_LIBRARY__) ||
  93.   defined(IRIX64) || defined(IRIX5) || defined(IRIX6) */
  94. #include "sendmail/errstring.h"
  95. static void err __P((int, const char *, ...));
  96. static void usage __P((void));
  97. static char *xalloc __P((int));
  98. #define newstr(s) strcpy(xalloc(strlen(s) + 1), s)
  99. static char *
  100. xalloc(sz)
  101. register int sz;
  102. {
  103. register char *p;
  104. /* some systems can't handle size zero mallocs */
  105. if (sz <= 0)
  106. sz = 1;
  107. p = malloc((unsigned) sz);
  108. if (p == NULL)
  109. err(EX_TEMPFAIL, "out of memory");
  110. return (p);
  111. }
  112. int
  113. main(argc, argv)
  114. int argc;
  115. char *argv[];
  116. {
  117. int ch, debug, i, pdes[2], pid, status;
  118. size_t fplen = 0, fptlen = 0, len;
  119. off_t offset;
  120. FILE *fp;
  121. char *addrp = NULL, *domain, *p, *t;
  122. char *from_path, *from_sys, *from_user;
  123. char *args[100], buf[2048], lbuf[2048];
  124. struct stat sb;
  125. extern char *optarg;
  126. extern int optind;
  127. debug = 0;
  128. domain = "UUCP"; /* Default "domain". */
  129. while ((ch = getopt(argc, argv, "D:T")) != EOF)
  130. {
  131. switch (ch)
  132. {
  133.   case 'T':
  134. debug = 1;
  135. break;
  136.   case 'D':
  137. domain = optarg;
  138. break;
  139.   case '?':
  140.   default:
  141. usage();
  142. }
  143. }
  144. argc -= optind;
  145. argv += optind;
  146. if (argc < 1)
  147. usage();
  148. from_path = from_sys = from_user = NULL;
  149. for (offset = 0; ; )
  150. {
  151. /* Get and nul-terminate the line. */
  152. if (fgets(lbuf, sizeof(lbuf), stdin) == NULL)
  153. exit(EX_DATAERR);
  154. if ((p = strchr(lbuf, 'n')) == NULL)
  155. err(EX_DATAERR, "line too long");
  156. *p = '';
  157. /* Parse lines until reach a non-"From" line. */
  158. if (!strncmp(lbuf, "From ", 5))
  159. addrp = lbuf + 5;
  160. else if (!strncmp(lbuf, ">From ", 6))
  161. addrp = lbuf + 6;
  162. else if (offset == 0)
  163. err(EX_DATAERR,
  164.     "missing or empty From line: %s", lbuf);
  165. else
  166. {
  167. *p = 'n';
  168. break;
  169. }
  170. if (*addrp == '')
  171. err(EX_DATAERR, "corrupted From line: %s", lbuf);
  172. /* Use the "remote from" if it exists. */
  173. for (p = addrp; (p = strchr(p + 1, 'r')) != NULL; )
  174. {
  175. if (!strncmp(p, "remote from ", 12))
  176. {
  177. for (t = p += 12; *t != ''; ++t)
  178. {
  179. if (isascii(*t) && isspace(*t))
  180. break;
  181. }
  182. *t = '';
  183. if (debug)
  184. fprintf(stderr, "remote from: %sn", p);
  185. break;
  186. }
  187. }
  188. /* Else use the string up to the last bang. */
  189. if (p == NULL)
  190. {
  191. if (*addrp == '!')
  192. err(EX_DATAERR, "bang starts address: %s",
  193.     addrp);
  194. else if ((t = strrchr(addrp, '!')) != NULL)
  195. {
  196. *t = '';
  197. p = addrp;
  198. addrp = t + 1;
  199. if (*addrp == '')
  200. err(EX_DATAERR,
  201.     "corrupted From line: %s", lbuf);
  202. if (debug)
  203. fprintf(stderr, "bang: %sn", p);
  204. }
  205. }
  206. /* 'p' now points to any system string from this line. */
  207. if (p != NULL)
  208. {
  209. /* Nul terminate it as necessary. */
  210. for (t = p; *t != ''; ++t)
  211. {
  212. if (isascii(*t) && isspace(*t))
  213. break;
  214. }
  215. *t = '';
  216. /* If the first system, copy to the from_sys string. */
  217. if (from_sys == NULL)
  218. {
  219. from_sys = newstr(p);
  220. if (debug)
  221. fprintf(stderr, "from_sys: %sn",
  222. from_sys);
  223. }
  224. /* Concatenate to the path string. */
  225. len = t - p;
  226. if (from_path == NULL)
  227. {
  228. fplen = 0;
  229. if ((from_path = malloc(fptlen = 256)) == NULL)
  230. err(EX_TEMPFAIL, NULL);
  231. }
  232. if (fplen + len + 2 > fptlen)
  233. {
  234. fptlen += MAX(fplen + len + 2, 256);
  235. if ((from_path = realloc(from_path,
  236.  fptlen)) == NULL)
  237. err(EX_TEMPFAIL, NULL);
  238. }
  239. memmove(from_path + fplen, p, len);
  240. fplen += len;
  241. from_path[fplen++] = '!';
  242. from_path[fplen] = '';
  243. }
  244. /* Save off from user's address; the last one wins. */
  245. for (p = addrp; *p != ''; ++p)
  246. {
  247. if (isascii(*p) && isspace(*p))
  248. break;
  249. }
  250. *p = '';
  251. if (*addrp == '')
  252. addrp = "<>";
  253. if (from_user != NULL)
  254. free(from_user);
  255. from_user = newstr(addrp);
  256. if (debug)
  257. {
  258. if (from_path != NULL)
  259. fprintf(stderr, "from_path: %sn", from_path);
  260. fprintf(stderr, "from_user: %sn", from_user);
  261. }
  262. if (offset != -1)
  263. offset = (off_t)ftell(stdin);
  264. }
  265. i = 0;
  266. args[i++] = _PATH_SENDMAIL; /* Build sendmail's argument list. */
  267. args[i++] = "-oee"; /* No errors, just status. */
  268. args[i++] = "-odq"; /* Queue it, don't try to deliver. */
  269. args[i++] = "-oi"; /* Ignore '.' on a line by itself. */
  270. /* set from system and protocol used */
  271. if (from_sys == NULL)
  272. snprintf(buf, sizeof(buf), "-p%s", domain);
  273. else if (strchr(from_sys, '.') == NULL)
  274. snprintf(buf, sizeof(buf), "-p%s:%s.%s",
  275. domain, from_sys, domain);
  276. else
  277. snprintf(buf, sizeof(buf), "-p%s:%s", domain, from_sys);
  278. args[i++] = newstr(buf);
  279. /* Set name of ``from'' person. */
  280. snprintf(buf, sizeof(buf), "-f%s%s",
  281.  from_path ? from_path : "", from_user);
  282. args[i++] = newstr(buf);
  283. /*
  284. **  Don't copy arguments beginning with - as they will be
  285. **  passed to sendmail and could be interpreted as flags.
  286. **  To prevent confusion of sendmail wrap < and > around
  287. **  the address (helps to pass addrs like @gw1,@gw2:aa@bb)
  288. */
  289. while (*argv)
  290. {
  291. if (**argv == '-')
  292. err(EX_USAGE, "dash precedes argument: %s", *argv);
  293. if (strchr(*argv, ',') == NULL || strchr(*argv, '<') != NULL)
  294. args[i++] = *argv;
  295. else
  296. {
  297. len = strlen(*argv) + 3;
  298. if ((args[i] = malloc(len)) == NULL)
  299. err(EX_TEMPFAIL, "Cannot malloc");
  300. snprintf(args[i++], len, "<%s>", *argv);
  301. }
  302. argv++;
  303. }
  304. args[i] = 0;
  305. if (debug)
  306. {
  307. fprintf(stderr, "Sendmail arguments:n");
  308. for (i = 0; args[i]; i++)
  309. fprintf(stderr, "t%sn", args[i]);
  310. }
  311. /*
  312. **  If called with a regular file as standard input, seek to the right
  313. **  position in the file and just exec sendmail.  Could probably skip
  314. **  skip the stat, but it's not unreasonable to believe that a failed
  315. **  seek will cause future reads to fail.
  316. */
  317. if (!fstat(STDIN_FILENO, &sb) && S_ISREG(sb.st_mode))
  318. {
  319. if (lseek(STDIN_FILENO, offset, SEEK_SET) != offset)
  320. err(EX_TEMPFAIL, "stdin seek");
  321. (void) execv(_PATH_SENDMAIL, args);
  322. err(EX_OSERR, "%s", _PATH_SENDMAIL);
  323. }
  324. if (pipe(pdes) < 0)
  325. err(EX_OSERR, NULL);
  326. switch (pid = FORK())
  327. {
  328.   case -1: /* Err. */
  329. err(EX_OSERR, NULL);
  330. /* NOTREACHED */
  331.   case 0: /* Child. */
  332. if (pdes[0] != STDIN_FILENO)
  333. {
  334. (void) dup2(pdes[0], STDIN_FILENO);
  335. (void) close(pdes[0]);
  336. }
  337. (void) close(pdes[1]);
  338. (void) execv(_PATH_SENDMAIL, args);
  339. _exit(127);
  340. /* NOTREACHED */
  341. }
  342. if ((fp = fdopen(pdes[1], "w")) == NULL)
  343. err(EX_OSERR, NULL);
  344. (void) close(pdes[0]);
  345. /* Copy the file down the pipe. */
  346. do
  347. {
  348. (void) fprintf(fp, "%s", lbuf);
  349. } while (fgets(lbuf, sizeof(lbuf), stdin) != NULL);
  350. if (ferror(stdin))
  351. err(EX_TEMPFAIL, "stdin: %s", errstring(errno));
  352. if (fclose(fp))
  353. err(EX_OSERR, NULL);
  354. if ((waitpid(pid, &status, 0)) == -1)
  355. err(EX_OSERR, "%s", _PATH_SENDMAIL);
  356. if (!WIFEXITED(status))
  357. err(EX_OSERR, "%s: did not terminate normally", _PATH_SENDMAIL);
  358. if (WEXITSTATUS(status))
  359. err(status, "%s: terminated with %d (non-zero) status",
  360.     _PATH_SENDMAIL, WEXITSTATUS(status));
  361. exit(EX_OK);
  362. /* NOTREACHED */
  363. return EX_OK;
  364. }
  365. static void
  366. usage()
  367. {
  368. (void) fprintf(stderr, "usage: rmail [-T] [-D domain] user ...n");
  369. exit(EX_USAGE);
  370. }
  371. #ifdef __STDC__
  372. # include <stdarg.h>
  373. #else /* __STDC__ */
  374. # include <varargs.h>
  375. #endif /* __STDC__ */
  376. static void
  377. #ifdef __STDC__
  378. err(int eval, const char *fmt, ...)
  379. #else /* __STDC__ */
  380. err(eval, fmt, va_alist)
  381. int eval;
  382. const char *fmt;
  383. va_dcl
  384. #endif /* __STDC__ */
  385. {
  386. va_list ap;
  387. #if __STDC__
  388. va_start(ap, fmt);
  389. #else /* __STDC__ */
  390. va_start(ap);
  391. #endif /* __STDC__ */
  392. (void) fprintf(stderr, "rmail: ");
  393. (void) vfprintf(stderr, fmt, ap);
  394. va_end(ap);
  395. (void) fprintf(stderr, "n");
  396. exit(eval);
  397. }