⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 movemail.c

📁 早期freebsd实现
💻 C
字号:
/* movemail foo bar -- move file foo to file bar,   locking file foo the way /bin/mail respects.   Copyright (C) 1986 Free Software Foundation, Inc.This file is part of GNU Emacs.GNU Emacs is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 1, or (at your option)any later version.GNU Emacs is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with GNU Emacs; see the file COPYING.  If not, write tothe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  *//* * Modified January, 1986 by Michael R. Gretzinger (Project Athena) * * Added POP (Post Office Protocol) service.  When compiled -DPOP * movemail will accept input filename arguments of the form * "po:username".  This will cause movemail to open a connection to * a pop server running on $MAILHOST (environment variable).  Movemail * must be setuid to root in order to work with POP. *  * New module: popmail.c * Modified routines: *	main - added code within #ifdef MAIL_USE_POP; added setuid(getuid()) *		after POP code.  * New routines in movemail.c: *	get_errmsg - return pointer to system error message * */#include <sys/types.h>#include <sys/stat.h>#include <sys/file.h>#include <errno.h>#include <unistd.h>#define NO_SHORTNAMES   /* Tell config not to load remap.h */#include "../src/config.h"#ifdef USG#include <fcntl.h>#include <unistd.h>#ifndef F_OK#define F_OK 0#define X_OK 1#define W_OK 2#define R_OK 4#endif#endif /* USG */#ifdef XENIX#include <sys/locking.h>#endif/* Cancel substitutions made by config.h for Emacs.  */#undef open#undef read#undef write#undef closechar *concat ();extern int errno;/* Nonzero means this is name of a lock file to delete on fatal error.  */char *delete_lockname;main (argc, argv)     int argc;     char **argv;{  char *inname, *outname;  int indesc, outdesc;  char buf[1024];  int nread;#ifndef MAIL_USE_FLOCK  struct stat st;  long now;  int tem;  char *lockname, *p;  char tempname[40];  int desc;#endif /* not MAIL_USE_FLOCK */  delete_lockname = 0;  if (argc < 3)    fatal ("two arguments required");  inname = argv[1];  outname = argv[2];  /* Check access to output file.  */  if (access (outname, F_OK) == 0 && access (outname, W_OK) != 0)    pfatal_with_name (outname);  /* Also check that outname's directory is writeable to the real uid.  */  {    char *buf = (char *) malloc (strlen (outname) + 1);    char *p, q;    strcpy (buf, outname);    p = buf + strlen (buf);    while (p > buf && p[-1] != '/')      *--p = 0;    if (p == buf)      *p++ = '.';    if (access (buf, W_OK) != 0)      pfatal_with_name (buf);    free (buf);  }#ifdef MAIL_USE_POP  if (!bcmp (inname, "po:", 3))    {      int status; char *user;      user = (char *) rindex (inname, ':') + 1;      status = popmail (user, outname);      exit (status);    }  setuid (getuid());#endif /* MAIL_USE_POP */  /* Check access to input file.  */  if (access (inname, R_OK | W_OK) != 0)    pfatal_with_name (inname);#ifndef MAIL_USE_FLOCK  /* Use a lock file named /usr/spool/mail/$USER.lock:     If it exists, the mail file is locked.  */  lockname = concat (inname, ".lock", "");  strcpy (tempname, inname);  p = tempname + strlen (tempname);  while (p != tempname && p[-1] != '/')    p--;  *p = 0;  strcpy (p, "EXXXXXX");  mktemp (tempname);  (void) unlink (tempname);  while (1)    {      /* Create the lock file, but not under the lock file name.  */      /* Give up if cannot do that.  */      desc = open (tempname, O_WRONLY | O_CREAT, 0666);      if (desc < 0)        pfatal_with_name (concat ("temporary file \"", tempname, "\""));      close (desc);      tem = link (tempname, lockname);      (void) unlink (tempname);      if (tem >= 0)	break;      sleep (1);      /* If lock file is a minute old, unlock it.  */      if (stat (lockname, &st) >= 0)	{	  now = time (0);	  if (st.st_ctime < now - 60)	    (void) unlink (lockname);	}    }  delete_lockname = lockname;#endif /* not MAIL_USE_FLOCK */#ifdef MAIL_USE_FLOCK  indesc = open (inname, O_RDWR);#else /* if not MAIL_USE_FLOCK */  indesc = open (inname, O_RDONLY);#endif /* not MAIL_USE_FLOCK */  if (indesc < 0)    pfatal_with_name (inname);#if defined(BSD) || defined(XENIX)  /* In case movemail is setuid to root, make sure the user can     read the output file.  */  /* This is desirable for all systems     but I don't want to assume all have the umask system call */  umask (umask (0) & 0333);#endif /* BSD or Xenix */  outdesc = open (outname, O_WRONLY | O_CREAT | O_EXCL, 0666);  if (outdesc < 0)    pfatal_with_name (outname);#ifdef MAIL_USE_FLOCK#ifdef XENIX  if (locking (indesc, LK_RLCK, 0L) < 0) pfatal_with_name (inname);#else  flock (indesc, LOCK_EX);#endif#endif /* MAIL_USE_FLOCK */  while (1)    {      nread = read (indesc, buf, sizeof buf);      if (nread != write (outdesc, buf, nread))	{	  int saved_errno = errno;	  (void) unlink (outname);	  errno = saved_errno;	  pfatal_with_name (outname);	}      if (nread < sizeof buf)	break;    }#ifdef BSD  fsync (outdesc);#endif  /* Check to make sure no errors before we zap the inbox.  */  if (close (outdesc) != 0)    {      int saved_errno = errno;      (void) unlink (outname);      errno = saved_errno;      pfatal_with_name (outname);  }#ifdef MAIL_USE_FLOCK#if defined(STRIDE) || defined(XENIX)  /* Stride, xenix have file locking, but no ftruncate.  This mess will do. */  (void) close (open (inname, O_CREAT | O_TRUNC | O_RDWR, 0666));#else  (void) ftruncate (indesc, (off_t)0);#endif /* STRIDE or XENIX */#endif /* MAIL_USE_FLOCK */  close (indesc);#ifndef MAIL_USE_FLOCK  /* Delete the input file; if we can't, at least get rid of its contents.  */  if (unlink (inname) < 0)    if (errno != ENOENT)      creat (inname, 0666);  (void) unlink (lockname);#endif /* not MAIL_USE_FLOCK */  exit (0);}/* Print error message and exit.  */fatal (s1, s2)     char *s1, *s2;{  if (delete_lockname)    unlink (delete_lockname);  error (s1, s2);  exit (1);}/* Print error message.  `s1' is printf control string, `s2' is arg for it. */error (s1, s2, s3)     char *s1, *s2, *s3;{  printf ("movemail: ");  printf (s1, s2, s3);  printf ("\n");}pfatal_with_name (name)     char *name;{  extern int errno, sys_nerr;  extern char *sys_errlist[];  char *s;  if (errno < sys_nerr)    s = concat ("", sys_errlist[errno], " for %s");  else    s = "cannot open %s";  fatal (s, name);}/* Return a newly-allocated string whose contents concatenate those of s1, s2, s3.  */char *concat (s1, s2, s3)     char *s1, *s2, *s3;{  int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);  char *result = (char *) xmalloc (len1 + len2 + len3 + 1);  strcpy (result, s1);  strcpy (result + len1, s2);  strcpy (result + len1 + len2, s3);  *(result + len1 + len2 + len3) = 0;  return result;}/* Like malloc but get fatal error if memory is exhausted.  */intxmalloc (size)     int size;{  int result = malloc (size);  if (!result)    fatal ("virtual memory exhausted", 0);  return result;}/* This is the guts of the interface to the Post Office Protocol.  */#ifdef MAIL_USE_POP#include <sys/socket.h>#include <netinet/in.h>#include <netdb.h>#include <stdio.h>#ifdef USG#include <fcntl.h>/* Cancel substitutions made by config.h for Emacs.  */#undef open#undef read#undef write#undef close#endif /* USG */#define NOTOK (-1)#define OK 0#define DONE 1char *progname;FILE *sfi;FILE *sfo;char Errmsg[80];static int debug = 0;popmail(user, outfile)char *user;char *outfile;{    char *host;    int nmsgs, nbytes;    char response[128];    register int i;    int mbfi;    FILE *mbf;    char *getenv();    int mbx_write();    char *get_errmsg();    host = getenv("MAILHOST");    if (host == NULL) {	fatal("no MAILHOST defined");    }    if (pop_init(host) == NOTOK) {	error(Errmsg);	return(1);    }    if (getline(response, sizeof response, sfi) != OK) {	error(response);	return(1);    }    if (pop_command("USER %s", user) == NOTOK || 	pop_command("RPOP %s", user) == NOTOK) {	error(Errmsg);	pop_command("QUIT");	return(1);    }    if (pop_stat(&nmsgs, &nbytes) == NOTOK) {	error(Errmsg);	pop_command("QUIT");	return(1);    }    if (!nmsgs)      {	pop_command("QUIT");	return(0);      }    mbfi = open (outfile, O_WRONLY | O_CREAT | O_EXCL, 0666);    if (mbfi < 0)      {	pop_command("QUIT");	error("Error in open: %s, %s", get_errmsg(), outfile);	return(1);      }    fchown(mbfi, getuid(), -1);    if ((mbf = fdopen(mbfi, "w")) == NULL)      {	pop_command("QUIT");	error("Error in fdopen: %s", get_errmsg());	close(mbfi);	unlink(outfile);	return(1);      }    for (i = 1; i <= nmsgs; i++) {	mbx_delimit_begin(mbf);	if (pop_retr(i, mbx_write, mbf) != OK) {	    error(Errmsg);	    pop_command("QUIT");	    close(mbfi);	    return(1);	}	mbx_delimit_end(mbf);	fflush(mbf);    }    for (i = 1; i <= nmsgs; i++) {	if (pop_command("DELE %d", i) == NOTOK) {	    error(Errmsg);	    pop_command("QUIT");	    close(mbfi);	    return(1);	}    }    pop_command("QUIT");    close(mbfi);    return(0);}pop_init(host)char *host;{    register struct hostent *hp;    register struct servent *sp;    int lport = IPPORT_RESERVED - 1;    struct sockaddr_in sin;    register int s;    char *get_errmsg();    hp = gethostbyname(host);    if (hp == NULL) {	sprintf(Errmsg, "MAILHOST unknown: %s", host);	return(NOTOK);    }    sp = getservbyname("pop", "tcp");    if (sp == 0) {	strcpy(Errmsg, "tcp/pop: unknown service");	return(NOTOK);    }    sin.sin_family = hp->h_addrtype;    bcopy(hp->h_addr, (char *)&sin.sin_addr, hp->h_length);    sin.sin_port = sp->s_port;    s = rresvport(&lport);    if (s < 0) {	sprintf(Errmsg, "error creating socket: %s", get_errmsg());	return(NOTOK);    }    if (connect(s, (char *)&sin, sizeof sin) < 0) {	sprintf(Errmsg, "error during connect: %s", get_errmsg());	close(s);	return(NOTOK);    }    sfi = fdopen(s, "r");    sfo = fdopen(s, "w");    if (sfi == NULL || sfo == NULL) {	sprintf(Errmsg, "error in fdopen: %s", get_errmsg());	close(s);	return(NOTOK);    }    return(OK);}pop_command(fmt, a, b, c, d)char *fmt;{    char buf[128];    char errmsg[64];    sprintf(buf, fmt, a, b, c, d);    if (debug) fprintf(stderr, "---> %s\n", buf);    if (putline(buf, Errmsg, sfo) == NOTOK) return(NOTOK);    if (getline(buf, sizeof buf, sfi) != OK) {	strcpy(Errmsg, buf);	return(NOTOK);    }    if (debug) fprintf(stderr, "<--- %s\n", buf);    if (*buf != '+') {	strcpy(Errmsg, buf);	return(NOTOK);    } else {	return(OK);    }}    pop_stat(nmsgs, nbytes)int *nmsgs, *nbytes;{    char buf[128];    if (debug) fprintf(stderr, "---> STAT\n");    if (putline("STAT", Errmsg, sfo) == NOTOK) return(NOTOK);    if (getline(buf, sizeof buf, sfi) != OK) {	strcpy(Errmsg, buf);	return(NOTOK);    }    if (debug) fprintf(stderr, "<--- %s\n", buf);    if (*buf != '+') {	strcpy(Errmsg, buf);	return(NOTOK);    } else {	sscanf(buf, "+OK %d %d", nmsgs, nbytes);	return(OK);    }}pop_retr(msgno, action, arg)int (*action)();{    char buf[128];    sprintf(buf, "RETR %d", msgno);    if (debug) fprintf(stderr, "%s\n", buf);    if (putline(buf, Errmsg, sfo) == NOTOK) return(NOTOK);    if (getline(buf, sizeof buf, sfi) != OK) {	strcpy(Errmsg, buf);	return(NOTOK);    }    while (1) {	switch (multiline(buf, sizeof buf, sfi)) {	case OK:	    (*action)(buf, arg);	    break;	case DONE:	    return (OK);	case NOTOK:	    strcpy(Errmsg, buf);	    return (NOTOK);	}    }}getline(buf, n, f)char *buf;register int n;FILE *f;{    register char *p;    int c;    p = buf;    while (--n > 0 && (c = fgetc(f)) != EOF)      if ((*p++ = c) == '\n') break;    if (ferror(f)) {	strcpy(buf, "error on connection");	return (NOTOK);    }    if (c == EOF && p == buf) {	strcpy(buf, "connection closed by foreign host");	return (DONE);    }    *p = NULL;    if (*--p == '\n') *p = NULL;    if (*--p == '\r') *p = NULL;    return(OK);}multiline(buf, n, f)char *buf;register int n;FILE *f;{    if (getline(buf, n, f) != OK) return (NOTOK);    if (*buf == '.') {	if (*(buf+1) == NULL) {	    return (DONE);	} else {	    strcpy(buf, buf+1);	}    }    return(OK);}char *get_errmsg(){    extern int errno, sys_nerr;    extern char *sys_errlist[];    char *s;    if (errno < sys_nerr)      s = sys_errlist[errno];    else      s = "unknown error";    return(s);}putline(buf, err, f)char *buf;char *err;FILE *f;{    fprintf(f, "%s\r\n", buf);    fflush(f);    if (ferror(f)) {	strcpy(err, "lost connection");	return(NOTOK);    }    return(OK);}mbx_write(line, mbf)char *line;FILE *mbf;{    fputs(line, mbf);    fputc(0x0a, mbf);}mbx_delimit_begin(mbf)FILE *mbf;{    fputs("\f\n0, unseen,,\n", mbf);}mbx_delimit_end(mbf)FILE *mbf;{    putc('\037', mbf);}#endif /* MAIL_USE_POP */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -