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