home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume8 / pcmail / part03 < prev    next >
Text File  |  1989-11-03  |  49KB  |  1,335 lines

  1. Newsgroups: comp.sources.misc
  2. subject: v08i111: pcmail part 03 of 08
  3. From: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  4. Reply-To: markl@oracle.com (Croaker the Physician)
  5.  
  6. Posting-number: Volume 8, Issue 111
  7. Submitted-by: markl@oracle.com (Croaker the Physician)
  8. Archive-name: pcmail/part03
  9.  
  10. #--------------------------------CUT HERE-------------------------------------
  11. #! /bin/sh
  12. #
  13. # This is a shell archive.  Save this into a file, edit it
  14. # and delete all lines above this comment.  Then give this
  15. # file to sh by executing the command "sh file".  The files
  16. # will be extracted into the current directory owned by
  17. # you with default permissions.
  18. #
  19. # The files contained herein are:
  20. #
  21. # -rw-r--r--  1 markl        5212 Oct 30 15:47 nntp.h
  22. # -rw-r--r--  1 markl        8697 Oct 30 15:47 nntp_slave.c
  23. # -rw-rw-r--  1 markl       21473 Nov  1 13:33 pcmail.el
  24. # -rw-rw-r--  1 markl        5839 Oct 30 15:47 pcmaildate.el
  25. # -rw-rw-r--  1 markl        4209 Oct 30 15:47 pcmaildrop.el
  26. #
  27. echo 'x - nntp.h'
  28. if test -f nntp.h; then echo 'shar: not overwriting nntp.h'; else
  29. sed 's/^X//' << '________This_Is_The_END________' > nntp.h
  30. X/*
  31. X GNU-EMACS PCMAIL mail reader support utility
  32. X
  33. X Written by Mark L. Lambert
  34. X Architecture Group, Network Products Division
  35. X Oracle Corporation
  36. X 20 Davis Dr,
  37. X Belmont CA, 94002
  38. X
  39. X internet: markl@oracle.com or markl%oracle.com@apple.com
  40. X UUCP:     {hplabs,uunet,apple}!oracle!markl
  41. X
  42. XCopyright (C) 1989 Mark L. Lambert
  43. X
  44. XThis file is not officially part of GNU Emacs, but is being
  45. Xdonated to the Free Software Foundation.  As such, it is
  46. Xsubject to the standard GNU-Emacs General Public License,
  47. Xreferred to below.
  48. X
  49. XGNU Emacs is distributed in the hope that it will be useful,
  50. Xbut WITHOUT ANY WARRANTY.  No author or distributor
  51. Xaccepts responsibility to anyone for the consequences of using it
  52. Xor for whether it serves any particular purpose or works at all,
  53. Xunless he says so in writing.  Refer to the GNU Emacs General Public
  54. XLicense for full details.
  55. X
  56. XEveryone is granted permission to copy, modify and redistribute
  57. XGNU Emacs, but only under the conditions described in the
  58. XGNU Emacs General Public License.   A copy of this license is
  59. Xsupposed to have been given to you along with GNU Emacs so you
  60. Xcan know your rights and responsibilities.  It should be in a
  61. Xfile named COPYING.  Among other things, the copyright notice
  62. Xand this notice must be preserved on all copies.
  63. X*/
  64. X
  65. X/*
  66. X * Response codes for NNTP server
  67. X *
  68. X * @(#)response_codes.h 1.6     (Berkeley) 2/6/86
  69. X *
  70. X * First digit:
  71. X *
  72. X *      1xx     Informative message
  73. X *      2xx     Command ok
  74. X *      3xx     Command ok so far, continue
  75. X *      4xx     Command was correct, but couldn't be performed
  76. X *              for some specified reason.
  77. X *      5xx     Command unimplemented, incorrect, or a
  78. X *              program error has occured.
  79. X *
  80. X * Second digit:
  81. X *
  82. X *      x0x     Connection, setup, miscellaneous
  83. X *      x1x     Newsgroup selection
  84. X *      x2x     Article selection
  85. X *      x3x     Distribution
  86. X *      x4x     Posting
  87. X */
  88. X
  89. X#define CHAR_INF        '1'
  90. X#define CHAR_OK         '2'
  91. X#define CHAR_CONT       '3'
  92. X#define CHAR_ERR        '4'
  93. X#define CHAR_FATAL      '5'
  94. X
  95. X#define INF_HELP        100     /* Help text on way */
  96. X#define INF_DEBUG       199     /* Debug output */
  97. X
  98. X#define OK_CANPOST      200     /* Hello; you can post */
  99. X#define OK_NOPOST       201     /* Hello; you can't post */
  100. X#define OK_SLAVE        202     /* Slave status noted */
  101. X#define OK_GOODBYE      205     /* Closing connection */
  102. X#define OK_GROUP        211     /* Group selected */
  103. X#define OK_GROUPS       215     /* Newsgroups follow */
  104. X#define OK_ARTICLE      220     /* Article (head & body) follows */
  105. X#define OK_HEAD         221     /* Head follows */
  106. X#define OK_BODY         222     /* Body follows */
  107. X#define OK_NOTEXT       223     /* No text sent -- stat, next, last */
  108. X#define OK_NEWNEWS      230     /* New articles by message-id follow */
  109. X#define OK_NEWGROUPS    231     /* New newsgroups follow */
  110. X#define OK_XFERED       235     /* Article transferred successfully */
  111. X#define OK_POSTED       240     /* Article posted successfully */
  112. X
  113. X#define CONT_XFER       335     /* Continue to send article */
  114. X#define CONT_POST       340     /* Continue to post article */
  115. X
  116. X#define ERR_GOODBYE     400     /* Have to hang up for some reason */
  117. X#define ERR_NOGROUP     411     /* No such newsgroup */
  118. X#define ERR_NCING       412     /* Not currently in newsgroup */
  119. X#define ERR_NOCRNT      420     /* No current article selected */
  120. X#define ERR_NONEXT      421     /* No next article in this group */
  121. X#define ERR_NOPREV      422     /* No previous article in this group */
  122. X#define ERR_NOARTIG     423     /* No such article in this group */
  123. X#define ERR_NOART       430     /* No such article at all */
  124. X#define ERR_GOTIT       435     /* Already got that article, don't send */
  125. X#define ERR_XFERFAIL    436     /* Transfer failed */
  126. X#define ERR_XFERRJCT    437     /* Article rejected, don't resend */
  127. X#define ERR_NOPOST      440     /* Posting not allowed */
  128. X#define ERR_POSTFAIL    441     /* Posting failed */
  129. X
  130. X#define ERR_COMMAND     500     /* Command not recognized */
  131. X#define ERR_CMDSYN      501     /* Command syntax error */
  132. X#define ERR_ACCESS      502     /* Access to server denied */
  133. X#define ERR_FAULT       503     /* Program fault, command not performed */
  134. X
  135. X/* nntp program interface error codes */
  136. X#define NN_ERR_OS_RANGE 2
  137. X#define NN_ERR_NOERR    0
  138. X#define NN_ERR_IO       1
  139. X#define NN_ERR_SKT      2
  140. X#define NN_ERR_CONN     3
  141. X#define NN_ERR_NOSVC    4
  142. X#define NN_ERR_NOHOST   5
  143. X#define NN_ERR_RESET    6
  144. X#define NN_ERR_PROTO    7
  145. X
  146. Xint nntp_out(), nntp_open_connection(), nntp_list_end_p(), 
  147. X    nntp_in(), nntp_command();
  148. Xvoid nntp_close();
  149. Xchar *nntp_errstring();
  150. X
  151. X#define TRUE 1
  152. X#define FALSE (!TRUE)
  153. X#define OK 0
  154. X#define ERROR (-1)
  155. X
  156. X#define nntp_current_reply(nnp) ((nnp)->nn_reply)
  157. X#define nntp_current_reply_code(nnp) ((nnp)->nn_reply_code)
  158. X#define nntp_end_list(nnp) (nntp_out((nnp), "."))
  159. X#define nntp_errno(nnp) ((nnp)->nn_error)
  160. X#define nntp_os_errorp(nnp) (nntp_errno((nnp)) <= NN_ERR_OS_RANGE)
  161. X
  162. Xtypedef struct {
  163. X    char nn_inbuf[512];
  164. X    char *nn_old_data_begin;
  165. X    char *nn_new_data_begin;
  166. X    char nn_reply[512];
  167. X    char nn_outbuf[512];
  168. X    int nn_reply_code;
  169. X    int nn_skt;
  170. X    int nn_error;
  171. X    int nn_nbytes;
  172. X} Nntp_stream;
  173. ________This_Is_The_END________
  174. if test `wc -c < nntp.h` -ne 5212; then
  175.     echo 'shar: nntp.h was damaged during transit (should have been 5212 bytes)'
  176. fi
  177. fi        ; : end of overwriting check
  178. echo 'x - nntp_slave.c'
  179. if test -f nntp_slave.c; then echo 'shar: not overwriting nntp_slave.c'; else
  180. sed 's/^X//' << '________This_Is_The_END________' > nntp_slave.c
  181. X/*
  182. X GNU-EMACS PCMAIL mail reader support utility
  183. X
  184. X Written by Mark L. Lambert
  185. X Architecture Group, Network Products Division
  186. X Oracle Corporation
  187. X 20 Davis Dr,
  188. X Belmont CA, 94002
  189. X
  190. X internet: markl@oracle.com or markl%oracle.com@apple.com
  191. X UUCP:     {hplabs,uunet,apple}!oracle!markl
  192. X
  193. XCopyright (C) 1989 Mark L. Lambert
  194. X
  195. XThis file is not officially part of GNU Emacs, but is being
  196. Xdonated to the Free Software Foundation.  As such, it is
  197. Xsubject to the standard GNU-Emacs General Public License,
  198. Xreferred to below.
  199. X
  200. XGNU Emacs is distributed in the hope that it will be useful,
  201. Xbut WITHOUT ANY WARRANTY.  No author or distributor
  202. Xaccepts responsibility to anyone for the consequences of using it
  203. Xor for whether it serves any particular purpose or works at all,
  204. Xunless he says so in writing.  Refer to the GNU Emacs General Public
  205. XLicense for full details.
  206. X
  207. XEveryone is granted permission to copy, modify and redistribute
  208. XGNU Emacs, but only under the conditions described in the
  209. XGNU Emacs General Public License.   A copy of this license is
  210. Xsupposed to have been given to you along with GNU Emacs so you
  211. Xcan know your rights and responsibilities.  It should be in a
  212. Xfile named COPYING.  Among other things, the copyright notice
  213. Xand this notice must be preserved on all copies.
  214. X
  215. Xnntp_slave.  A very simple and primitive NNTP client.  Called as:
  216. X
  217. X    nntp_slave <server> <newsgroup name> <output file> <control file>
  218. X
  219. XThe program connects to SERVER and retrieves into OUTPUT-FILE all messages
  220. Xin NEWSGROUP-NAME with article numbers greater than the article number in
  221. XCONTROL-FILE.  The messages are separated by the delimiting sequence
  222. XSLV_ART_DELIM, #defined below.
  223. X
  224. XEventually, this should probably be replaced with Emacs-Lisp NNTP code.  
  225. XThis stuff just happened to be already lying around...
  226. X*/
  227. X
  228. X#include <stdio.h>
  229. X#include "nntp.h"
  230. X#include <errno.h>
  231. X
  232. X#define SLV_ART_DELIM "\014\n"
  233. X#define SLV_M_NAME 50
  234. X#define SLV_M_PATH 256
  235. X#define SLV_M_BUF 512
  236. X#define MAX(x, y) ((x) > (y) ? (x) : (y))
  237. X
  238. Xvoid slv_err_report(), slv_osd_bboard();
  239. Xchar *strerror();
  240. X
  241. Xvoid main(argc, argv)
  242. X
  243. Xint argc;
  244. Xchar *argv[];
  245. X{
  246. X  char server[SLV_M_NAME], bbname[SLV_M_NAME], ctlname[SLV_M_PATH],
  247. X       outfile[SLV_M_PATH];
  248. X  int slv_cmdline(), slv_new_articles(), ret;
  249. X  Nntp_stream nnp;
  250. X
  251. X  if(slv_cmdline(argc, argv, server, bbname, outfile, ctlname) == ERROR)
  252. X    exit(1);
  253. X  if(nntp_open_connection(server, &nnp) == ERROR)
  254. X  {
  255. X    slv_err_report(&nnp);
  256. X    exit(1);
  257. X  }
  258. X  ret = slv_new_articles(&nnp, bbname, outfile, ctlname);
  259. X  nntp_close(&nnp);
  260. X  (ret == ERROR) ? exit(1) : exit(0);
  261. X}
  262. X
  263. Xint slv_cmdline(argc, argv, server, bbname, outfile, ctlname)
  264. X
  265. Xint argc;
  266. Xchar *argv[];
  267. Xchar *server;
  268. Xchar *bbname;
  269. Xchar *outfile;
  270. Xchar *ctlname;
  271. X{
  272. X  if(argc != 5) 
  273. X  {
  274. X    printf("nntp-slave: usage is nntp_slave <server-name> <newsgroup-name> <outfile> <controlfile>\n");
  275. X    return(ERROR);
  276. X  }
  277. X  strncpy(server, argv[1], SLV_M_NAME);
  278. X  strncpy(bbname, argv[2], SLV_M_NAME);
  279. X  strncpy(outfile, argv[3], SLV_M_PATH);
  280. X  strncpy(ctlname, argv[4], SLV_M_PATH);
  281. X  return(OK);
  282. X}
  283. X
  284. Xint slv_new_articles(nnp, bbname, outfile, ctl_path)
  285. X
  286. XNntp_stream *nnp;
  287. Xchar *bbname;
  288. Xchar *outfile;
  289. Xchar *ctl_path;
  290. X{
  291. X  char ctlinfo[SLV_M_BUF], ctlbboard[SLV_M_NAME], 
  292. X       cmdbuf[SLV_M_BUF], junk2[SLV_M_NAME], ctl_path_new[SLV_M_PATH];
  293. X  int slv_deliver(), ctllast = 0, ret, bb_first, bb_last, junk, newlast,
  294. X      slv_open_ctl_outfile();
  295. X  FILE *fin = NULL, *fout = NULL;
  296. X
  297. X  /* open control file, read all information, write out all but desired 
  298. X     bboard, store desired bboard information (last article read) */
  299. X
  300. X  (void) sprintf(ctl_path_new, "%snew", ctl_path);
  301. X  fin = fopen(ctl_path, "r");
  302. X  if(slv_open_ctl_outfile(ctl_path_new, &fout) == ERROR)
  303. X    goto EndComm;
  304. X  if(fin)
  305. X  {
  306. X    while(fgets(ctlinfo, sizeof(ctlinfo), fin))
  307. X    {
  308. X      if(sscanf(ctlinfo, "%s %d", ctlbboard, &junk) != 2)
  309. X      {
  310. X    printf("nntp-slave: Illegal format in newsgroup control file\n");
  311. X    goto EndComm;
  312. X      }
  313. X      if(strcmp(ctlbboard, bbname) != 0)
  314. X      {
  315. X        fputs(ctlinfo, fout);
  316. X    if(ferror(fout))
  317. X    {
  318. X      printf("nntp-slave: Newsgroup control file write error (%s)\n", 
  319. X         strerror(errno));
  320. X      goto EndComm;
  321. X    }
  322. X      }
  323. X      else
  324. X        ctllast = junk;
  325. X    }
  326. X    if(fclose(fin) == ERROR)
  327. X    {
  328. X      printf("nntp-slave: Newsgroup control file close error (%s)\n", 
  329. X         strerror(errno));
  330. X      fin = NULL;
  331. X      goto EndComm;
  332. X    }
  333. X  }
  334. X  /* if newsgroup is already subscribed to, ctllast is last article number 
  335. X     read, otherwise it is zero.  Set group to desired bboard and read 
  336. X     information.  If group exists, set target article count to be max 
  337. X     articles on group, and set start article count to be 
  338. X     MAX(ctllast, group-first).  Get articles, update control file, and bung 
  339. X     out */
  340. X  (void) sprintf(cmdbuf, "group %s", bbname);
  341. X  if((ret = nntp_command(nnp, cmdbuf)) == ERROR)
  342. X  {
  343. X    slv_err_report(nnp);
  344. X    goto EndComm;
  345. X  }
  346. X  else if(ret == 0)
  347. X  {
  348. X    if(nntp_current_reply_code(nnp) == ERR_NOGROUP)
  349. X      printf("nntp-slave: No newsgroup named \"%s\"\n", bbname);
  350. X    else
  351. X      printf("nntp-slave: Unexpected response \"%s\"", 
  352. X         nntp_current_reply(nnp));
  353. X    goto EndComm;
  354. X  }
  355. X  if(sscanf(nntp_current_reply(nnp), "%d %d %d %d %s", &junk, &junk, 
  356. X        &bb_first, &bb_last, junk2) != 5)
  357. X  {
  358. X    printf("nntp-slave: Protocol error in GROUP reply \"%s\"\n", 
  359. X       nntp_current_reply(nnp));
  360. X    goto EndComm;
  361. X  }
  362. X
  363. X  /* figure the first article to read: if we've never seen this bboard,
  364. X     start with article 1 or 20 less than the limit, whatever is greater.
  365. X     Otherwise start with the first article the server knows about or
  366. X     the control file's last article, whatever is greater */
  367. X  if(ctllast == 0) ctllast = MAX(1, bb_last - 20);
  368. X  else ctllast = MAX(ctllast, bb_first);
  369. X
  370. X  ret = slv_deliver(nnp, bbname, ctllast, bb_last, &newlast, outfile);
  371. X  (void) fprintf(fout, "%s %d\n", bbname, newlast);
  372. X  if(ferror(fout))
  373. X  {
  374. X    printf("nntp-slave: Newsgroup control file write error (%s)\n", 
  375. X       strerror(errno));
  376. X    goto EndComm;
  377. X  }
  378. X  if(fclose(fout) == ERROR)
  379. X  {
  380. X    printf("nntp-slave: Newsgroup control file close error (%s)\n", 
  381. X       strerror(errno));
  382. X    fout = NULL;
  383. X    goto EndComm;
  384. X  }
  385. X  if(rename(ctl_path_new, ctl_path) == ERROR)
  386. X  {
  387. X    printf("nntp-slave: Newsgroup control file rename error (%s)\n", 
  388. X       strerror(errno));
  389. X    goto EndComm;
  390. X  }    
  391. X  return(ret);
  392. X
  393. X EndComm:
  394. X  if(fout) (void) fclose(fout);
  395. X  if(fin) (void) fclose(fin);
  396. X  return(ERROR);
  397. X}
  398. X
  399. Xint slv_deliver(nnp, bbname, first, last, newlast, inbox_path)
  400. X
  401. XNntp_stream *nnp;
  402. Xchar *bbname;
  403. Xint first, last, *newlast;
  404. Xchar *inbox_path;
  405. X{
  406. X  FILE *fout = NULL;
  407. X  char cmdbuf[SLV_M_BUF];
  408. X  int ret;
  409. X
  410. X  if(! (fout = fopen(inbox_path, "w")))
  411. X  {
  412. X    printf("nntp-slave: %s open error (%s)\n", inbox_path, strerror(errno));
  413. X    goto EndComm;
  414. X  }
  415. X  for(*newlast = first; *newlast <= last; ++(*newlast))
  416. X  {
  417. X    (void) sprintf(cmdbuf, "article %d", *newlast);
  418. X    if((ret = nntp_command(nnp, cmdbuf)) == ERROR)
  419. X    {
  420. X      slv_err_report(nnp);
  421. X      goto EndComm;
  422. X    }
  423. X    else if(nntp_current_reply_code(nnp) == ERR_NOARTIG ||
  424. X        nntp_current_reply_code(nnp) == ERR_NOART) 
  425. X      continue;                                     /* skip missing articles */
  426. X    else if(nntp_current_reply_code(nnp) != OK_ARTICLE) 
  427. X    {
  428. X      printf("nntp-slave: Unexpected response \"%s\"", 
  429. X         nntp_current_reply(nnp));
  430. X      goto EndComm;
  431. X    }
  432. X    (void) fputs(SLV_ART_DELIM, fout);
  433. X    if(ferror(fout))
  434. X    {
  435. X      printf("nntp-slave: Inbox file write error (%s)\n", strerror(errno));
  436. X      goto EndComm;
  437. X    }
  438. X    while((ret = nntp_list_end_p(nnp)) == 0)
  439. X    {
  440. X      (void) fprintf(fout, "%s\n", nntp_current_reply(nnp));
  441. X      if(ferror(fout))
  442. X      {
  443. X    printf("nntp_slave: Inbox file write error (%s)\n", strerror(errno));
  444. X    goto EndComm;
  445. X      }
  446. X    }
  447. X    if(ret == ERROR)
  448. X    {
  449. X      slv_err_report(nnp);
  450. X      goto EndComm;
  451. X    }
  452. X  }
  453. X  if(fclose(fout) == ERROR)
  454. X  {
  455. X    fout = NULL;
  456. X    printf("nntp_slave: Error closing inbox file (%s)\n", strerror(errno));
  457. X    goto EndComm;
  458. X  }
  459. X  return(OK);
  460. X
  461. X EndComm:
  462. X  if(fout) (void) fclose(fout);
  463. X  return(ERROR);
  464. X}
  465. X
  466. Xvoid slv_err_report(nnp)
  467. Xregister Nntp_stream *nnp;
  468. X{
  469. X  printf("nntp-slave: NNTP error (%s)\n", nntp_errstring(nnp));
  470. X  if(nntp_os_errorp(nnp)) 
  471. X    printf("nntp-slave: OS error %d (%s)\n", errno, strerror(errno));
  472. X}
  473. X
  474. Xint slv_open_ctl_outfile(ctl_path, fout) 
  475. X
  476. Xchar *ctl_path;
  477. XFILE **fout;
  478. X{
  479. X  if(! (*fout = fopen(ctl_path, "w")))
  480. X  {
  481. X    printf("nntp-slave: Newsgroup control file open error (%s)\n", 
  482. X       strerror(errno));
  483. X    return(ERROR);
  484. X  }
  485. X  return(OK);
  486. X}
  487. X
  488. X/* system-dependent stuff * follows */
  489. X
  490. Xextern char *sys_errlist[];
  491. X
  492. Xchar *strerror(n)
  493. Xint n;
  494. X{
  495. X  return(sys_errlist[errno]);
  496. X}
  497. ________This_Is_The_END________
  498. if test `wc -c < nntp_slave.c` -ne 8697; then
  499.     echo 'shar: nntp_slave.c was damaged during transit (should have been 8697 bytes)'
  500. fi
  501. fi        ; : end of overwriting check
  502. echo 'x - pcmail.el'
  503. if test -f pcmail.el; then echo 'shar: not overwriting pcmail.el'; else
  504. sed 's/^X//' << '________This_Is_The_END________' > pcmail.el
  505. X;;;; GNU-EMACS PCMAIL mail reader
  506. X
  507. X;;  Written by Mark L. Lambert
  508. X;;  Architecture Group, Network Products Division
  509. X;;  Oracle Corporation
  510. X;;  20 Davis Dr,
  511. X;;  Belmont CA, 94002
  512. X;;
  513. X;;  internet: markl@oracle.com or markl%oracle.com@apple.com
  514. X;;  UUCP:     {hplabs,uunet,apple}!oracle!markl
  515. X
  516. X;; Copyright (C) 1989 Mark L. Lambert
  517. X
  518. X;; This file is not officially part of GNU Emacs, but is being
  519. X;; donated to the Free Software Foundation.  As such, it is
  520. X;; subject to the standard GNU-Emacs General Public License,
  521. X;; referred to below.
  522. X
  523. X;; GNU Emacs is distributed in the hope that it will be useful,
  524. X;; but WITHOUT ANY WARRANTY.  No author or distributor
  525. X;; accepts responsibility to anyone for the consequences of using it
  526. X;; or for whether it serves any particular purpose or works at all,
  527. X;; unless he says so in writing.  Refer to the GNU Emacs General Public
  528. X;; License for full details.
  529. X
  530. X;; Everyone is granted permission to copy, modify and redistribute
  531. X;; GNU Emacs, but only under the conditions described in the
  532. X;; GNU Emacs General Public License.   A copy of this license is
  533. X;; supposed to have been given to you along with GNU Emacs so you
  534. X;; can know your rights and responsibilities.  It should be in a
  535. X;; file named COPYING.  Among other things, the copyright notice
  536. X;; and this notice must be preserved on all copies.
  537. X
  538. X;;;; required pcmail elisp files.  Order is significant.
  539. X
  540. X(require 'pcmailsysdep)
  541. X(require 'pcmailbabyl)
  542. X(require 'pcmaildrop)
  543. X(require 'pcmailfolder)
  544. X(require 'pcmaillist)
  545. X(require 'pcmailattr)
  546. X(require 'pcmailmove)
  547. X(require 'pcmaildate)
  548. X(require 'pcmailsub)
  549. X(require 'mail-utils)
  550. X
  551. X;;;; global variables
  552. X
  553. X;;; system-defined variables
  554. X
  555. X(defconst pcmail-version "4.0"
  556. X  "Mail reader version.")
  557. X
  558. X(defvar pcmail-directory (get 'pcmail-mail-environment 'mail-directory)
  559. X  "The directory in which all folders are stored.")
  560. X
  561. X(defvar pcmail-time-zone (get 'pcmail-mail-environment 'time-zone)
  562. X  "The local time zone, in three character format, i.e. \"PST\".")
  563. X
  564. X;;; user-defined config parameters
  565. X  
  566. X(defvar pcmail-nntp-host-name "newshost"
  567. X  "*The name of your local NNTP server.  Only interesting if you are using
  568. XThe nntp-mail-drop or nntp-file-mail-drop mail drop types, in which case it 
  569. Xmust be defined.")
  570. X
  571. X(defvar pcmail-expiration-hook
  572. X  '(lambda (n) (pcmail-set-attribute n "deleted" t))
  573. X  "*A hook expression that is applied to messages with the \"timely\"
  574. Xattribute when current date is later than message's \"expires:\" field.")
  575. X
  576. X(defvar pcmail-progress-interval 10
  577. X  "*When performing time-intensive tasks like message counting or filtering,
  578. Xa progress message is displayed every pcmail-progress-interval messages, with
  579. Xthe total number of messages processed displayed upon completion of the task.")
  580. X
  581. X(defvar pcmail-uninteresting-fields-list
  582. X  '("via" "mail-from" "origin" "status" "received" "message-id" "expires"
  583. X      "resent-message-id" "summary-line" "return-path" "priority")
  584. X  "*Non-nil means prune from the message header all fields in this list.
  585. XView the unpruned header with the \\[pcmail-toggle-message-header] command.")
  586. X
  587. X(defvar pcmail-wastebasket-folder "wastebasket"
  588. X  "*The wastebasket folder name.  The wastebasket folder is a useful place 
  589. Xto copy messages that aren't really wanted anymore.  
  590. XIf pcmail-wastebasket-on-expunge is non-NIL, expunged messages are placed
  591. Xhere before removal from their folder.")
  592. X
  593. X(defvar pcmail-wastebasket-on-expunge nil
  594. X  "*Non-nil means copy deleted messages to the wastebasket before expunging.
  595. XThis can be very time-consuming.")
  596. X
  597. X(defvar pcmail-expunge-on-save t
  598. X  "*Non-nil means expunge folders before saving them.")
  599. X
  600. X(defvar pcmail-save-on-quit t
  601. X  "*Non-nil means save all folders upon exit from the mail reader.")
  602. X
  603. X(defvar pcmail-delete-on-archive nil
  604. X  "*Non-nil means automatically delete a message that is archived to a file.")
  605. X
  606. X(defvar pcmail-delete-on-copy nil
  607. X  "*Non-nil means automatically delete a message that is copied to another 
  608. Xfolder.")
  609. X
  610. X(defvar pcmail-delete-on-print nil
  611. X  "*Non-nil means automatically delete a message that is sent to a printer.")
  612. X
  613. X(defvar pcmail-printer-name (get 'pcmail-mail-environment 'printer)
  614. X  "*The printer that the \\[pcmail-print-message] command sends messages to.")
  615. X
  616. X(defvar pcmail-pigeonhole-hook nil
  617. X  "*If non-NIL, a hook expression applied to each new message in a mail drop.
  618. XThe hook expression is passed the new message's absolute message number.")
  619. X
  620. X(defvar pcmail-interesting-hook 
  621. X  '(lambda (n) (and (not (pcmail-has-attribute-p n "deleted"))
  622. X            (< (pcmail-message-priority n) 5)))
  623. X  "*If non-NIL, a lambda expression which is applied to a message number.  
  624. XIf the expression returns non-NIL, the message is interesting, otherwise it
  625. Xis not.")
  626. X
  627. X(defvar pcmail-yank-message-on-reply nil
  628. X  "*If non-NIL, the \\[pcmail-answer-message\\] command will automatically
  629. Xinsert a copy of the replied-to message in the message reply.")
  630. X
  631. X(defvar pcmail-yank-prefix nil
  632. X  "*If a string, any message inserted into the message composition buffer
  633. Xwill have that string placed at the beginning of each non-blank line.")
  634. X
  635. X(defvar pcmail-highlight-forwarded-message nil
  636. X  "*Non-NIL means place a \"begin forwarded message\" line before the 
  637. Xforwarded message and a \"end forwarded message\" line after it.  Messages 
  638. Xare forwarded using the \\[pcmail-forward-message\\] command.")
  639. X
  640. X(defvar pcmail-default-filter-name "all"
  641. X  "*Name of the filter to be used when you first enter a folder.
  642. XDefault value is the filter named \"all\", which contains all messages
  643. Xin the folder.")
  644. X
  645. X(defvar pcmail-summary-format "%d  %25f  %s"
  646. X  "*The format string used to format summary lines.  
  647. XThe following percent-constructs are recognized:
  648. X
  649. X   %b:  replace with the contents of the bcc: field
  650. X   %c:  replace with the contents of the cc: field
  651. X   %C:  replace with the message's character count
  652. X   %d:  replace with the contents of the date: field, dd-mon-yy
  653. X   %f:  replace with the contents of the from: field
  654. X   %l:  replace with the message's line count
  655. X   %m:  replace with the contents of the message-id: field
  656. X   %s:  replace with the contents of the subject: field
  657. X   %t:  replace with the contents of the to: field
  658. X
  659. XAll directive modifications (field width, justification, etc) are recognized 
  660. Xand work as the emacs-lisp format function.
  661. XDefault value of pcmail-summary-format places date, followed by from and 
  662. Xsubject fields, in a summary line.")
  663. X
  664. X(defvar pcmail-date-format "%d-%m-%y"
  665. X  "*The format string used to format dates.  
  666. XThe following percent-constructs are recognized:
  667. X
  668. X   %d:  replace with the day of the month
  669. X   %n:  replace with the number of the month
  670. X   %m:  replace with the first three letters of the month
  671. X   %M:  replace with the full name of the month
  672. X   %y:  replace with the last two digits of the year
  673. X   %Y:  replace with the full year
  674. X
  675. XAll directive modifications (field width, justification, etc) are recognized 
  676. Xand work as the emacs-lisp format function.
  677. XDefault value of pcmail-date-format is \"%d-%m-%y\", which creates a
  678. Xdate of the form dd-mmm-yy.")
  679. X
  680. X(defvar pcmail-folder-mode-line-format 
  681. X  "Folder: %-18f (%eMessage %s/%S%n: %a) %p"
  682. X  "*The format string used to format a folder's mode line.
  683. XThe following percent-constructs are recognized:
  684. X
  685. X   %a:  replace with the current message's attribute list, or \"[none]\",
  686. X        if the message has no attributes
  687. X   %c:  replace with the current message's character count
  688. X   %e:  if current message is being edited, replace with \"Editing\"
  689. X   %E:  if current message is timely, replace with expiration date
  690. X   %f:  replace with the current folder name
  691. X   %l:  replace with the current message's line count
  692. X   %n:  if the current subset does not comprise the entire folder, or the
  693. X        current message's number os not the same as its absolute number,
  694. X        replace with the message's absolute number and the total number of
  695. X        messages in the folder in the form \"[<curr>/<total>]\"
  696. X   %p:  replace with the current message's priority if the priority
  697. X        number is greater than 1.
  698. X   %s:  replace with the current message's number
  699. X   %S:  replace with the number of messages in the current subset
  700. X
  701. XAll directive modifications (field width, justification, etc) are recognized 
  702. Xand work as the emacs-lisp format function.")
  703. X
  704. X(defvar pcmail-resummarize-folder-on-change nil
  705. X  "*If non-NIL, resummarize a folder with an existing summary every time
  706. Xthe folder changes.  Changes are defined as a change in the number of messages
  707. Xin the folder or a change in their order.  Default value is NIL.")
  708. X
  709. X;;;; mail reader entry point
  710. X
  711. X(defun pcmail (&optional no-hooks) 
  712. X  "Read and edit mail using the Pcmail mail reader.
  713. X
  714. XPcmail operates on Babyl-format mail files.  Pcmail (as does RMAIL)
  715. Xtreats the \"unseen\" label as a Babyl-defined attribute rather than
  716. Xthe user-defined attribute it should be.  Pcmail conforms to the Babyl
  717. Xspecification in all other respects.
  718. X
  719. XThere are a number of configuration variables that you can set to
  720. Xcustomize the mail reader.  A list of them follows this documentation.
  721. XUse a lambda-expression set to \"pcmail-hook\" in order to set these
  722. Xvariables upon entry into the mail reader.  Type \\[describe-mode]
  723. Xafter the mail reader has started; this will get you a list of mode
  724. Xcommands.  Typing \\[describe-function] with one of the function names
  725. Xlisted in the mode documentation will give more detailed documentation
  726. Xon what the particular function does.
  727. X
  728. XFollowing is a list of user-settable configuration variables.  Type
  729. X \\[describe-variable] to get a particular variable's description.
  730. X
  731. Xpcmail-expunge-on-save        pcmail-yank-original-on-reply
  732. Xpcmail-delete-on-archive        pcmail-delete-on-copy 
  733. Xpcmail-delete-on-print         pcmail-pigeonhole-hook
  734. Xpcmail-printer-name        pcmail-highlight-forwarded-message
  735. Xpcmail-wastebasket-folder    pcmail-yank-prefix
  736. Xpcmail-default-filter-name      pcmail-uninteresting-fields-list
  737. Xpcmail-progess-interval         pcmail-interesting-hook
  738. Xpcmail-expiration-hook        pcmail-wastebasket-on-expunge
  739. Xpcmail-date-format              pcmail-summary-format
  740. Xpcmail-nntp-host-name
  741. X
  742. Xmail-header-separator        rmail-dont-reply-to-names
  743. Xmail-use-rfc822            mail-aliases
  744. Xmail-yank-ignored-headers    mail-self-blind
  745. Xmail-default-reply-to           mail-archive-file-name
  746. Xmail-setup-hook
  747. X
  748. XTyping \\[pcmail] causes the hook variable \"pcmail-hook\" to
  749. Xbe evaluated unless a prefix argument has been supplied.  The hook 
  750. Xvariable \"pcmail-exit-hook\" is evaluated upon exit from the mail reader 
  751. Xvia the \\[pcmail-quit] command."
  752. X  (interactive "P")  
  753. X  (or no-hooks (run-hooks 'pcmail-hook))
  754. X  (pcmail-maybe-init)
  755. X  (pcmail-get-mail pcmail-primary-folder-name))
  756. X
  757. X;;; maybe create mail directory, folder list, and primary folder.
  758. X(defun pcmail-maybe-init ()
  759. X  "Create mail directory and primary folder as necessary.
  760. XArgs: none"
  761. X  (and (get 'pcmail-mail-environment 'send-mail-function)
  762. X       (setq send-mail-function 
  763. X         (get 'pcmail-mail-environment 'send-mail-function)))
  764. X  (cond ((not (file-directory-p pcmail-directory))
  765. X     (or (yes-or-no-p 
  766. X          (format "Pcmail mail directory \"%s\" does not exist.  Create? "
  767. X              pcmail-directory))
  768. X       (error "Aborted."))
  769. X     (funcall (get 'pcmail-mail-environment 'create-mail-directory-fn))
  770. X     (pcmail-create-folder-list-file)))
  771. X  (pcmail-load-folder-information)
  772. X  (cond ((not (pcmail-find-folder pcmail-primary-folder-name))
  773. X     (or (yes-or-no-p 
  774. X          (format "Pcmail primary folder \"%s\" not found.  Create? "
  775. X              pcmail-primary-folder-name))
  776. X         (error "Aborted."))
  777. X     (pcmail-create-folder pcmail-primary-folder-name
  778. X                   (get 'pcmail-mail-environment 
  779. X                    'default-mail-drop-list)))))
  780. X
  781. X;;; mail reader exit point
  782. X
  783. X(defun pcmail-quit (no-hooks)
  784. X  "Exit the mail reader.  
  785. XArgs: none.
  786. X  Exit the mail reader in an orderly manner.  If pcmail-save-on-quit is 
  787. Xnon-NIL, save all folders first.  Evaluate the hook variable 
  788. Xpcmail-exit-hook unless a prefix argument was supplied."
  789. X  (interactive "P")
  790. X  (let ((cb (current-buffer)))
  791. X
  792. X    ; if the wastebasket exists, open it up so its messages get counted,
  793. X    ; expired, and expunged correctly in the following save code
  794. X    (and (pcmail-find-folder pcmail-wastebasket-folder)
  795. X     (save-excursion
  796. X       (pcmail-open-folder pcmail-wastebasket-folder)))
  797. X    (and pcmail-save-on-quit
  798. X     (mapcar
  799. X      '(lambda (m)
  800. X         (cond ((and (pcmail-folder-buffer-name m)
  801. X             (get-buffer (pcmail-folder-buffer-name m)))
  802. X            (pcmail-save-folder m)
  803. X            (bury-buffer (pcmail-folder-buffer-name m)))))
  804. X      (pcmail-all-folders)))
  805. X    (let ((nmsgs))
  806. X      (and (pcmail-find-folder pcmail-wastebasket-folder)
  807. X       (> (setq nmsgs (pcmail-nmessages pcmail-wastebasket-folder)) 0)
  808. X       (progn (message "%d message%s in the wastebasket"
  809. X               nmsgs (pcmail-s-ending nmsgs))
  810. X          (sit-for 2))))
  811. X    (save-excursion
  812. X      (pcmail-open-folder-list)
  813. X      (pcmail-save-buffer)
  814. X      (bury-buffer (current-buffer)))
  815. X    (or no-hooks (run-hooks 'pcmail-exit-hook))
  816. X    
  817. X    ;and make sure the folder current at quit time is displayed now
  818. X    ; (pcmail-save-folder changes the current buffer)
  819. X    (switch-to-buffer cb)
  820. X    (call-interactively 'switch-to-buffer)))
  821. X
  822. X;;;; autoloads for edit, mail, summary, and output commands
  823. X
  824. X(autoload 'pcmail-mail "pcmailmail")
  825. X(autoload 'pcmail-answer-message "pcmailmail")
  826. X(autoload 'pcmail-forward-message "pcmailmail")
  827. X(autoload 'pcmail-edit-message "pcmailedit")
  828. X(autoload 'pcmail-archive-message "pcmailout")
  829. X(autoload 'pcmail-print-message "pcmailout")
  830. X(autoload 'pcmail-copy-message "pcmailout")
  831. X(autoload 'pcmail-copy-message-1 "pcmailout")
  832. X(autoload 'pcmail-archive-subset "pcmailout")
  833. X(autoload 'pcmail-print-subset "pcmailout")
  834. X(autoload 'pcmail-copy-subset "pcmailout")
  835. X(autoload 'pcmail-wastebasket-message "pcmailout")
  836. X(autoload 'pcmail-summarize-folder "pcmailsum")
  837. X
  838. X;;;; random routines, used by all pc*.el files
  839. X
  840. X;;; minibuffer input utilities
  841. X
  842. X(defun pcmail-read-file-name (prompt fname &optional must-exist)
  843. X  "Read a file name from the minibuffer.
  844. XArgs: (prompt fname &optional must-exist)
  845. X  Read a file name from the minibuffer, prompting with PROMPT and using
  846. Xthe file portion of FNAME as default file, the directory portion as default
  847. Xdirectory.  If optional MUST-EXIST is non-NIL, input must be an existing
  848. Xfile name."
  849. X  (expand-file-name
  850. X   (read-file-name (concat prompt
  851. X               (if fname (concat "(default " fname ") ") ""))
  852. X           (and fname (file-name-directory fname))
  853. X           fname
  854. X           must-exist)))
  855. X
  856. X;; a simple read routine to grab a file name from the minibuffer.  The function
  857. X;; is only called when the folder buffer has been widened, so it narrows to
  858. X;; the current message before getting input, then restores
  859. X
  860. X(defun pcmail-narrow-read-file-name (fname)
  861. X  "Read a file name, narrowing the current buffer to the current message.
  862. XArgs: (fname)
  863. X  FNAME is the default to present to the user.  If NIL, no default is 
  864. Xpresented.  Note this is a more restrictive version of pcmail-read-file-name,
  865. Xthat assumes a standard prompt and required file existence."
  866. X  (save-excursion
  867. X    (save-restriction
  868. X      (pcmail-narrow-to-message 
  869. X       (pcmail-make-absolute pcmail-current-subset-message))
  870. X      (pcmail-read-file-name "File name: " (expand-file-name fname) t))))
  871. X
  872. X(defun pcmail-read-string-default (prompt &optional default no-blanks)
  873. X  "Read from minibuffer with optional default input.
  874. XArgs: (prompt &optional default no-blanks)
  875. X  Read from minibuffer, prompting with PROMPT, plus DEFAULT (if present).
  876. XIf a default is supplied, allow input of \"\", which causes the default 
  877. Xvalue to be returned.  If \"\" is not input, the input is returned.  If 
  878. Xoptional NO-BLANKS is non-NIL, do not allow blanks in input."
  879. X  (let ((res))
  880. X    (cond ((and (stringp default)
  881. X        (> (length default) 0))
  882. X       (setq prompt (concat prompt "(default " default ") ")))
  883. X      (t
  884. X        (setq default nil)))
  885. X    (cond (no-blanks
  886. X       (setq res (read-no-blanks-input prompt "")))
  887. X      (t
  888. X       (setq res (read-string prompt))))
  889. X    (cond ((string= res "")
  890. X        (cond (default)
  891. X          (t
  892. X            (error "No default has been set."))))
  893. X      (t
  894. X        res))))
  895. X
  896. X(defun pcmail-completing-read (prompt table &optional default pred force-p)
  897. X  "Completing read from minibuffer with optional default input.
  898. XArgs: (prompt table &optional default pred force-p)
  899. X  Read from the minibuffer using prompt PROMPT and completion list or
  900. Xobarray TABLE.  If pred is non-NIL, input is valid only if PRED when
  901. Xapplied to input returns non-NIL.  If FORCE-P is non-NIL, require a 
  902. Xmatch with an elt of TABLE.
  903. XIf DEFAULT is a string, a blank string can be input, in which case the
  904. Xreturned value will be the default.  A non-blank input will be returned as 
  905. Xa new default."
  906. X  (let ((res) (completion-ignore-case t))
  907. X    (cond ((and (stringp default)
  908. X        (> (length default) 0))
  909. X       (setq prompt (concat prompt "(default " default ") ")))
  910. X      (t
  911. X        (setq default nil)))
  912. X    (cond ((string= (setq res
  913. X              (completing-read prompt table pred force-p nil)) "")
  914. X       (or default
  915. X           (error "No default has been specified.")))
  916. X      (t
  917. X        res))))
  918. X
  919. X;;; random routines
  920. X
  921. X(defun pcmail-mode-setup (mode name keymap)
  922. X  "Generic routine for setting up pcmail modes.
  923. XArgs: (mode name keymap)
  924. X  All pcmail buffers have common features, which this routine sets up.  MODE 
  925. Xis the buffer's mode symbol, NAME is the buffer's mode name, and KEYMAP is
  926. Xthe buffer's key map."
  927. X  (kill-all-local-variables)
  928. X  (put mode 'mode-class 'special)
  929. X  (use-local-map keymap)
  930. X  (set-syntax-table text-mode-syntax-table)
  931. X  (make-local-variable 'version-control)
  932. X  (make-local-variable 'require-final-newline)
  933. X  (make-local-variable 'file-precious-flag)
  934. X  (setq major-mode mode
  935. X    mode-name name
  936. X    local-abbrev-table text-mode-abbrev-table
  937. X    buffer-read-only t
  938. X    buffer-auto-save-file-name nil
  939. X    file-precious-flag t
  940. X    require-final-newline nil
  941. X    version-control 'never))
  942. X
  943. X(defun pcmail-s-ending (n)
  944. X  "If N is 1, return the empty string, otherwise return \"s\".
  945. XArgs: (n)"
  946. X  (if (= n 1) "" "s"))
  947. X
  948. X(defun pcmail-save-buffer (&optional buf)
  949. X  "Save buffer object BUF, or current buffer if BUF is NIL.
  950. XArgs: (&optional buf)
  951. XThe only reason this function exists is that the normal save-buffer call
  952. Xdisplays messages in the minibuffer like \"(no changes need to be saved)\",
  953. Xwhich are distracting in the mail reader."
  954. X  (save-excursion
  955. X    (and buf 
  956. X     (get-buffer buf) 
  957. X     (set-buffer buf))
  958. X    (save-restriction
  959. X      (cond ((buffer-modified-p)
  960. X         (widen)
  961. X         (write-region (point-min) (point-max) buffer-file-name nil 'nomsg)
  962. X         (clear-visited-file-modtime)
  963. X         (set-buffer-modified-p nil))))
  964. X    t))
  965. X
  966. X(defun pcmail-force-mode-line-update ()
  967. X  "Force a mode line update.
  968. XArgs: none"
  969. X  (set-buffer-modified-p (buffer-modified-p)))
  970. X
  971. X(defun pcmail-search-entry-list (name alist)
  972. X  "Return the list associated with NAME in ALIST.
  973. XArgs: (name alist)"
  974. X  (assoc name alist))
  975. X
  976. X(defun pcmail-in-sequence-p (thing seq)
  977. X  "Determine if a thing is in a sequence of such things.
  978. XArgs: (thing seq)
  979. X  Return index of THING in SEQ if THING is EQUAL to an element in SEQ, nil
  980. Xelse.  SEQ may be either a list or a vector."
  981. X  (let ((i 0)
  982. X    (found))
  983. X    (while (and (not found) (< i (length seq)))
  984. X      (and (equal thing (cond ((vectorp seq) (aref seq i))
  985. X                  ((listp seq) (nth i seq))))
  986. X       (setq found i))
  987. X      (setq i (1+ i)))
  988. X    found))
  989. X
  990. X(defun pcmail-parse-space-list (s)
  991. X  "Turn a string of words separated by whitespace or commas into a list.
  992. XArgs: s"
  993. X  (let ((l) (i 0))
  994. X    (while (string-match "\\([^ \t,]+\\)" s i)
  995. X      (setq l (cons (substring s (match-beginning 1) (match-end 1)) l)
  996. X        i (match-end 1)))
  997. X    l))
  998. X
  999. X(defun pcmail-format-string (format alist)
  1000. X  "Format an arbitrary format string FORMAT using directive functions in ALIST.
  1001. XArgs: (format alist)
  1002. X  FORMAT is a format string with embedded printf-style format directives.
  1003. XALIST is an association list.  Each alist element's car is a format character.
  1004. XEach alist element's cadr is a function to call when the character is 
  1005. Xencountered following a percent sign.  The function is passed any length or
  1006. Xjustification modifiers, together with a list of arguments which are the
  1007. Xalist element's caddr, if present.  The function may return a string or 
  1008. Xa number, which is concatenated appropriately onto the formatted output 
  1009. Xstring.  The output string is returned."
  1010. X  (let ((arglist) (directive) (start) (arg) (len)
  1011. X    (outformat (copy-sequence format)) (charstart))
  1012. X    (while (string-match "%\\(-?[0-9]*\\)\\([a-zA-Z]\\)" outformat start)
  1013. X      (or (setq directive (pcmail-search-entry-list 
  1014. X               (substring outformat (match-beginning 2)
  1015. X                      (match-end 2))
  1016. X               alist))
  1017. X      (error "Unknown format directive in \"%s\"" outformat))
  1018. X      (setq len 
  1019. X        (string-to-int (substring outformat (match-beginning 1) 
  1020. X                      (match-end 1)))
  1021. X        start (match-end 0)
  1022. X        charstart (match-beginning 2)
  1023. X        arg (apply (nth 1 directive) (nthcdr 2 directive)))
  1024. X      (cond ((numberp arg)
  1025. X         (aset outformat charstart ?d))
  1026. X        (t
  1027. X         (setq arg (pcmail-justify-string arg len))
  1028. X         (aset outformat charstart ?s)))
  1029. X      (setq arglist (append arglist (list arg))))
  1030. X    (apply 'format outformat arglist)))
  1031. X
  1032. X(defun pcmail-justify-string (s len)
  1033. X  "Justify string S to LEN spaces, left if LEN is negative, right else.
  1034. XArgs: (s len)"
  1035. X  (let ((abslen (if (> len 0) len (- len))))
  1036. X    (cond ((zerop abslen)
  1037. X       s)
  1038. X      ((> (length s) abslen)
  1039. X       (substring s 0 abslen))
  1040. X      ((< len 0)
  1041. X       (concat s (make-string (- abslen (length s)) ? )))
  1042. X      ((> len 0)
  1043. X       (concat (make-string (- abslen (length s)) ? ) s)))))
  1044. X
  1045. X(provide 'pcmail)
  1046. ________This_Is_The_END________
  1047. if test `wc -c < pcmail.el` -ne 21473; then
  1048.     echo 'shar: pcmail.el was damaged during transit (should have been 21473 bytes)'
  1049. fi
  1050. fi        ; : end of overwriting check
  1051. echo 'x - pcmaildate.el'
  1052. if test -f pcmaildate.el; then echo 'shar: not overwriting pcmaildate.el'; else
  1053. sed 's/^X//' << '________This_Is_The_END________' > pcmaildate.el
  1054. X;;;; GNU-EMACS PCMAIL mail reader
  1055. X
  1056. X;;  Written by Mark L. Lambert
  1057. X;;  Architecture Group, Network Products Division
  1058. X;;  Oracle Corporation
  1059. X;;  20 Davis Dr,
  1060. X;;  Belmont CA, 94002
  1061. X;;
  1062. X;;  internet: markl@oracle.com or markl%oracle.com@apple.com
  1063. X;;  UUCP:     {hplabs,uunet,apple}!oracle!markl
  1064. X
  1065. X;; Copyright (C) 1989 Mark L. Lambert
  1066. X
  1067. X;; This file is not officially part of GNU Emacs, but is being
  1068. X;; donated to the Free Software Foundation.  As such, it is
  1069. X;; subject to the standard GNU-Emacs General Public License,
  1070. X;; referred to below.
  1071. X
  1072. X;; GNU Emacs is distributed in the hope that it will be useful,
  1073. X;; but WITHOUT ANY WARRANTY.  No author or distributor
  1074. X;; accepts responsibility to anyone for the consequences of using it
  1075. X;; or for whether it serves any particular purpose or works at all,
  1076. X;; unless he says so in writing.  Refer to the GNU Emacs General Public
  1077. X;; License for full details.
  1078. X
  1079. X;; Everyone is granted permission to copy, modify and redistribute
  1080. X;; GNU Emacs, but only under the conditions described in the
  1081. X;; GNU Emacs General Public License.   A copy of this license is
  1082. X;; supposed to have been given to you along with GNU Emacs so you
  1083. X;; can know your rights and responsibilities.  It should be in a
  1084. X;; file named COPYING.  Among other things, the copyright notice
  1085. X;; and this notice must be preserved on all copies.
  1086. X
  1087. X;;; global variables
  1088. X
  1089. X(defconst pcmail-month-alist
  1090. X  '(("???" 0) ("January" 0) ("February" 31) ("March" 49) ("April" 80) 
  1091. X    ("May" 110) ("June" 141) ("July" 171) ("August" 202) ("September" 233) 
  1092. X    ("October" 263) ("November" 294) ("December" 324))
  1093. X  "Assoc list of month names to number of days since beginning of year.")
  1094. X
  1095. X;;; date-hacking routines
  1096. X
  1097. X(defun pcmail-date-less-than-p (a b)
  1098. X  "Args: (a b)
  1099. XReturn T is message A's date is chronologically before B's, NIL else."
  1100. X  (< (pcmail-date-triple-to-ndays (pcmail-message-date a))
  1101. X     (pcmail-date-triple-to-ndays (pcmail-message-date b))))
  1102. X
  1103. X(defun pcmail-message-date (n)
  1104. X  "Return specified message's Date: field contents as a date triple.
  1105. XArgs: (n)
  1106. X  First search the pcmail-date-vector cache for a date triple.  If none is
  1107. Xfound, get message N's Date: field and bash it into a triple of the 
  1108. Xform (day month year).  If no date exists, return the triple '(0 0 0)."
  1109. X  (or (aref pcmail-date-vector n)
  1110. X      (aset pcmail-date-vector n
  1111. X        (cond ((zerop n)
  1112. X           '(0 0 0))
  1113. X          (t
  1114. X            (save-excursion
  1115. X              (save-restriction
  1116. X            (let ((case-fold-search t))
  1117. X              (pcmail-narrow-to-unpruned-header n)
  1118. X              (or (pcmail-string-to-date-triple 
  1119. X                (mail-fetch-field "date" nil))
  1120. X                  '(0 0 0))))))))))
  1121. X
  1122. X(defun pcmail-month-string-to-num (s)
  1123. X  "Convert a month name to its number.
  1124. XArgs: (s)"
  1125. X  (let ((found) (i 0))
  1126. X    (setq s (downcase (substring s 0 3)))
  1127. X    (mapcar '(lambda (mon) 
  1128. X           (and (string= s (downcase (substring (car mon) 0 3)))
  1129. X            (setq found i))
  1130. X           (setq i (1+ i)))
  1131. X        pcmail-month-alist)
  1132. X    found))
  1133. X
  1134. X(defun pcmail-num-to-month-string (n &optional fullname)
  1135. X  "Convert a month number to its name.  Return NIL if number is not 1-12.
  1136. XArgs: (n)"
  1137. X  (cond ((< n (length pcmail-month-alist))
  1138. X     (if fullname
  1139. X         (nth 0 (nth n pcmail-month-alist))
  1140. X       (substring (nth 0 (nth n pcmail-month-alist)) 0 3)))))
  1141. X
  1142. X(defun pcmail-date-triple-to-ndays (date)
  1143. X  "Turn a date triple into an absolute number.
  1144. XArgs: (date)
  1145. X  Convert triple DATE (DAY MONTH YEAR) into a number of days by adding DAY
  1146. Xto number of days in year as of beginning of MONTH and number of days in 
  1147. Xyear times YEAR.  Amount is not absolutely accurate, but good enough for
  1148. Xour purposes."
  1149. X  (+ (* 365 (nth 2 date))
  1150. X     (nth 1 (nth (nth 1 date) pcmail-month-alist))
  1151. X     (nth 0 date)))
  1152. X
  1153. X(defun pcmail-date-triple-to-string (date)
  1154. X  "Format a date triple as a string.
  1155. XArgs: (date)
  1156. X  Convert triple DATE (day month year) into a string whose format is
  1157. Xdetermined by the config variable pcmail-date-format. "
  1158. X  (pcmail-format-string 
  1159. X   pcmail-date-format
  1160. X   (list (list "d" '(lambda (date) (nth 0 date)) date)
  1161. X     (list "n" '(lambda (date) (nth 1 date)) date)
  1162. X     (list "m" '(lambda (date) (pcmail-num-to-month-string (nth 1 date)))
  1163. X           date)
  1164. X     (list "M" '(lambda (date) 
  1165. X              (pcmail-num-to-month-string (nth 1 date) t)) date)
  1166. X     (list "y" '(lambda (date) (nth 2 date)) date)
  1167. X     (list "Y" '(lambda (date) (+ 1900 (nth 2 date))) date))))
  1168. X
  1169. X(defun pcmail-string-to-date-triple (&optional s)
  1170. X  "Convert a date string into a date triple.
  1171. XArgs: (&optional s)
  1172. X  Convert message date: field string S to a date triple (day month year).
  1173. XIf conversion cannot be performed, return NIL.  If S is NIL, convert today's 
  1174. Xdate."
  1175. X  (let ((day)
  1176. X    (month)
  1177. X    (year))
  1178. X    (or s (setq s (pcmail-todays-date)))
  1179. X    (cond ((string-match "\\([0-3]?[0-9]\\)[ \t---_]+\\([a-zA-Z][a-zA-Z][a-zA-Z]\\)[a-zA-Z]*[ \t---_]+\\([0-9][0-9][0-9]*\\)"
  1180. X             s)
  1181. X       (setq day
  1182. X         (string-to-int
  1183. X           (substring s (match-beginning 1) (match-end 1)))
  1184. X         month
  1185. X         (pcmail-month-string-to-num
  1186. X          (substring s (match-beginning 2) (match-end 2)))
  1187. X         year
  1188. X         (string-to-int
  1189. X           (substring s (match-beginning 3) (match-end 3))))))
  1190. X    (cond ((and year day month (not (zerop day)) (> year 0))
  1191. X       (and (>= year 1900)
  1192. X        (setq year (- year 1900)))
  1193. X       (list day month year)))))
  1194. X
  1195. X(defun pcmail-todays-date ()
  1196. X  "Convert today's date into an RFC822 date.
  1197. XArgs: none"
  1198. X  (let ((d (current-time-string)))
  1199. X    (and (string-match (concat "\\([a-zA-Z]+\\)[ ]+\\([a-zA-Z]+\\)[ ]+"
  1200. X                   "\\([0-9]+\\)[ ]+"
  1201. X                   "\\([0-9]+:[0-9]+:[0-9]+\\)[ ]+"
  1202. X                   "19\\([0-9][0-9]\\)")
  1203. X               d)
  1204. X     (concat (substring d (match-beginning 1) (match-end 1))
  1205. X         ", " (substring d (match-beginning 3) (match-end 3))
  1206. X         " " (substring d (match-beginning 2) (match-end 2))
  1207. X         " " (substring d (match-beginning 5) (match-end 5))
  1208. X         " " (substring d (match-beginning 4) (match-end 4))
  1209. X         " " pcmail-time-zone))))
  1210. X
  1211. X(provide 'pcmaildate)
  1212. ________This_Is_The_END________
  1213. if test `wc -c < pcmaildate.el` -ne 5839; then
  1214.     echo 'shar: pcmaildate.el was damaged during transit (should have been 5839 bytes)'
  1215. fi
  1216. fi        ; : end of overwriting check
  1217. echo 'x - pcmaildrop.el'
  1218. if test -f pcmaildrop.el; then echo 'shar: not overwriting pcmaildrop.el'; else
  1219. sed 's/^X//' << '________This_Is_The_END________' > pcmaildrop.el
  1220. X;;;; GNU-EMACS PCMAIL mail reader
  1221. X
  1222. X;;  Written by Mark L. Lambert
  1223. X;;  Architecture Group, Network Products Division
  1224. X;;  Oracle Corporation
  1225. X;;  20 Davis Dr,
  1226. X;;  Belmont CA, 94002
  1227. X;;
  1228. X;;  internet: markl@oracle.com or markl%oracle.com@apple.com
  1229. X;;  UUCP:     {hplabs,uunet,apple}!oracle!markl
  1230. X
  1231. X;; Copyright (C) 1989 Mark L. Lambert
  1232. X
  1233. X;; This file is not officially part of GNU Emacs, but is being
  1234. X;; donated to the Free Software Foundation.  As such, it is
  1235. X;; subject to the standard GNU-Emacs General Public License,
  1236. X;; referred to below.
  1237. X
  1238. X;; GNU Emacs is distributed in the hope that it will be useful,
  1239. X;; but WITHOUT ANY WARRANTY.  No author or distributor
  1240. X;; accepts responsibility to anyone for the consequences of using it
  1241. X;; or for whether it serves any particular purpose or works at all,
  1242. X;; unless he says so in writing.  Refer to the GNU Emacs General Public
  1243. X;; License for full details.
  1244. X
  1245. X;; Everyone is granted permission to copy, modify and redistribute
  1246. X;; GNU Emacs, but only under the conditions described in the
  1247. X;; GNU Emacs General Public License.   A copy of this license is
  1248. X;; supposed to have been given to you along with GNU Emacs so you
  1249. X;; can know your rights and responsibilities.  It should be in a
  1250. X;; file named COPYING.  Among other things, the copyright notice
  1251. X;; and this notice must be preserved on all copies.
  1252. X
  1253. X;;;; mail drop-specific functions: transfer a mail drop's contents to a 
  1254. X;;;; folder buffer, transform its message headers to RFC-822 format
  1255. X
  1256. X;;;; global variables
  1257. X
  1258. X;;; system-defined globals
  1259. X
  1260. X(defvar pcmail-primary-folder-name (downcase (user-login-name))
  1261. X  "The name of your primary folder.  New mail always arrives here.")
  1262. X
  1263. X(defvar pcmail-last-mail-drop-type nil
  1264. X  "Name of last mail drop type given to the pcmail-load-mail-drop command.")
  1265. X
  1266. X;;; utility functions
  1267. X
  1268. X(defun pcmail-read-mail-drop (folder-name drop-list)
  1269. X  "Transfer new mail from mail drops to a specified folder.
  1270. XArgs: (folder-name drop-list)
  1271. X Get mail from the mail drops in drop-list, appending it to FOLDER-NAME.  
  1272. XUpdate all message vectors and auto-pigeonhole messages as necessary.
  1273. XAssume folder-name is current buffer.  Leave buffer widened."
  1274. X  (let ((opoint)
  1275. X    (omsgs pcmail-total-messages))
  1276. X    (widen)
  1277. X    (setq opoint (point-max))
  1278. X    (unwind-protect
  1279. X    (mapcar 'pcmail-insert-mail-drop-contents drop-list)
  1280. X      (pcmail-set-message-vectors opoint)
  1281. X      (pcmail-set-nmessages folder-name pcmail-total-messages)
  1282. X      (pcmail-change-in-folder-list folder-name pcmail-total-messages))
  1283. X    (unwind-protect
  1284. X    (progn
  1285. X      (and pcmail-pigeonhole-hook
  1286. X           (let ((n (1+ omsgs)))
  1287. X         (while (<= n pcmail-total-messages)
  1288. X           (funcall pcmail-pigeonhole-hook n)
  1289. X           (setq n (1+ n))))))
  1290. X      (and (> pcmail-total-messages omsgs)
  1291. X       (pcmail-save-buffer)))
  1292. X    (- pcmail-total-messages omsgs)))
  1293. X
  1294. X(defun pcmail-insert-mail-drop-contents (mail-drop)
  1295. X  "Insert contents of specified mail drop into the current buffer
  1296. XArgs: (mail-drop)
  1297. X  Using MAIL-DROP's insert-function property, insert MAIL-DROP's
  1298. Xcontents into the current buffer and convert the contents to Babyl format."
  1299. X  (let ((tofile) (insert-fn) (opoint) (newmsgs 0)
  1300. X    (make-backup-files (and make-backup-files (buffer-modified-p)))
  1301. X    (buffer-read-only nil))
  1302. X    (or (setq insert-fn (get mail-drop 'insert-function))
  1303. X    (error "Missing transfer function for mail drop type %s" mail-drop))
  1304. X    (message "Checking %s..." mail-drop)
  1305. X    (setq tofile (funcall insert-fn mail-drop))
  1306. X    (cond ((and tofile (file-exists-p tofile))
  1307. X       (setq opoint (goto-char (point-max)))
  1308. X       (insert-file-contents tofile)
  1309. X       (goto-char (point-max))
  1310. X       (or (= (preceding-char) ?\n)
  1311. X           (= (preceding-char) ?\^_) ;no new mail although tofile exists
  1312. X           (insert ?\n))
  1313. X       (and (get mail-drop 'log-mail-drop)
  1314. X        (copy-file tofile
  1315. X               (expand-file-name (get mail-drop 'log-mail-drop)
  1316. X                         pcmail-directory) t))
  1317. X       (condition-case nil
  1318. X           (delete-file tofile)
  1319. X         (file-error nil))
  1320. X       (setq newmsgs
  1321. X         (pcmail-convert-region-to-babyl-format mail-drop opoint
  1322. X                            (point-max)))))
  1323. X    (message "Checking %s...done (%s new message%s)"
  1324. X         mail-drop (if (zerop newmsgs) "no" (int-to-string newmsgs))
  1325. X         (pcmail-s-ending newmsgs))))
  1326. X
  1327. X(provide 'pcmaildrop)
  1328. ________This_Is_The_END________
  1329. if test `wc -c < pcmaildrop.el` -ne 4209; then
  1330.     echo 'shar: pcmaildrop.el was damaged during transit (should have been 4209 bytes)'
  1331. fi
  1332. fi        ; : end of overwriting check
  1333. exit 0
  1334.  
  1335.