160240Shibler /* movemail foo bar -- move file foo to file bar,
260240Shibler locking file foo the way /bin/mail respects.
360240Shibler Copyright (C) 1986 Free Software Foundation, Inc.
460240Shibler
560240Shibler This file is part of GNU Emacs.
660240Shibler
760240Shibler GNU Emacs is free software; you can redistribute it and/or modify
860240Shibler it under the terms of the GNU General Public License as published by
960240Shibler the Free Software Foundation; either version 1, or (at your option)
1060240Shibler any later version.
1160240Shibler
1260240Shibler GNU Emacs is distributed in the hope that it will be useful,
1360240Shibler but WITHOUT ANY WARRANTY; without even the implied warranty of
1460240Shibler MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1560240Shibler GNU General Public License for more details.
1660240Shibler
1760240Shibler You should have received a copy of the GNU General Public License
1860240Shibler along with GNU Emacs; see the file COPYING. If not, write to
1960240Shibler the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
2060240Shibler
2160240Shibler /*
2260240Shibler * Modified January, 1986 by Michael R. Gretzinger (Project Athena)
2360240Shibler *
2460240Shibler * Added POP (Post Office Protocol) service. When compiled -DPOP
2560240Shibler * movemail will accept input filename arguments of the form
2660240Shibler * "po:username". This will cause movemail to open a connection to
2760240Shibler * a pop server running on $MAILHOST (environment variable). Movemail
2860240Shibler * must be setuid to root in order to work with POP.
2960240Shibler *
3060240Shibler * New module: popmail.c
3160240Shibler * Modified routines:
3260240Shibler * main - added code within #ifdef MAIL_USE_POP; added setuid(getuid())
3360240Shibler * after POP code.
3460240Shibler * New routines in movemail.c:
3560240Shibler * get_errmsg - return pointer to system error message
3660240Shibler *
3760240Shibler */
3860240Shibler
3960240Shibler #include <sys/types.h>
4060240Shibler #include <sys/stat.h>
4160240Shibler #include <sys/file.h>
4260240Shibler #include <errno.h>
43*60587Sbostic #include <unistd.h>
4460240Shibler #define NO_SHORTNAMES /* Tell config not to load remap.h */
4560240Shibler #include "../src/config.h"
4660240Shibler
4760240Shibler #ifdef USG
4860240Shibler #include <fcntl.h>
4960240Shibler #include <unistd.h>
5060240Shibler #ifndef F_OK
5160240Shibler #define F_OK 0
5260240Shibler #define X_OK 1
5360240Shibler #define W_OK 2
5460240Shibler #define R_OK 4
5560240Shibler #endif
5660240Shibler #endif /* USG */
5760240Shibler
5860240Shibler #ifdef XENIX
5960240Shibler #include <sys/locking.h>
6060240Shibler #endif
6160240Shibler
6260240Shibler /* Cancel substitutions made by config.h for Emacs. */
6360240Shibler #undef open
6460240Shibler #undef read
6560240Shibler #undef write
6660240Shibler #undef close
6760240Shibler
6860240Shibler char *concat ();
6960240Shibler extern int errno;
7060240Shibler
7160240Shibler /* Nonzero means this is name of a lock file to delete on fatal error. */
7260240Shibler char *delete_lockname;
7360240Shibler
main(argc,argv)7460240Shibler main (argc, argv)
7560240Shibler int argc;
7660240Shibler char **argv;
7760240Shibler {
7860240Shibler char *inname, *outname;
7960240Shibler int indesc, outdesc;
8060240Shibler char buf[1024];
8160240Shibler int nread;
8260240Shibler
8360240Shibler #ifndef MAIL_USE_FLOCK
8460240Shibler struct stat st;
8560240Shibler long now;
8660240Shibler int tem;
8760240Shibler char *lockname, *p;
8860240Shibler char tempname[40];
8960240Shibler int desc;
9060240Shibler #endif /* not MAIL_USE_FLOCK */
9160240Shibler
9260240Shibler delete_lockname = 0;
9360240Shibler
9460240Shibler if (argc < 3)
9560240Shibler fatal ("two arguments required");
9660240Shibler
9760240Shibler inname = argv[1];
9860240Shibler outname = argv[2];
9960240Shibler
10060240Shibler /* Check access to output file. */
10160240Shibler if (access (outname, F_OK) == 0 && access (outname, W_OK) != 0)
10260240Shibler pfatal_with_name (outname);
10360240Shibler
10460240Shibler /* Also check that outname's directory is writeable to the real uid. */
10560240Shibler {
10660240Shibler char *buf = (char *) malloc (strlen (outname) + 1);
10760240Shibler char *p, q;
10860240Shibler strcpy (buf, outname);
10960240Shibler p = buf + strlen (buf);
11060240Shibler while (p > buf && p[-1] != '/')
11160240Shibler *--p = 0;
11260240Shibler if (p == buf)
11360240Shibler *p++ = '.';
11460240Shibler if (access (buf, W_OK) != 0)
11560240Shibler pfatal_with_name (buf);
11660240Shibler free (buf);
11760240Shibler }
11860240Shibler
11960240Shibler #ifdef MAIL_USE_POP
12060240Shibler if (!bcmp (inname, "po:", 3))
12160240Shibler {
12260240Shibler int status; char *user;
12360240Shibler
12460240Shibler user = (char *) rindex (inname, ':') + 1;
12560240Shibler status = popmail (user, outname);
12660240Shibler exit (status);
12760240Shibler }
12860240Shibler
12960240Shibler setuid (getuid());
13060240Shibler #endif /* MAIL_USE_POP */
13160240Shibler
13260240Shibler /* Check access to input file. */
13360240Shibler if (access (inname, R_OK | W_OK) != 0)
13460240Shibler pfatal_with_name (inname);
13560240Shibler
13660240Shibler #ifndef MAIL_USE_FLOCK
13760240Shibler /* Use a lock file named /usr/spool/mail/$USER.lock:
13860240Shibler If it exists, the mail file is locked. */
13960240Shibler lockname = concat (inname, ".lock", "");
14060240Shibler strcpy (tempname, inname);
14160240Shibler p = tempname + strlen (tempname);
14260240Shibler while (p != tempname && p[-1] != '/')
14360240Shibler p--;
14460240Shibler *p = 0;
14560240Shibler strcpy (p, "EXXXXXX");
14660240Shibler mktemp (tempname);
14760240Shibler (void) unlink (tempname);
14860240Shibler
14960240Shibler while (1)
15060240Shibler {
15160240Shibler /* Create the lock file, but not under the lock file name. */
15260240Shibler /* Give up if cannot do that. */
15360240Shibler desc = open (tempname, O_WRONLY | O_CREAT, 0666);
15460240Shibler if (desc < 0)
15560240Shibler pfatal_with_name (concat ("temporary file \"", tempname, "\""));
15660240Shibler close (desc);
15760240Shibler
15860240Shibler tem = link (tempname, lockname);
15960240Shibler (void) unlink (tempname);
16060240Shibler if (tem >= 0)
16160240Shibler break;
16260240Shibler sleep (1);
16360240Shibler
16460240Shibler /* If lock file is a minute old, unlock it. */
16560240Shibler if (stat (lockname, &st) >= 0)
16660240Shibler {
16760240Shibler now = time (0);
16860240Shibler if (st.st_ctime < now - 60)
16960240Shibler (void) unlink (lockname);
17060240Shibler }
17160240Shibler }
17260240Shibler
17360240Shibler delete_lockname = lockname;
17460240Shibler #endif /* not MAIL_USE_FLOCK */
17560240Shibler
17660240Shibler #ifdef MAIL_USE_FLOCK
17760240Shibler indesc = open (inname, O_RDWR);
17860240Shibler #else /* if not MAIL_USE_FLOCK */
17960240Shibler indesc = open (inname, O_RDONLY);
18060240Shibler #endif /* not MAIL_USE_FLOCK */
18160240Shibler if (indesc < 0)
18260240Shibler pfatal_with_name (inname);
18360240Shibler
18460240Shibler #if defined(BSD) || defined(XENIX)
18560240Shibler /* In case movemail is setuid to root, make sure the user can
18660240Shibler read the output file. */
18760240Shibler /* This is desirable for all systems
18860240Shibler but I don't want to assume all have the umask system call */
18960240Shibler umask (umask (0) & 0333);
19060240Shibler #endif /* BSD or Xenix */
19160240Shibler outdesc = open (outname, O_WRONLY | O_CREAT | O_EXCL, 0666);
19260240Shibler if (outdesc < 0)
19360240Shibler pfatal_with_name (outname);
19460240Shibler #ifdef MAIL_USE_FLOCK
19560240Shibler #ifdef XENIX
19660240Shibler if (locking (indesc, LK_RLCK, 0L) < 0) pfatal_with_name (inname);
19760240Shibler #else
19860240Shibler flock (indesc, LOCK_EX);
19960240Shibler #endif
20060240Shibler #endif /* MAIL_USE_FLOCK */
20160240Shibler
20260240Shibler while (1)
20360240Shibler {
20460240Shibler nread = read (indesc, buf, sizeof buf);
20560240Shibler if (nread != write (outdesc, buf, nread))
20660240Shibler {
20760240Shibler int saved_errno = errno;
20860240Shibler (void) unlink (outname);
20960240Shibler errno = saved_errno;
21060240Shibler pfatal_with_name (outname);
21160240Shibler }
21260240Shibler if (nread < sizeof buf)
21360240Shibler break;
21460240Shibler }
21560240Shibler
21660240Shibler #ifdef BSD
21760240Shibler fsync (outdesc);
21860240Shibler #endif
21960240Shibler
22060240Shibler /* Check to make sure no errors before we zap the inbox. */
22160240Shibler if (close (outdesc) != 0)
22260240Shibler {
22360240Shibler int saved_errno = errno;
22460240Shibler (void) unlink (outname);
22560240Shibler errno = saved_errno;
22660240Shibler pfatal_with_name (outname);
22760240Shibler }
22860240Shibler
22960240Shibler #ifdef MAIL_USE_FLOCK
23060240Shibler #if defined(STRIDE) || defined(XENIX)
23160240Shibler /* Stride, xenix have file locking, but no ftruncate. This mess will do. */
23260240Shibler (void) close (open (inname, O_CREAT | O_TRUNC | O_RDWR, 0666));
23360240Shibler #else
23460290Shibler (void) ftruncate (indesc, (off_t)0);
23560240Shibler #endif /* STRIDE or XENIX */
23660240Shibler #endif /* MAIL_USE_FLOCK */
23760240Shibler close (indesc);
23860240Shibler
23960240Shibler #ifndef MAIL_USE_FLOCK
24060240Shibler /* Delete the input file; if we can't, at least get rid of its contents. */
24160240Shibler if (unlink (inname) < 0)
24260240Shibler if (errno != ENOENT)
24360240Shibler creat (inname, 0666);
24460240Shibler (void) unlink (lockname);
24560240Shibler #endif /* not MAIL_USE_FLOCK */
24660240Shibler exit (0);
24760240Shibler }
24860240Shibler
24960240Shibler /* Print error message and exit. */
25060240Shibler
fatal(s1,s2)25160240Shibler fatal (s1, s2)
25260240Shibler char *s1, *s2;
25360240Shibler {
25460240Shibler if (delete_lockname)
25560240Shibler unlink (delete_lockname);
25660240Shibler error (s1, s2);
25760240Shibler exit (1);
25860240Shibler }
25960240Shibler
26060240Shibler /* Print error message. `s1' is printf control string, `s2' is arg for it. */
26160240Shibler
error(s1,s2,s3)26260240Shibler error (s1, s2, s3)
26360240Shibler char *s1, *s2, *s3;
26460240Shibler {
26560240Shibler printf ("movemail: ");
26660240Shibler printf (s1, s2, s3);
26760240Shibler printf ("\n");
26860240Shibler }
26960240Shibler
pfatal_with_name(name)27060240Shibler pfatal_with_name (name)
27160240Shibler char *name;
27260240Shibler {
27360240Shibler extern int errno, sys_nerr;
27460240Shibler extern char *sys_errlist[];
27560240Shibler char *s;
27660240Shibler
27760240Shibler if (errno < sys_nerr)
27860240Shibler s = concat ("", sys_errlist[errno], " for %s");
27960240Shibler else
28060240Shibler s = "cannot open %s";
28160240Shibler fatal (s, name);
28260240Shibler }
28360240Shibler
28460240Shibler /* Return a newly-allocated string whose contents concatenate those of s1, s2, s3. */
28560240Shibler
28660240Shibler char *
concat(s1,s2,s3)28760240Shibler concat (s1, s2, s3)
28860240Shibler char *s1, *s2, *s3;
28960240Shibler {
29060240Shibler int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
29160240Shibler char *result = (char *) xmalloc (len1 + len2 + len3 + 1);
29260240Shibler
29360240Shibler strcpy (result, s1);
29460240Shibler strcpy (result + len1, s2);
29560240Shibler strcpy (result + len1 + len2, s3);
29660240Shibler *(result + len1 + len2 + len3) = 0;
29760240Shibler
29860240Shibler return result;
29960240Shibler }
30060240Shibler
30160240Shibler /* Like malloc but get fatal error if memory is exhausted. */
30260240Shibler
30360240Shibler int
xmalloc(size)30460240Shibler xmalloc (size)
30560240Shibler int size;
30660240Shibler {
30760240Shibler int result = malloc (size);
30860240Shibler if (!result)
30960240Shibler fatal ("virtual memory exhausted", 0);
31060240Shibler return result;
31160240Shibler }
31260240Shibler
31360240Shibler /* This is the guts of the interface to the Post Office Protocol. */
31460240Shibler
31560240Shibler #ifdef MAIL_USE_POP
31660240Shibler
31760240Shibler #include <sys/socket.h>
31860240Shibler #include <netinet/in.h>
31960240Shibler #include <netdb.h>
32060240Shibler #include <stdio.h>
32160240Shibler
32260240Shibler #ifdef USG
32360240Shibler #include <fcntl.h>
32460240Shibler /* Cancel substitutions made by config.h for Emacs. */
32560240Shibler #undef open
32660240Shibler #undef read
32760240Shibler #undef write
32860240Shibler #undef close
32960240Shibler #endif /* USG */
33060240Shibler
33160240Shibler #define NOTOK (-1)
33260240Shibler #define OK 0
33360240Shibler #define DONE 1
33460240Shibler
33560240Shibler char *progname;
33660240Shibler FILE *sfi;
33760240Shibler FILE *sfo;
33860240Shibler char Errmsg[80];
33960240Shibler
34060240Shibler static int debug = 0;
34160240Shibler
popmail(user,outfile)34260240Shibler popmail(user, outfile)
34360240Shibler char *user;
34460240Shibler char *outfile;
34560240Shibler {
34660240Shibler char *host;
34760240Shibler int nmsgs, nbytes;
34860240Shibler char response[128];
34960240Shibler register int i;
35060240Shibler int mbfi;
35160240Shibler FILE *mbf;
35260240Shibler char *getenv();
35360240Shibler int mbx_write();
35460240Shibler char *get_errmsg();
35560240Shibler
35660240Shibler host = getenv("MAILHOST");
35760240Shibler if (host == NULL) {
35860240Shibler fatal("no MAILHOST defined");
35960240Shibler }
36060240Shibler
36160240Shibler if (pop_init(host) == NOTOK) {
36260240Shibler error(Errmsg);
36360240Shibler return(1);
36460240Shibler }
36560240Shibler
36660240Shibler if (getline(response, sizeof response, sfi) != OK) {
36760240Shibler error(response);
36860240Shibler return(1);
36960240Shibler }
37060240Shibler
37160240Shibler if (pop_command("USER %s", user) == NOTOK ||
37260240Shibler pop_command("RPOP %s", user) == NOTOK) {
37360240Shibler error(Errmsg);
37460240Shibler pop_command("QUIT");
37560240Shibler return(1);
37660240Shibler }
37760240Shibler
37860240Shibler if (pop_stat(&nmsgs, &nbytes) == NOTOK) {
37960240Shibler error(Errmsg);
38060240Shibler pop_command("QUIT");
38160240Shibler return(1);
38260240Shibler }
38360240Shibler
38460240Shibler if (!nmsgs)
38560240Shibler {
38660240Shibler pop_command("QUIT");
38760240Shibler return(0);
38860240Shibler }
38960240Shibler
39060240Shibler mbfi = open (outfile, O_WRONLY | O_CREAT | O_EXCL, 0666);
39160240Shibler if (mbfi < 0)
39260240Shibler {
39360240Shibler pop_command("QUIT");
39460240Shibler error("Error in open: %s, %s", get_errmsg(), outfile);
39560240Shibler return(1);
39660240Shibler }
39760240Shibler fchown(mbfi, getuid(), -1);
39860240Shibler
39960240Shibler if ((mbf = fdopen(mbfi, "w")) == NULL)
40060240Shibler {
40160240Shibler pop_command("QUIT");
40260240Shibler error("Error in fdopen: %s", get_errmsg());
40360240Shibler close(mbfi);
40460240Shibler unlink(outfile);
40560240Shibler return(1);
40660240Shibler }
40760240Shibler
40860240Shibler for (i = 1; i <= nmsgs; i++) {
40960240Shibler mbx_delimit_begin(mbf);
41060240Shibler if (pop_retr(i, mbx_write, mbf) != OK) {
41160240Shibler error(Errmsg);
41260240Shibler pop_command("QUIT");
41360240Shibler close(mbfi);
41460240Shibler return(1);
41560240Shibler }
41660240Shibler mbx_delimit_end(mbf);
41760240Shibler fflush(mbf);
41860240Shibler }
41960240Shibler
42060240Shibler for (i = 1; i <= nmsgs; i++) {
42160240Shibler if (pop_command("DELE %d", i) == NOTOK) {
42260240Shibler error(Errmsg);
42360240Shibler pop_command("QUIT");
42460240Shibler close(mbfi);
42560240Shibler return(1);
42660240Shibler }
42760240Shibler }
42860240Shibler
42960240Shibler pop_command("QUIT");
43060240Shibler close(mbfi);
43160240Shibler return(0);
43260240Shibler }
43360240Shibler
pop_init(host)43460240Shibler pop_init(host)
43560240Shibler char *host;
43660240Shibler {
43760240Shibler register struct hostent *hp;
43860240Shibler register struct servent *sp;
43960240Shibler int lport = IPPORT_RESERVED - 1;
44060240Shibler struct sockaddr_in sin;
44160240Shibler register int s;
44260240Shibler char *get_errmsg();
44360240Shibler
44460240Shibler hp = gethostbyname(host);
44560240Shibler if (hp == NULL) {
44660240Shibler sprintf(Errmsg, "MAILHOST unknown: %s", host);
44760240Shibler return(NOTOK);
44860240Shibler }
44960240Shibler
45060240Shibler sp = getservbyname("pop", "tcp");
45160240Shibler if (sp == 0) {
45260240Shibler strcpy(Errmsg, "tcp/pop: unknown service");
45360240Shibler return(NOTOK);
45460240Shibler }
45560240Shibler
45660240Shibler sin.sin_family = hp->h_addrtype;
45760240Shibler bcopy(hp->h_addr, (char *)&sin.sin_addr, hp->h_length);
45860240Shibler sin.sin_port = sp->s_port;
45960240Shibler s = rresvport(&lport);
46060240Shibler if (s < 0) {
46160240Shibler sprintf(Errmsg, "error creating socket: %s", get_errmsg());
46260240Shibler return(NOTOK);
46360240Shibler }
46460240Shibler
46560240Shibler if (connect(s, (char *)&sin, sizeof sin) < 0) {
46660240Shibler sprintf(Errmsg, "error during connect: %s", get_errmsg());
46760240Shibler close(s);
46860240Shibler return(NOTOK);
46960240Shibler }
47060240Shibler
47160240Shibler sfi = fdopen(s, "r");
47260240Shibler sfo = fdopen(s, "w");
47360240Shibler if (sfi == NULL || sfo == NULL) {
47460240Shibler sprintf(Errmsg, "error in fdopen: %s", get_errmsg());
47560240Shibler close(s);
47660240Shibler return(NOTOK);
47760240Shibler }
47860240Shibler
47960240Shibler return(OK);
48060240Shibler }
48160240Shibler
pop_command(fmt,a,b,c,d)48260240Shibler pop_command(fmt, a, b, c, d)
48360240Shibler char *fmt;
48460240Shibler {
48560240Shibler char buf[128];
48660240Shibler char errmsg[64];
48760240Shibler
48860240Shibler sprintf(buf, fmt, a, b, c, d);
48960240Shibler
49060240Shibler if (debug) fprintf(stderr, "---> %s\n", buf);
49160240Shibler if (putline(buf, Errmsg, sfo) == NOTOK) return(NOTOK);
49260240Shibler
49360240Shibler if (getline(buf, sizeof buf, sfi) != OK) {
49460240Shibler strcpy(Errmsg, buf);
49560240Shibler return(NOTOK);
49660240Shibler }
49760240Shibler
49860240Shibler if (debug) fprintf(stderr, "<--- %s\n", buf);
49960240Shibler if (*buf != '+') {
50060240Shibler strcpy(Errmsg, buf);
50160240Shibler return(NOTOK);
50260240Shibler } else {
50360240Shibler return(OK);
50460240Shibler }
50560240Shibler }
50660240Shibler
50760240Shibler
pop_stat(nmsgs,nbytes)50860240Shibler pop_stat(nmsgs, nbytes)
50960240Shibler int *nmsgs, *nbytes;
51060240Shibler {
51160240Shibler char buf[128];
51260240Shibler
51360240Shibler if (debug) fprintf(stderr, "---> STAT\n");
51460240Shibler if (putline("STAT", Errmsg, sfo) == NOTOK) return(NOTOK);
51560240Shibler
51660240Shibler if (getline(buf, sizeof buf, sfi) != OK) {
51760240Shibler strcpy(Errmsg, buf);
51860240Shibler return(NOTOK);
51960240Shibler }
52060240Shibler
52160240Shibler if (debug) fprintf(stderr, "<--- %s\n", buf);
52260240Shibler if (*buf != '+') {
52360240Shibler strcpy(Errmsg, buf);
52460240Shibler return(NOTOK);
52560240Shibler } else {
52660240Shibler sscanf(buf, "+OK %d %d", nmsgs, nbytes);
52760240Shibler return(OK);
52860240Shibler }
52960240Shibler }
53060240Shibler
53160240Shibler pop_retr(msgno, action, arg)
53260240Shibler int (*action)();
53360240Shibler {
53460240Shibler char buf[128];
53560240Shibler
53660240Shibler sprintf(buf, "RETR %d", msgno);
53760240Shibler if (debug) fprintf(stderr, "%s\n", buf);
53860240Shibler if (putline(buf, Errmsg, sfo) == NOTOK) return(NOTOK);
53960240Shibler
54060240Shibler if (getline(buf, sizeof buf, sfi) != OK) {
54160240Shibler strcpy(Errmsg, buf);
54260240Shibler return(NOTOK);
54360240Shibler }
54460240Shibler
54560240Shibler while (1) {
54660240Shibler switch (multiline(buf, sizeof buf, sfi)) {
54760240Shibler case OK:
54860240Shibler (*action)(buf, arg);
54960240Shibler break;
55060240Shibler case DONE:
55160240Shibler return (OK);
55260240Shibler case NOTOK:
55360240Shibler strcpy(Errmsg, buf);
55460240Shibler return (NOTOK);
55560240Shibler }
55660240Shibler }
55760240Shibler }
55860240Shibler
getline(buf,n,f)55960240Shibler getline(buf, n, f)
56060240Shibler char *buf;
56160240Shibler register int n;
56260240Shibler FILE *f;
56360240Shibler {
56460240Shibler register char *p;
56560240Shibler int c;
56660240Shibler
56760240Shibler p = buf;
56860240Shibler while (--n > 0 && (c = fgetc(f)) != EOF)
56960240Shibler if ((*p++ = c) == '\n') break;
57060240Shibler
57160240Shibler if (ferror(f)) {
57260240Shibler strcpy(buf, "error on connection");
57360240Shibler return (NOTOK);
57460240Shibler }
57560240Shibler
57660240Shibler if (c == EOF && p == buf) {
57760240Shibler strcpy(buf, "connection closed by foreign host");
57860240Shibler return (DONE);
57960240Shibler }
58060240Shibler
58160240Shibler *p = NULL;
58260240Shibler if (*--p == '\n') *p = NULL;
58360240Shibler if (*--p == '\r') *p = NULL;
58460240Shibler return(OK);
58560240Shibler }
58660240Shibler
multiline(buf,n,f)58760240Shibler multiline(buf, n, f)
58860240Shibler char *buf;
58960240Shibler register int n;
59060240Shibler FILE *f;
59160240Shibler {
59260240Shibler if (getline(buf, n, f) != OK) return (NOTOK);
59360240Shibler if (*buf == '.') {
59460240Shibler if (*(buf+1) == NULL) {
59560240Shibler return (DONE);
59660240Shibler } else {
59760240Shibler strcpy(buf, buf+1);
59860240Shibler }
59960240Shibler }
60060240Shibler return(OK);
60160240Shibler }
60260240Shibler
60360240Shibler char *
get_errmsg()60460240Shibler get_errmsg()
60560240Shibler {
60660240Shibler extern int errno, sys_nerr;
60760240Shibler extern char *sys_errlist[];
60860240Shibler char *s;
60960240Shibler
61060240Shibler if (errno < sys_nerr)
61160240Shibler s = sys_errlist[errno];
61260240Shibler else
61360240Shibler s = "unknown error";
61460240Shibler return(s);
61560240Shibler }
61660240Shibler
putline(buf,err,f)61760240Shibler putline(buf, err, f)
61860240Shibler char *buf;
61960240Shibler char *err;
62060240Shibler FILE *f;
62160240Shibler {
62260240Shibler fprintf(f, "%s\r\n", buf);
62360240Shibler fflush(f);
62460240Shibler if (ferror(f)) {
62560240Shibler strcpy(err, "lost connection");
62660240Shibler return(NOTOK);
62760240Shibler }
62860240Shibler return(OK);
62960240Shibler }
63060240Shibler
mbx_write(line,mbf)63160240Shibler mbx_write(line, mbf)
63260240Shibler char *line;
63360240Shibler FILE *mbf;
63460240Shibler {
63560240Shibler fputs(line, mbf);
63660240Shibler fputc(0x0a, mbf);
63760240Shibler }
63860240Shibler
mbx_delimit_begin(mbf)63960240Shibler mbx_delimit_begin(mbf)
64060240Shibler FILE *mbf;
64160240Shibler {
64260240Shibler fputs("\f\n0, unseen,,\n", mbf);
64360240Shibler }
64460240Shibler
mbx_delimit_end(mbf)64560240Shibler mbx_delimit_end(mbf)
64660240Shibler FILE *mbf;
64760240Shibler {
64860240Shibler putc('\037', mbf);
64960240Shibler }
65060240Shibler
65160240Shibler #endif /* MAIL_USE_POP */
652