/usr.bin/mail/quit.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 494 lines · 373 code · 27 blank · 94 comment · 154 complexity · 3c6158fdedc6963b0dc02a55884b9f3b MD5 · raw file

  1. /*
  2. * Copyright (c) 1980, 1993
  3. * The Regents of the University of California. All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. * 4. Neither the name of the University nor the names of its contributors
  14. * may be used to endorse or promote products derived from this software
  15. * without specific prior written permission.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  18. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20. * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  21. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  23. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  24. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  25. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  26. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  27. * SUCH DAMAGE.
  28. */
  29. #ifndef lint
  30. #if 0
  31. static char sccsid[] = "@(#)quit.c 8.2 (Berkeley) 4/28/95";
  32. #endif
  33. #endif /* not lint */
  34. #include <sys/cdefs.h>
  35. __FBSDID("$FreeBSD$");
  36. #include "rcv.h"
  37. #include <fcntl.h>
  38. #include "extern.h"
  39. /*
  40. * Rcv -- receive mail rationally.
  41. *
  42. * Termination processing.
  43. */
  44. /*
  45. * The "quit" command.
  46. */
  47. int
  48. quitcmd(void)
  49. {
  50. /*
  51. * If we are sourcing, then return 1 so execute() can handle it.
  52. * Otherwise, return -1 to abort command loop.
  53. */
  54. if (sourcing)
  55. return (1);
  56. return (-1);
  57. }
  58. /*
  59. * Save all of the undetermined messages at the top of "mbox"
  60. * Save all untouched messages back in the system mailbox.
  61. * Remove the system mailbox, if none saved there.
  62. */
  63. void
  64. quit(void)
  65. {
  66. int mcount, p, modify, autohold, anystat, holdbit, nohold;
  67. FILE *ibuf, *obuf, *fbuf, *rbuf, *readstat, *abuf;
  68. struct message *mp;
  69. int c, fd;
  70. struct stat minfo;
  71. char *mbox, tempname[PATHSIZE];
  72. /*
  73. * If we are read only, we can't do anything,
  74. * so just return quickly.
  75. */
  76. if (readonly)
  77. return;
  78. /*
  79. * If editing (not reading system mail box), then do the work
  80. * in edstop()
  81. */
  82. if (edit) {
  83. edstop();
  84. return;
  85. }
  86. /*
  87. * See if there any messages to save in mbox. If no, we
  88. * can save copying mbox to /tmp and back.
  89. *
  90. * Check also to see if any files need to be preserved.
  91. * Delete all untouched messages to keep them out of mbox.
  92. * If all the messages are to be preserved, just exit with
  93. * a message.
  94. */
  95. fbuf = Fopen(mailname, "r");
  96. if (fbuf == NULL)
  97. goto newmail;
  98. (void)flock(fileno(fbuf), LOCK_EX);
  99. rbuf = NULL;
  100. if (fstat(fileno(fbuf), &minfo) >= 0 && minfo.st_size > mailsize) {
  101. printf("New mail has arrived.\n");
  102. (void)snprintf(tempname, sizeof(tempname),
  103. "%s/mail.RqXXXXXXXXXX", tmpdir);
  104. if ((fd = mkstemp(tempname)) == -1 ||
  105. (rbuf = Fdopen(fd, "w")) == NULL)
  106. goto newmail;
  107. #ifdef APPEND
  108. (void)fseeko(fbuf, mailsize, SEEK_SET);
  109. while ((c = getc(fbuf)) != EOF)
  110. (void)putc(c, rbuf);
  111. #else
  112. p = minfo.st_size - mailsize;
  113. while (p-- > 0) {
  114. c = getc(fbuf);
  115. if (c == EOF)
  116. goto newmail;
  117. (void)putc(c, rbuf);
  118. }
  119. #endif
  120. (void)Fclose(rbuf);
  121. if ((rbuf = Fopen(tempname, "r")) == NULL)
  122. goto newmail;
  123. (void)rm(tempname);
  124. }
  125. /*
  126. * Adjust the message flags in each message.
  127. */
  128. anystat = 0;
  129. autohold = value("hold") != NULL;
  130. holdbit = autohold ? MPRESERVE : MBOX;
  131. nohold = MBOX|MSAVED|MDELETED|MPRESERVE;
  132. if (value("keepsave") != NULL)
  133. nohold &= ~MSAVED;
  134. for (mp = &message[0]; mp < &message[msgCount]; mp++) {
  135. if (mp->m_flag & MNEW) {
  136. mp->m_flag &= ~MNEW;
  137. mp->m_flag |= MSTATUS;
  138. }
  139. if (mp->m_flag & MSTATUS)
  140. anystat++;
  141. if ((mp->m_flag & MTOUCH) == 0)
  142. mp->m_flag |= MPRESERVE;
  143. if ((mp->m_flag & nohold) == 0)
  144. mp->m_flag |= holdbit;
  145. }
  146. modify = 0;
  147. if (Tflag != NULL) {
  148. if ((readstat = Fopen(Tflag, "w")) == NULL)
  149. Tflag = NULL;
  150. }
  151. for (c = 0, p = 0, mp = &message[0]; mp < &message[msgCount]; mp++) {
  152. if (mp->m_flag & MBOX)
  153. c++;
  154. if (mp->m_flag & MPRESERVE)
  155. p++;
  156. if (mp->m_flag & MODIFY)
  157. modify++;
  158. if (Tflag != NULL && (mp->m_flag & (MREAD|MDELETED)) != 0) {
  159. char *id;
  160. if ((id = hfield("article-id", mp)) != NULL)
  161. fprintf(readstat, "%s\n", id);
  162. }
  163. }
  164. if (Tflag != NULL)
  165. (void)Fclose(readstat);
  166. if (p == msgCount && !modify && !anystat) {
  167. printf("Held %d message%s in %s\n",
  168. p, p == 1 ? "" : "s", mailname);
  169. (void)Fclose(fbuf);
  170. return;
  171. }
  172. if (c == 0) {
  173. if (p != 0) {
  174. writeback(rbuf);
  175. (void)Fclose(fbuf);
  176. return;
  177. }
  178. goto cream;
  179. }
  180. /*
  181. * Create another temporary file and copy user's mbox file
  182. * darin. If there is no mbox, copy nothing.
  183. * If he has specified "append" don't copy his mailbox,
  184. * just copy saveable entries at the end.
  185. */
  186. mbox = expand("&");
  187. mcount = c;
  188. if (value("append") == NULL) {
  189. (void)snprintf(tempname, sizeof(tempname),
  190. "%s/mail.RmXXXXXXXXXX", tmpdir);
  191. if ((fd = mkstemp(tempname)) == -1 ||
  192. (obuf = Fdopen(fd, "w")) == NULL) {
  193. warn("%s", tempname);
  194. (void)Fclose(fbuf);
  195. return;
  196. }
  197. if ((ibuf = Fopen(tempname, "r")) == NULL) {
  198. warn("%s", tempname);
  199. (void)rm(tempname);
  200. (void)Fclose(obuf);
  201. (void)Fclose(fbuf);
  202. return;
  203. }
  204. (void)rm(tempname);
  205. if ((abuf = Fopen(mbox, "r")) != NULL) {
  206. while ((c = getc(abuf)) != EOF)
  207. (void)putc(c, obuf);
  208. (void)Fclose(abuf);
  209. }
  210. if (ferror(obuf)) {
  211. warnx("%s", tempname);
  212. (void)Fclose(ibuf);
  213. (void)Fclose(obuf);
  214. (void)Fclose(fbuf);
  215. return;
  216. }
  217. (void)Fclose(obuf);
  218. (void)close(open(mbox, O_CREAT | O_TRUNC | O_WRONLY, 0600));
  219. if ((obuf = Fopen(mbox, "r+")) == NULL) {
  220. warn("%s", mbox);
  221. (void)Fclose(ibuf);
  222. (void)Fclose(fbuf);
  223. return;
  224. }
  225. }
  226. if (value("append") != NULL) {
  227. if ((obuf = Fopen(mbox, "a")) == NULL) {
  228. warn("%s", mbox);
  229. (void)Fclose(fbuf);
  230. return;
  231. }
  232. (void)fchmod(fileno(obuf), 0600);
  233. }
  234. for (mp = &message[0]; mp < &message[msgCount]; mp++)
  235. if (mp->m_flag & MBOX)
  236. if (sendmessage(mp, obuf, saveignore, NULL) < 0) {
  237. warnx("%s", mbox);
  238. (void)Fclose(ibuf);
  239. (void)Fclose(obuf);
  240. (void)Fclose(fbuf);
  241. return;
  242. }
  243. /*
  244. * Copy the user's old mbox contents back
  245. * to the end of the stuff we just saved.
  246. * If we are appending, this is unnecessary.
  247. */
  248. if (value("append") == NULL) {
  249. rewind(ibuf);
  250. c = getc(ibuf);
  251. while (c != EOF) {
  252. (void)putc(c, obuf);
  253. if (ferror(obuf))
  254. break;
  255. c = getc(ibuf);
  256. }
  257. (void)Fclose(ibuf);
  258. }
  259. (void)fflush(obuf);
  260. trunc(obuf);
  261. if (ferror(obuf)) {
  262. warn("%s", mbox);
  263. (void)Fclose(obuf);
  264. (void)Fclose(fbuf);
  265. return;
  266. }
  267. (void)Fclose(obuf);
  268. if (mcount == 1)
  269. printf("Saved 1 message in mbox\n");
  270. else
  271. printf("Saved %d messages in mbox\n", mcount);
  272. /*
  273. * Now we are ready to copy back preserved files to
  274. * the system mailbox, if any were requested.
  275. */
  276. if (p != 0) {
  277. writeback(rbuf);
  278. (void)Fclose(fbuf);
  279. return;
  280. }
  281. /*
  282. * Finally, remove his /var/mail file.
  283. * If new mail has arrived, copy it back.
  284. */
  285. cream:
  286. if (rbuf != NULL) {
  287. abuf = Fopen(mailname, "r+");
  288. if (abuf == NULL)
  289. goto newmail;
  290. while ((c = getc(rbuf)) != EOF)
  291. (void)putc(c, abuf);
  292. (void)Fclose(rbuf);
  293. trunc(abuf);
  294. (void)Fclose(abuf);
  295. alter(mailname);
  296. (void)Fclose(fbuf);
  297. return;
  298. }
  299. demail();
  300. (void)Fclose(fbuf);
  301. return;
  302. newmail:
  303. printf("Thou hast new mail.\n");
  304. if (fbuf != NULL)
  305. (void)Fclose(fbuf);
  306. }
  307. /*
  308. * Preserve all the appropriate messages back in the system
  309. * mailbox, and print a nice message indicated how many were
  310. * saved. On any error, just return -1. Else return 0.
  311. * Incorporate the any new mail that we found.
  312. */
  313. int
  314. writeback(FILE *res)
  315. {
  316. struct message *mp;
  317. int p, c;
  318. FILE *obuf;
  319. p = 0;
  320. if ((obuf = Fopen(mailname, "r+")) == NULL) {
  321. warn("%s", mailname);
  322. return (-1);
  323. }
  324. #ifndef APPEND
  325. if (res != NULL)
  326. while ((c = getc(res)) != EOF)
  327. (void)putc(c, obuf);
  328. #endif
  329. for (mp = &message[0]; mp < &message[msgCount]; mp++)
  330. if ((mp->m_flag&MPRESERVE)||(mp->m_flag&MTOUCH)==0) {
  331. p++;
  332. if (sendmessage(mp, obuf, NULL, NULL) < 0) {
  333. warnx("%s", mailname);
  334. (void)Fclose(obuf);
  335. return (-1);
  336. }
  337. }
  338. #ifdef APPEND
  339. if (res != NULL)
  340. while ((c = getc(res)) != EOF)
  341. (void)putc(c, obuf);
  342. #endif
  343. (void)fflush(obuf);
  344. trunc(obuf);
  345. if (ferror(obuf)) {
  346. warn("%s", mailname);
  347. (void)Fclose(obuf);
  348. return (-1);
  349. }
  350. if (res != NULL)
  351. (void)Fclose(res);
  352. (void)Fclose(obuf);
  353. alter(mailname);
  354. if (p == 1)
  355. printf("Held 1 message in %s\n", mailname);
  356. else
  357. printf("Held %d messages in %s\n", p, mailname);
  358. return (0);
  359. }
  360. /*
  361. * Terminate an editing session by attempting to write out the user's
  362. * file from the temporary. Save any new stuff appended to the file.
  363. */
  364. void
  365. edstop(void)
  366. {
  367. int gotcha, c;
  368. struct message *mp;
  369. FILE *obuf, *ibuf, *readstat;
  370. struct stat statb;
  371. char tempname[PATHSIZE];
  372. if (readonly)
  373. return;
  374. holdsigs();
  375. if (Tflag != NULL) {
  376. if ((readstat = Fopen(Tflag, "w")) == NULL)
  377. Tflag = NULL;
  378. }
  379. for (mp = &message[0], gotcha = 0; mp < &message[msgCount]; mp++) {
  380. if (mp->m_flag & MNEW) {
  381. mp->m_flag &= ~MNEW;
  382. mp->m_flag |= MSTATUS;
  383. }
  384. if (mp->m_flag & (MODIFY|MDELETED|MSTATUS))
  385. gotcha++;
  386. if (Tflag != NULL && (mp->m_flag & (MREAD|MDELETED)) != 0) {
  387. char *id;
  388. if ((id = hfield("article-id", mp)) != NULL)
  389. fprintf(readstat, "%s\n", id);
  390. }
  391. }
  392. if (Tflag != NULL)
  393. (void)Fclose(readstat);
  394. if (!gotcha || Tflag != NULL)
  395. goto done;
  396. ibuf = NULL;
  397. if (stat(mailname, &statb) >= 0 && statb.st_size > mailsize) {
  398. int fd;
  399. (void)snprintf(tempname, sizeof(tempname),
  400. "%s/mbox.XXXXXXXXXX", tmpdir);
  401. if ((fd = mkstemp(tempname)) == -1 ||
  402. (obuf = Fdopen(fd, "w")) == NULL) {
  403. warn("%s", tempname);
  404. relsesigs();
  405. reset(0);
  406. }
  407. if ((ibuf = Fopen(mailname, "r")) == NULL) {
  408. warn("%s", mailname);
  409. (void)Fclose(obuf);
  410. (void)rm(tempname);
  411. relsesigs();
  412. reset(0);
  413. }
  414. (void)fseeko(ibuf, mailsize, SEEK_SET);
  415. while ((c = getc(ibuf)) != EOF)
  416. (void)putc(c, obuf);
  417. (void)Fclose(ibuf);
  418. (void)Fclose(obuf);
  419. if ((ibuf = Fopen(tempname, "r")) == NULL) {
  420. warn("%s", tempname);
  421. (void)rm(tempname);
  422. relsesigs();
  423. reset(0);
  424. }
  425. (void)rm(tempname);
  426. }
  427. printf("\"%s\" ", mailname);
  428. (void)fflush(stdout);
  429. if ((obuf = Fopen(mailname, "r+")) == NULL) {
  430. warn("%s", mailname);
  431. relsesigs();
  432. reset(0);
  433. }
  434. trunc(obuf);
  435. c = 0;
  436. for (mp = &message[0]; mp < &message[msgCount]; mp++) {
  437. if ((mp->m_flag & MDELETED) != 0)
  438. continue;
  439. c++;
  440. if (sendmessage(mp, obuf, NULL, NULL) < 0) {
  441. warnx("%s", mailname);
  442. relsesigs();
  443. reset(0);
  444. }
  445. }
  446. gotcha = (c == 0 && ibuf == NULL);
  447. if (ibuf != NULL) {
  448. while ((c = getc(ibuf)) != EOF)
  449. (void)putc(c, obuf);
  450. (void)Fclose(ibuf);
  451. }
  452. (void)fflush(obuf);
  453. if (ferror(obuf)) {
  454. warn("%s", mailname);
  455. relsesigs();
  456. reset(0);
  457. }
  458. (void)Fclose(obuf);
  459. if (gotcha) {
  460. (void)rm(mailname);
  461. printf("removed\n");
  462. } else
  463. printf("complete\n");
  464. (void)fflush(stdout);
  465. done:
  466. relsesigs();
  467. }