1*60240Shibler /* movemail foo bar -- move file foo to file bar, 2*60240Shibler locking file foo the way /bin/mail respects. 3*60240Shibler Copyright (C) 1986 Free Software Foundation, Inc. 4*60240Shibler 5*60240Shibler This file is part of GNU Emacs. 6*60240Shibler 7*60240Shibler GNU Emacs is free software; you can redistribute it and/or modify 8*60240Shibler it under the terms of the GNU General Public License as published by 9*60240Shibler the Free Software Foundation; either version 1, or (at your option) 10*60240Shibler any later version. 11*60240Shibler 12*60240Shibler GNU Emacs is distributed in the hope that it will be useful, 13*60240Shibler but WITHOUT ANY WARRANTY; without even the implied warranty of 14*60240Shibler MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15*60240Shibler GNU General Public License for more details. 16*60240Shibler 17*60240Shibler You should have received a copy of the GNU General Public License 18*60240Shibler along with GNU Emacs; see the file COPYING. If not, write to 19*60240Shibler the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ 20*60240Shibler 21*60240Shibler /* 22*60240Shibler * Modified January, 1986 by Michael R. Gretzinger (Project Athena) 23*60240Shibler * 24*60240Shibler * Added POP (Post Office Protocol) service. When compiled -DPOP 25*60240Shibler * movemail will accept input filename arguments of the form 26*60240Shibler * "po:username". This will cause movemail to open a connection to 27*60240Shibler * a pop server running on $MAILHOST (environment variable). Movemail 28*60240Shibler * must be setuid to root in order to work with POP. 29*60240Shibler * 30*60240Shibler * New module: popmail.c 31*60240Shibler * Modified routines: 32*60240Shibler * main - added code within #ifdef MAIL_USE_POP; added setuid(getuid()) 33*60240Shibler * after POP code. 34*60240Shibler * New routines in movemail.c: 35*60240Shibler * get_errmsg - return pointer to system error message 36*60240Shibler * 37*60240Shibler */ 38*60240Shibler 39*60240Shibler #include <sys/types.h> 40*60240Shibler #include <sys/stat.h> 41*60240Shibler #include <sys/file.h> 42*60240Shibler #include <errno.h> 43*60240Shibler #define NO_SHORTNAMES /* Tell config not to load remap.h */ 44*60240Shibler #include "../src/config.h" 45*60240Shibler 46*60240Shibler #ifdef USG 47*60240Shibler #include <fcntl.h> 48*60240Shibler #include <unistd.h> 49*60240Shibler #ifndef F_OK 50*60240Shibler #define F_OK 0 51*60240Shibler #define X_OK 1 52*60240Shibler #define W_OK 2 53*60240Shibler #define R_OK 4 54*60240Shibler #endif 55*60240Shibler #endif /* USG */ 56*60240Shibler 57*60240Shibler #ifdef XENIX 58*60240Shibler #include <sys/locking.h> 59*60240Shibler #endif 60*60240Shibler 61*60240Shibler /* Cancel substitutions made by config.h for Emacs. */ 62*60240Shibler #undef open 63*60240Shibler #undef read 64*60240Shibler #undef write 65*60240Shibler #undef close 66*60240Shibler 67*60240Shibler char *concat (); 68*60240Shibler extern int errno; 69*60240Shibler 70*60240Shibler /* Nonzero means this is name of a lock file to delete on fatal error. */ 71*60240Shibler char *delete_lockname; 72*60240Shibler 73*60240Shibler main (argc, argv) 74*60240Shibler int argc; 75*60240Shibler char **argv; 76*60240Shibler { 77*60240Shibler char *inname, *outname; 78*60240Shibler int indesc, outdesc; 79*60240Shibler char buf[1024]; 80*60240Shibler int nread; 81*60240Shibler 82*60240Shibler #ifndef MAIL_USE_FLOCK 83*60240Shibler struct stat st; 84*60240Shibler long now; 85*60240Shibler int tem; 86*60240Shibler char *lockname, *p; 87*60240Shibler char tempname[40]; 88*60240Shibler int desc; 89*60240Shibler #endif /* not MAIL_USE_FLOCK */ 90*60240Shibler 91*60240Shibler delete_lockname = 0; 92*60240Shibler 93*60240Shibler if (argc < 3) 94*60240Shibler fatal ("two arguments required"); 95*60240Shibler 96*60240Shibler inname = argv[1]; 97*60240Shibler outname = argv[2]; 98*60240Shibler 99*60240Shibler /* Check access to output file. */ 100*60240Shibler if (access (outname, F_OK) == 0 && access (outname, W_OK) != 0) 101*60240Shibler pfatal_with_name (outname); 102*60240Shibler 103*60240Shibler /* Also check that outname's directory is writeable to the real uid. */ 104*60240Shibler { 105*60240Shibler char *buf = (char *) malloc (strlen (outname) + 1); 106*60240Shibler char *p, q; 107*60240Shibler strcpy (buf, outname); 108*60240Shibler p = buf + strlen (buf); 109*60240Shibler while (p > buf && p[-1] != '/') 110*60240Shibler *--p = 0; 111*60240Shibler if (p == buf) 112*60240Shibler *p++ = '.'; 113*60240Shibler if (access (buf, W_OK) != 0) 114*60240Shibler pfatal_with_name (buf); 115*60240Shibler free (buf); 116*60240Shibler } 117*60240Shibler 118*60240Shibler #ifdef MAIL_USE_POP 119*60240Shibler if (!bcmp (inname, "po:", 3)) 120*60240Shibler { 121*60240Shibler int status; char *user; 122*60240Shibler 123*60240Shibler user = (char *) rindex (inname, ':') + 1; 124*60240Shibler status = popmail (user, outname); 125*60240Shibler exit (status); 126*60240Shibler } 127*60240Shibler 128*60240Shibler setuid (getuid()); 129*60240Shibler #endif /* MAIL_USE_POP */ 130*60240Shibler 131*60240Shibler /* Check access to input file. */ 132*60240Shibler if (access (inname, R_OK | W_OK) != 0) 133*60240Shibler pfatal_with_name (inname); 134*60240Shibler 135*60240Shibler #ifndef MAIL_USE_FLOCK 136*60240Shibler /* Use a lock file named /usr/spool/mail/$USER.lock: 137*60240Shibler If it exists, the mail file is locked. */ 138*60240Shibler lockname = concat (inname, ".lock", ""); 139*60240Shibler strcpy (tempname, inname); 140*60240Shibler p = tempname + strlen (tempname); 141*60240Shibler while (p != tempname && p[-1] != '/') 142*60240Shibler p--; 143*60240Shibler *p = 0; 144*60240Shibler strcpy (p, "EXXXXXX"); 145*60240Shibler mktemp (tempname); 146*60240Shibler (void) unlink (tempname); 147*60240Shibler 148*60240Shibler while (1) 149*60240Shibler { 150*60240Shibler /* Create the lock file, but not under the lock file name. */ 151*60240Shibler /* Give up if cannot do that. */ 152*60240Shibler desc = open (tempname, O_WRONLY | O_CREAT, 0666); 153*60240Shibler if (desc < 0) 154*60240Shibler pfatal_with_name (concat ("temporary file \"", tempname, "\"")); 155*60240Shibler close (desc); 156*60240Shibler 157*60240Shibler tem = link (tempname, lockname); 158*60240Shibler (void) unlink (tempname); 159*60240Shibler if (tem >= 0) 160*60240Shibler break; 161*60240Shibler sleep (1); 162*60240Shibler 163*60240Shibler /* If lock file is a minute old, unlock it. */ 164*60240Shibler if (stat (lockname, &st) >= 0) 165*60240Shibler { 166*60240Shibler now = time (0); 167*60240Shibler if (st.st_ctime < now - 60) 168*60240Shibler (void) unlink (lockname); 169*60240Shibler } 170*60240Shibler } 171*60240Shibler 172*60240Shibler delete_lockname = lockname; 173*60240Shibler #endif /* not MAIL_USE_FLOCK */ 174*60240Shibler 175*60240Shibler #ifdef MAIL_USE_FLOCK 176*60240Shibler indesc = open (inname, O_RDWR); 177*60240Shibler #else /* if not MAIL_USE_FLOCK */ 178*60240Shibler indesc = open (inname, O_RDONLY); 179*60240Shibler #endif /* not MAIL_USE_FLOCK */ 180*60240Shibler if (indesc < 0) 181*60240Shibler pfatal_with_name (inname); 182*60240Shibler 183*60240Shibler #if defined(BSD) || defined(XENIX) 184*60240Shibler /* In case movemail is setuid to root, make sure the user can 185*60240Shibler read the output file. */ 186*60240Shibler /* This is desirable for all systems 187*60240Shibler but I don't want to assume all have the umask system call */ 188*60240Shibler umask (umask (0) & 0333); 189*60240Shibler #endif /* BSD or Xenix */ 190*60240Shibler outdesc = open (outname, O_WRONLY | O_CREAT | O_EXCL, 0666); 191*60240Shibler if (outdesc < 0) 192*60240Shibler pfatal_with_name (outname); 193*60240Shibler #ifdef MAIL_USE_FLOCK 194*60240Shibler #ifdef XENIX 195*60240Shibler if (locking (indesc, LK_RLCK, 0L) < 0) pfatal_with_name (inname); 196*60240Shibler #else 197*60240Shibler flock (indesc, LOCK_EX); 198*60240Shibler #endif 199*60240Shibler #endif /* MAIL_USE_FLOCK */ 200*60240Shibler 201*60240Shibler while (1) 202*60240Shibler { 203*60240Shibler nread = read (indesc, buf, sizeof buf); 204*60240Shibler if (nread != write (outdesc, buf, nread)) 205*60240Shibler { 206*60240Shibler int saved_errno = errno; 207*60240Shibler (void) unlink (outname); 208*60240Shibler errno = saved_errno; 209*60240Shibler pfatal_with_name (outname); 210*60240Shibler } 211*60240Shibler if (nread < sizeof buf) 212*60240Shibler break; 213*60240Shibler } 214*60240Shibler 215*60240Shibler #ifdef BSD 216*60240Shibler fsync (outdesc); 217*60240Shibler #endif 218*60240Shibler 219*60240Shibler /* Check to make sure no errors before we zap the inbox. */ 220*60240Shibler if (close (outdesc) != 0) 221*60240Shibler { 222*60240Shibler int saved_errno = errno; 223*60240Shibler (void) unlink (outname); 224*60240Shibler errno = saved_errno; 225*60240Shibler pfatal_with_name (outname); 226*60240Shibler } 227*60240Shibler 228*60240Shibler #ifdef MAIL_USE_FLOCK 229*60240Shibler #if defined(STRIDE) || defined(XENIX) 230*60240Shibler /* Stride, xenix have file locking, but no ftruncate. This mess will do. */ 231*60240Shibler (void) close (open (inname, O_CREAT | O_TRUNC | O_RDWR, 0666)); 232*60240Shibler #else 233*60240Shibler (void) ftruncate (indesc, 0L); 234*60240Shibler #endif /* STRIDE or XENIX */ 235*60240Shibler #endif /* MAIL_USE_FLOCK */ 236*60240Shibler close (indesc); 237*60240Shibler 238*60240Shibler #ifndef MAIL_USE_FLOCK 239*60240Shibler /* Delete the input file; if we can't, at least get rid of its contents. */ 240*60240Shibler if (unlink (inname) < 0) 241*60240Shibler if (errno != ENOENT) 242*60240Shibler creat (inname, 0666); 243*60240Shibler (void) unlink (lockname); 244*60240Shibler #endif /* not MAIL_USE_FLOCK */ 245*60240Shibler exit (0); 246*60240Shibler } 247*60240Shibler 248*60240Shibler /* Print error message and exit. */ 249*60240Shibler 250*60240Shibler fatal (s1, s2) 251*60240Shibler char *s1, *s2; 252*60240Shibler { 253*60240Shibler if (delete_lockname) 254*60240Shibler unlink (delete_lockname); 255*60240Shibler error (s1, s2); 256*60240Shibler exit (1); 257*60240Shibler } 258*60240Shibler 259*60240Shibler /* Print error message. `s1' is printf control string, `s2' is arg for it. */ 260*60240Shibler 261*60240Shibler error (s1, s2, s3) 262*60240Shibler char *s1, *s2, *s3; 263*60240Shibler { 264*60240Shibler printf ("movemail: "); 265*60240Shibler printf (s1, s2, s3); 266*60240Shibler printf ("\n"); 267*60240Shibler } 268*60240Shibler 269*60240Shibler pfatal_with_name (name) 270*60240Shibler char *name; 271*60240Shibler { 272*60240Shibler extern int errno, sys_nerr; 273*60240Shibler extern char *sys_errlist[]; 274*60240Shibler char *s; 275*60240Shibler 276*60240Shibler if (errno < sys_nerr) 277*60240Shibler s = concat ("", sys_errlist[errno], " for %s"); 278*60240Shibler else 279*60240Shibler s = "cannot open %s"; 280*60240Shibler fatal (s, name); 281*60240Shibler } 282*60240Shibler 283*60240Shibler /* Return a newly-allocated string whose contents concatenate those of s1, s2, s3. */ 284*60240Shibler 285*60240Shibler char * 286*60240Shibler concat (s1, s2, s3) 287*60240Shibler char *s1, *s2, *s3; 288*60240Shibler { 289*60240Shibler int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3); 290*60240Shibler char *result = (char *) xmalloc (len1 + len2 + len3 + 1); 291*60240Shibler 292*60240Shibler strcpy (result, s1); 293*60240Shibler strcpy (result + len1, s2); 294*60240Shibler strcpy (result + len1 + len2, s3); 295*60240Shibler *(result + len1 + len2 + len3) = 0; 296*60240Shibler 297*60240Shibler return result; 298*60240Shibler } 299*60240Shibler 300*60240Shibler /* Like malloc but get fatal error if memory is exhausted. */ 301*60240Shibler 302*60240Shibler int 303*60240Shibler xmalloc (size) 304*60240Shibler int size; 305*60240Shibler { 306*60240Shibler int result = malloc (size); 307*60240Shibler if (!result) 308*60240Shibler fatal ("virtual memory exhausted", 0); 309*60240Shibler return result; 310*60240Shibler } 311*60240Shibler 312*60240Shibler /* This is the guts of the interface to the Post Office Protocol. */ 313*60240Shibler 314*60240Shibler #ifdef MAIL_USE_POP 315*60240Shibler 316*60240Shibler #include <sys/socket.h> 317*60240Shibler #include <netinet/in.h> 318*60240Shibler #include <netdb.h> 319*60240Shibler #include <stdio.h> 320*60240Shibler 321*60240Shibler #ifdef USG 322*60240Shibler #include <fcntl.h> 323*60240Shibler /* Cancel substitutions made by config.h for Emacs. */ 324*60240Shibler #undef open 325*60240Shibler #undef read 326*60240Shibler #undef write 327*60240Shibler #undef close 328*60240Shibler #endif /* USG */ 329*60240Shibler 330*60240Shibler #define NOTOK (-1) 331*60240Shibler #define OK 0 332*60240Shibler #define DONE 1 333*60240Shibler 334*60240Shibler char *progname; 335*60240Shibler FILE *sfi; 336*60240Shibler FILE *sfo; 337*60240Shibler char Errmsg[80]; 338*60240Shibler 339*60240Shibler static int debug = 0; 340*60240Shibler 341*60240Shibler popmail(user, outfile) 342*60240Shibler char *user; 343*60240Shibler char *outfile; 344*60240Shibler { 345*60240Shibler char *host; 346*60240Shibler int nmsgs, nbytes; 347*60240Shibler char response[128]; 348*60240Shibler register int i; 349*60240Shibler int mbfi; 350*60240Shibler FILE *mbf; 351*60240Shibler char *getenv(); 352*60240Shibler int mbx_write(); 353*60240Shibler char *get_errmsg(); 354*60240Shibler 355*60240Shibler host = getenv("MAILHOST"); 356*60240Shibler if (host == NULL) { 357*60240Shibler fatal("no MAILHOST defined"); 358*60240Shibler } 359*60240Shibler 360*60240Shibler if (pop_init(host) == NOTOK) { 361*60240Shibler error(Errmsg); 362*60240Shibler return(1); 363*60240Shibler } 364*60240Shibler 365*60240Shibler if (getline(response, sizeof response, sfi) != OK) { 366*60240Shibler error(response); 367*60240Shibler return(1); 368*60240Shibler } 369*60240Shibler 370*60240Shibler if (pop_command("USER %s", user) == NOTOK || 371*60240Shibler pop_command("RPOP %s", user) == NOTOK) { 372*60240Shibler error(Errmsg); 373*60240Shibler pop_command("QUIT"); 374*60240Shibler return(1); 375*60240Shibler } 376*60240Shibler 377*60240Shibler if (pop_stat(&nmsgs, &nbytes) == NOTOK) { 378*60240Shibler error(Errmsg); 379*60240Shibler pop_command("QUIT"); 380*60240Shibler return(1); 381*60240Shibler } 382*60240Shibler 383*60240Shibler if (!nmsgs) 384*60240Shibler { 385*60240Shibler pop_command("QUIT"); 386*60240Shibler return(0); 387*60240Shibler } 388*60240Shibler 389*60240Shibler mbfi = open (outfile, O_WRONLY | O_CREAT | O_EXCL, 0666); 390*60240Shibler if (mbfi < 0) 391*60240Shibler { 392*60240Shibler pop_command("QUIT"); 393*60240Shibler error("Error in open: %s, %s", get_errmsg(), outfile); 394*60240Shibler return(1); 395*60240Shibler } 396*60240Shibler fchown(mbfi, getuid(), -1); 397*60240Shibler 398*60240Shibler if ((mbf = fdopen(mbfi, "w")) == NULL) 399*60240Shibler { 400*60240Shibler pop_command("QUIT"); 401*60240Shibler error("Error in fdopen: %s", get_errmsg()); 402*60240Shibler close(mbfi); 403*60240Shibler unlink(outfile); 404*60240Shibler return(1); 405*60240Shibler } 406*60240Shibler 407*60240Shibler for (i = 1; i <= nmsgs; i++) { 408*60240Shibler mbx_delimit_begin(mbf); 409*60240Shibler if (pop_retr(i, mbx_write, mbf) != OK) { 410*60240Shibler error(Errmsg); 411*60240Shibler pop_command("QUIT"); 412*60240Shibler close(mbfi); 413*60240Shibler return(1); 414*60240Shibler } 415*60240Shibler mbx_delimit_end(mbf); 416*60240Shibler fflush(mbf); 417*60240Shibler } 418*60240Shibler 419*60240Shibler for (i = 1; i <= nmsgs; i++) { 420*60240Shibler if (pop_command("DELE %d", i) == NOTOK) { 421*60240Shibler error(Errmsg); 422*60240Shibler pop_command("QUIT"); 423*60240Shibler close(mbfi); 424*60240Shibler return(1); 425*60240Shibler } 426*60240Shibler } 427*60240Shibler 428*60240Shibler pop_command("QUIT"); 429*60240Shibler close(mbfi); 430*60240Shibler return(0); 431*60240Shibler } 432*60240Shibler 433*60240Shibler pop_init(host) 434*60240Shibler char *host; 435*60240Shibler { 436*60240Shibler register struct hostent *hp; 437*60240Shibler register struct servent *sp; 438*60240Shibler int lport = IPPORT_RESERVED - 1; 439*60240Shibler struct sockaddr_in sin; 440*60240Shibler register int s; 441*60240Shibler char *get_errmsg(); 442*60240Shibler 443*60240Shibler hp = gethostbyname(host); 444*60240Shibler if (hp == NULL) { 445*60240Shibler sprintf(Errmsg, "MAILHOST unknown: %s", host); 446*60240Shibler return(NOTOK); 447*60240Shibler } 448*60240Shibler 449*60240Shibler sp = getservbyname("pop", "tcp"); 450*60240Shibler if (sp == 0) { 451*60240Shibler strcpy(Errmsg, "tcp/pop: unknown service"); 452*60240Shibler return(NOTOK); 453*60240Shibler } 454*60240Shibler 455*60240Shibler sin.sin_family = hp->h_addrtype; 456*60240Shibler bcopy(hp->h_addr, (char *)&sin.sin_addr, hp->h_length); 457*60240Shibler sin.sin_port = sp->s_port; 458*60240Shibler s = rresvport(&lport); 459*60240Shibler if (s < 0) { 460*60240Shibler sprintf(Errmsg, "error creating socket: %s", get_errmsg()); 461*60240Shibler return(NOTOK); 462*60240Shibler } 463*60240Shibler 464*60240Shibler if (connect(s, (char *)&sin, sizeof sin) < 0) { 465*60240Shibler sprintf(Errmsg, "error during connect: %s", get_errmsg()); 466*60240Shibler close(s); 467*60240Shibler return(NOTOK); 468*60240Shibler } 469*60240Shibler 470*60240Shibler sfi = fdopen(s, "r"); 471*60240Shibler sfo = fdopen(s, "w"); 472*60240Shibler if (sfi == NULL || sfo == NULL) { 473*60240Shibler sprintf(Errmsg, "error in fdopen: %s", get_errmsg()); 474*60240Shibler close(s); 475*60240Shibler return(NOTOK); 476*60240Shibler } 477*60240Shibler 478*60240Shibler return(OK); 479*60240Shibler } 480*60240Shibler 481*60240Shibler pop_command(fmt, a, b, c, d) 482*60240Shibler char *fmt; 483*60240Shibler { 484*60240Shibler char buf[128]; 485*60240Shibler char errmsg[64]; 486*60240Shibler 487*60240Shibler sprintf(buf, fmt, a, b, c, d); 488*60240Shibler 489*60240Shibler if (debug) fprintf(stderr, "---> %s\n", buf); 490*60240Shibler if (putline(buf, Errmsg, sfo) == NOTOK) return(NOTOK); 491*60240Shibler 492*60240Shibler if (getline(buf, sizeof buf, sfi) != OK) { 493*60240Shibler strcpy(Errmsg, buf); 494*60240Shibler return(NOTOK); 495*60240Shibler } 496*60240Shibler 497*60240Shibler if (debug) fprintf(stderr, "<--- %s\n", buf); 498*60240Shibler if (*buf != '+') { 499*60240Shibler strcpy(Errmsg, buf); 500*60240Shibler return(NOTOK); 501*60240Shibler } else { 502*60240Shibler return(OK); 503*60240Shibler } 504*60240Shibler } 505*60240Shibler 506*60240Shibler 507*60240Shibler pop_stat(nmsgs, nbytes) 508*60240Shibler int *nmsgs, *nbytes; 509*60240Shibler { 510*60240Shibler char buf[128]; 511*60240Shibler 512*60240Shibler if (debug) fprintf(stderr, "---> STAT\n"); 513*60240Shibler if (putline("STAT", Errmsg, sfo) == NOTOK) return(NOTOK); 514*60240Shibler 515*60240Shibler if (getline(buf, sizeof buf, sfi) != OK) { 516*60240Shibler strcpy(Errmsg, buf); 517*60240Shibler return(NOTOK); 518*60240Shibler } 519*60240Shibler 520*60240Shibler if (debug) fprintf(stderr, "<--- %s\n", buf); 521*60240Shibler if (*buf != '+') { 522*60240Shibler strcpy(Errmsg, buf); 523*60240Shibler return(NOTOK); 524*60240Shibler } else { 525*60240Shibler sscanf(buf, "+OK %d %d", nmsgs, nbytes); 526*60240Shibler return(OK); 527*60240Shibler } 528*60240Shibler } 529*60240Shibler 530*60240Shibler pop_retr(msgno, action, arg) 531*60240Shibler int (*action)(); 532*60240Shibler { 533*60240Shibler char buf[128]; 534*60240Shibler 535*60240Shibler sprintf(buf, "RETR %d", msgno); 536*60240Shibler if (debug) fprintf(stderr, "%s\n", buf); 537*60240Shibler if (putline(buf, Errmsg, sfo) == NOTOK) return(NOTOK); 538*60240Shibler 539*60240Shibler if (getline(buf, sizeof buf, sfi) != OK) { 540*60240Shibler strcpy(Errmsg, buf); 541*60240Shibler return(NOTOK); 542*60240Shibler } 543*60240Shibler 544*60240Shibler while (1) { 545*60240Shibler switch (multiline(buf, sizeof buf, sfi)) { 546*60240Shibler case OK: 547*60240Shibler (*action)(buf, arg); 548*60240Shibler break; 549*60240Shibler case DONE: 550*60240Shibler return (OK); 551*60240Shibler case NOTOK: 552*60240Shibler strcpy(Errmsg, buf); 553*60240Shibler return (NOTOK); 554*60240Shibler } 555*60240Shibler } 556*60240Shibler } 557*60240Shibler 558*60240Shibler getline(buf, n, f) 559*60240Shibler char *buf; 560*60240Shibler register int n; 561*60240Shibler FILE *f; 562*60240Shibler { 563*60240Shibler register char *p; 564*60240Shibler int c; 565*60240Shibler 566*60240Shibler p = buf; 567*60240Shibler while (--n > 0 && (c = fgetc(f)) != EOF) 568*60240Shibler if ((*p++ = c) == '\n') break; 569*60240Shibler 570*60240Shibler if (ferror(f)) { 571*60240Shibler strcpy(buf, "error on connection"); 572*60240Shibler return (NOTOK); 573*60240Shibler } 574*60240Shibler 575*60240Shibler if (c == EOF && p == buf) { 576*60240Shibler strcpy(buf, "connection closed by foreign host"); 577*60240Shibler return (DONE); 578*60240Shibler } 579*60240Shibler 580*60240Shibler *p = NULL; 581*60240Shibler if (*--p == '\n') *p = NULL; 582*60240Shibler if (*--p == '\r') *p = NULL; 583*60240Shibler return(OK); 584*60240Shibler } 585*60240Shibler 586*60240Shibler multiline(buf, n, f) 587*60240Shibler char *buf; 588*60240Shibler register int n; 589*60240Shibler FILE *f; 590*60240Shibler { 591*60240Shibler if (getline(buf, n, f) != OK) return (NOTOK); 592*60240Shibler if (*buf == '.') { 593*60240Shibler if (*(buf+1) == NULL) { 594*60240Shibler return (DONE); 595*60240Shibler } else { 596*60240Shibler strcpy(buf, buf+1); 597*60240Shibler } 598*60240Shibler } 599*60240Shibler return(OK); 600*60240Shibler } 601*60240Shibler 602*60240Shibler char * 603*60240Shibler get_errmsg() 604*60240Shibler { 605*60240Shibler extern int errno, sys_nerr; 606*60240Shibler extern char *sys_errlist[]; 607*60240Shibler char *s; 608*60240Shibler 609*60240Shibler if (errno < sys_nerr) 610*60240Shibler s = sys_errlist[errno]; 611*60240Shibler else 612*60240Shibler s = "unknown error"; 613*60240Shibler return(s); 614*60240Shibler } 615*60240Shibler 616*60240Shibler putline(buf, err, f) 617*60240Shibler char *buf; 618*60240Shibler char *err; 619*60240Shibler FILE *f; 620*60240Shibler { 621*60240Shibler fprintf(f, "%s\r\n", buf); 622*60240Shibler fflush(f); 623*60240Shibler if (ferror(f)) { 624*60240Shibler strcpy(err, "lost connection"); 625*60240Shibler return(NOTOK); 626*60240Shibler } 627*60240Shibler return(OK); 628*60240Shibler } 629*60240Shibler 630*60240Shibler mbx_write(line, mbf) 631*60240Shibler char *line; 632*60240Shibler FILE *mbf; 633*60240Shibler { 634*60240Shibler fputs(line, mbf); 635*60240Shibler fputc(0x0a, mbf); 636*60240Shibler } 637*60240Shibler 638*60240Shibler mbx_delimit_begin(mbf) 639*60240Shibler FILE *mbf; 640*60240Shibler { 641*60240Shibler fputs("\f\n0, unseen,,\n", mbf); 642*60240Shibler } 643*60240Shibler 644*60240Shibler mbx_delimit_end(mbf) 645*60240Shibler FILE *mbf; 646*60240Shibler { 647*60240Shibler putc('\037', mbf); 648*60240Shibler } 649*60240Shibler 650*60240Shibler #endif /* MAIL_USE_POP */ 651