home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 January
/
usenetsourcesnewsgroupsinfomagicjanuary1994.iso
/
sources
/
misc
/
volume32
/
mush
/
patch05c
< prev
next >
Wrap
Text File
|
1992-10-18
|
41KB
|
1,647 lines
Newsgroups: comp.sources.misc
From: bart@zigzag.z-code.com (Bart Schaefer)
Subject: v32i103: mush - Mail User's Shell, Patch05c/3
Message-ID: <1992Oct16.141355.6946@sparky.imd.sterling.com>
X-Md4-Signature: a106ba48c83eda60dc3249295e5224a4
Date: Fri, 16 Oct 1992 14:13:55 GMT
Approved: kent@sparky.imd.sterling.com
Submitted-by: bart@zigzag.z-code.com (Bart Schaefer)
Posting-number: Volume 32, Issue 103
Archive-name: mush/patch05c
Environment: UNIX
Patch-To: mush: Volume 18, Issue 58-79
This is Part 03 of Official Patch #5 for Mush 7.2. This is a shar of new
files in the Mush 7.2 distribution, NOT a diff. DO NOT feed this file to
patch! Save this message to a file in your mush source directory and
extract the contents with:
sh file
You don't actually need any of these files unless you are using DOT_LOCK
or POP3_SUPPORT. See README.
#!/bin/sh
# shar: Shell Archiver (v1.22+)
#
# Run the following text with /bin/sh to create:
# README-7.2.5
# pop.h
# pop.c
# pmush.c
# xcreat.c
#
echo "x - extracting README-7.2.5 (Text)"
sed 's/^X//' << 'SHAR_EOF' > README-7.2.5 &&
X
XThis is release 7.2.5 of the Mail User's Shell (mush).
X
XMush was last posted as a complete package at release 7.2.2. Before that,
Xthe last complete posting was 7.1.1. If your version of mush is older
Xthan 7.2.2, refer to README-7.0 and README-7.1 for lists of other changes.
XSee README-7.2.0 for changes from 7.1.1 to 7.2. Patch 3 was bugfixes only;
Xthere was no README-7.2.3. See README-7.2.4 for a list of changes in both
Xpatch 3 and patch 4.
X
XChanges in compilation:
X
X POP3_SUPPORT
X Enable POP client mode by compiling with this defined. See README.
X
X New files to support POP and DOT_LOCK have been added to the makefiles.
X
XNew/changed commands:
X
X See the $metamail variable for changes in print/type/etc.
X
XNew/changed variables:
X
X metamail
X If $metamail is set to the pathname (and arguments) of a MIME
X decoder (such as the "metamail" program), Mush will recognize
X MIME messages and "page" them through that decoder instead of
X through the regular $pager.
X
XTool mode changes:
X
X Bug fixes only, see below.
X
XBugs fixed in Patch #5:
X
X * Better parsing of double-quoted tokens in addresses
X
X * Unsetenv allocates a new copy of the environment on first call
X
X * Doesn't attempt to init tty if there isn't one
X
X * #define CURSES in config.h (as opposed to in CFLAGS) should work
X
X * On AIX, curses mode won't dump core
X
X * Recognize more date formats, and store dates to resolution in seconds
X for more accurate date sorting
X
X * Tool mode "sort" menu "by value of sort variable" works now
X
X * Better handling of X.400 addresses (heuristic for distinguishing them
X from file names has been improved)
X
X * Tool mode "save" pullright directory-walking menus work in all contexts
X (I hope)
X
X * Moved that silly piece of code that was setting $realname to the
X spool folder path
X
X * Code to init all hostname aliases for $hostname finally works right in
X all cases
X
X * Many improvements to DOT_LOCK; NFS "secure" lockfile creation
X
X * ~user/$variable parses correctly and expands $variable
X
X * Some compilation fixes for SGI IRIX
X
X * Child-process management for pager process improved
X
X * Support for POSIX_UTIME fixed
X
X * "saveopts" of variables, aliases, etc. with embedded quotes of mixed
X types does appropriate quoting of its output
SHAR_EOF
chmod 0644 README-7.2.5 || echo "restore of README-7.2.5 fails"
set `wc -c README-7.2.5`;Sum=$1
if test "$Sum" != "2290"
then echo original size 2290, current size $Sum;fi
echo "x - extracting pop.h (Text)"
sed 's/^X//' << 'SHAR_EOF' > pop.h &&
X/*
X * pop.h: Header file for the "pop.c" client POP3 protocol
X * implementation.
X */
X
X#ifdef POP3_SUPPORT
X
X#include <stdio.h>
X
X#define GETLINE_MAX 1024 /* a pretty arbitrary value */
X
Xextern char pop_error[];
Xextern int pop_debug;
X
Xtypedef struct _PopServer {
X int file, data;
X char buffer[GETLINE_MAX], *dp;
X} *PopServer;
X
X/*
X * Valid flags for the pop_open function.
X */
X
X#define POP_NO_KERBEROS (1<<0)
X#define POP_NO_HESIOD (1<<1)
X#define POP_NO_GETPASS (1<<2)
X
Xextern PopServer pop_open();
Xextern int pop_stat();
Xextern int pop_list();
Xextern char *pop_retrieve();
Xextern int pop_delete();
Xextern int pop_noop();
Xextern int pop_last();
Xextern int pop_reset();
Xextern int pop_quit();
Xextern void pop_close();
X
X#endif /* POP3_SUPPORT */
SHAR_EOF
chmod 0644 pop.h || echo "restore of pop.h fails"
set `wc -c pop.h`;Sum=$1
if test "$Sum" != "748"
then echo original size 748, current size $Sum;fi
echo "x - extracting pop.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > pop.c &&
X/*
X * pop.c: client routines for talking to a POP3-protocol post-office
X * server
X *
X * Jonathan Kamens
X * August 13, 1991
X */
X
X#ifdef POP3_SUPPORT
X
X#include <sys/types.h>
X#include <netinet/in.h>
X#include <sys/socket.h>
X#include "pop.h"
X
Xextern int errno;
X
X#ifdef KERBEROS
X#include <krb.h>
X#include <des.h>
X#ifdef sun
X#include <malloc.h>
X#else /* !sun */
Xextern char *
Xmalloc( /* unsigned */ );
Xextern void
Xfree( /* char * */ );
X#endif /* sun */
X#endif /* KERBEROS */
X
X#ifdef HESIOD
X#include <hesiod.h>
X/*
X * It really shouldn't be necessary to put this declaration here, but
X * the version of hesiod.h that Athena has installed in release 7.2
X * doesn't declare this function; I don't know if the 7.3 version of
X * hesiod.h does.
X */
Xextern struct servent *
Xhes_getservbyname( /* char *, char * */ );
X#endif /* HESIOD */
X
X#include <pwd.h>
X#include <string.h>
X#include <strings.h>
X
Xextern char *
Xstrstr( /* char *, char * */ );
X
X#include <netdb.h>
X#include <errno.h>
X#include <stdio.h>
X
Xextern char *sys_errlist[];
X#define strerror(eno) sys_errlist[eno]
X
Xextern char *
Xgetenv( /* char * */ );
Xextern char *
Xgetlogin( /* void */ );
Xextern char *
Xgetpass( /* char * */ );
Xextern int
Xgetuid( /* void */ );
Xextern void
Xbzero( /* char *, int */ ), bcopy( /* char *, char *, int */ );
Xextern int
Xsocket( /* int, int, int */ );
Xextern int
Xconnect( /* int, struct sockaddr *, int */ );
Xextern int
Xclose( /* int */ );
Xextern int
Xread( /* int, char *, int */ ), write( /* int, char *, int */ );
Xextern int
Xatoi( /* char * */ );
X
X#if !(defined(vax) && defined(__GNUC__))
Xextern int
Xfprintf( /* FILE *, char *, ... */ );
X#endif /* !(vax && __GNUC__) */
X
X#ifdef KERBEROS
Xextern int
Xkrb_sendauth( /* long, int, KTEXT, char *, char *, char *, u_long, MSG_DAT **,
X CREDENTIALS *, Key_schedule, struct sockaddr_in *,
X struct sockaddr_in *, char * */ );
Xextern char *
Xkrb_realmofhost( /* char * */ );
X#endif /* KERBEROS */
X
Xextern int h_errno;
X
Xstatic int socket_connection();
Xstatic char *getline();
Xstatic int sendline();
Xstatic int fullwrite();
Xstatic int getok();
Xstatic int gettermination();
X
X#define ERROR_MAX 80 /* a pretty arbitrary size */
X#define POP_PORT 110
X#define KPOP_PORT 1109
X#define POP_SERVICE "pop"
X#define KPOP_SERVICE "kpop"
X
Xchar pop_error[ERROR_MAX];
Xint pop_debug = 0;
X
X/*
X * Function: pop_open(char *host, char *username, char *password,
X * int flags)
X *
X * Purpose: Establishes a connection with a post-office server, and
X * completes the authorization portion of the session.
X *
X * Arguments:
X * host The server host with which the connection should be
X * established. Optional. If omitted, internal
X * heuristics will be used to determine the server host,
X * if possible.
X * username
X * The username of the mail-drop to access. Optional.
X * If omitted, internal heuristics will be used to
X * determine the username, if possible.
X * password
X * The password to use for authorization. If omitted,
X * internal heuristics will be used to determine the
X * password, if possible.
X * flags A bit mask containing flags controlling certain
X * functions of the routine. Valid flags are defined in
X * the file pop.h
X *
X * Return value: Upon successful establishment of a connection, a
X * non-null PopServer will be returned. Otherwise, null will be
X * returned, and the string variable pop_error will contain an
X * explanation of the error.
X */
XPopServer
Xpop_open(host, username, password, flags)
Xchar *host, *username, *password;
Xint flags;
X{
X int sock;
X PopServer server;
X
X /* Determine the user name */
X if (!username) {
X username = getenv("USER");
X if (!(username && *username)) {
X username = getlogin();
X if (!(username && *username)) {
X struct passwd *passwd;
X
X passwd = getpwuid(getuid());
X if (passwd && passwd->pw_name && *passwd->pw_name) {
X username = passwd->pw_name;
X } else {
X strcpy(pop_error, "Could not determine username");
X return (0);
X }
X }
X }
X }
X /* Determine the mail host */
X#ifdef HESIOD
X if ((!host) && (!(flags & POP_NO_HESIOD))) {
X struct hes_postoffice *office;
X
X office = hes_getmailhost(username);
X if (office && office->po_type && (!strcmp(office->po_type, "POP"))
X && office->po_name && *office->po_name && office->po_host
X && *office->po_host) {
X host = office->po_host;
X username = office->po_name;
X }
X }
X#endif
X if (!host) {
X host = getenv("MAILHOST");
X if (!host) {
X strcpy(pop_error, "Could not determine POP server");
X return (0);
X }
X }
X /* Determine the password */
X#ifdef KERBEROS
X#define DONT_NEED_PASSWORD (! (flags & POP_NO_KERBEROS))
X#else
X#define DONT_NEED_PASSWORD 0
X#endif
X
X /* Modified to return password if possible -- Bart */
X if ((!password || !*password) && (!DONT_NEED_PASSWORD)) {
X if (!(flags & POP_NO_GETPASS)) {
X char *p = getpass("Enter POP password:");
X if (p && password)
X (void) strcpy(password, p);
X password = p;
X }
X if (!password) {
X strcpy(pop_error, "Could not determine POP password");
X return (0);
X }
X }
X if (password)
X flags |= POP_NO_KERBEROS;
X else
X password = username;
X
X sock = socket_connection(host, flags);
X if (sock == -1)
X return (0);
X
X server = (PopServer) malloc(sizeof(struct _PopServer));
X if (!server) {
X strcpy(pop_error, "Out of memory in pop_open");
X return (0);
X }
X server->file = sock;
X server->data = 0;
X server->dp = server->buffer;
X
X if (getok(server))
X return (0);
X
X /*
X * I really shouldn't use the pop_error variable like this, but....
X */
X if (strlen(username) > ERROR_MAX - 6) {
X pop_close(server);
X strcpy(pop_error,
X "Username too long; recompile pop.c with larger ERROR_MAX");
X return (0);
X }
X sprintf(pop_error, "USER %s", username);
X
X if (sendline(server, pop_error) || getok(server)) {
X return (0);
X }
X if (strlen(password) > ERROR_MAX - 6) {
X pop_close(server);
X strcpy(pop_error,
X "Password too long; recompile pop.c with larger ERROR_MAX");
X return (0);
X }
X sprintf(pop_error, "PASS %s", password);
X
X if (sendline(server, pop_error) || getok(server)) {
X return (0);
X }
X return (server);
X}
X
X/*
X * Function: pop_stat
X *
X * Purpose: Issue the STAT command to the server and return (in the
X * value parameters) the number of messages in the maildrop and
X * the total size of the maildrop.
X *
X * Return value: 0 on success, or non-zero with an error in pop_error
X * in failure.
X *
X * Side effects: Closes the connection on failure.
X */
Xint
Xpop_stat(server, count, size)
XPopServer server;
Xint *count, *size;
X{
X char *fromserver;
X
X if (sendline(server, "STAT") || (!(fromserver = getline(server))))
X return (-1);
X
X if (strncmp(fromserver, "+OK ", 4)) {
X strcpy(pop_error, "Unexpected response from POP server in pop_stat");
X pop_close();
X return (-1);
X }
X *count = atoi(&fromserver[4]);
X
X fromserver = index(&fromserver[4], ' ');
X if (!fromserver) {
X strcpy(pop_error,
X "Badly formatted response from server in pop_stat");
X pop_close(server);
X return (-1);
X }
X *size = atoi(fromserver + 1);
X
X return (0);
X}
X
X/*
X * Function: pop_list
X *
X * Purpose: Performs the POP "list" command and returns (in value
X * parameters) two malloc'd zero-terminated arrays -- one of
X * message IDs, and a parallel one of sizes.
X *
X * Arguments:
X * server The pop connection to talk to.
X * message The number of the one message about which to get
X * information, or 0 to get information about all
X * messages.
X *
X * Return value: 0 on success, non-zero with error in pop_error on
X * failure.
X *
X * Side effects: Closes the connection on error.
X */
Xint
Xpop_list(server, message, IDs, sizes)
XPopServer server;
Xint message, **IDs, **sizes;
X{
X int how_many, i;
X char *fromserver;
X
X if (message)
X how_many = 1;
X else {
X int count, size;
X
X if (pop_stat(server, &count, &size))
X return (-1);
X how_many = count;
X }
X
X *IDs = (int *) malloc((how_many + 1) * sizeof(int));
X *sizes = (int *) malloc((how_many + 1) * sizeof(int));
X if (!(*IDs && *sizes)) {
X strcpy(pop_error, "Out of memory in pop_list");
X pop_close(server);
X return (-1);
X }
X if (message) {
X sprintf(pop_error, "LIST %d", message);
X if (sendline(server, pop_error)) {
X free((char *) *IDs);
X free((char *) *sizes);
X return (-1);
X }
X if (!(fromserver = getline(server))) {
X free((char *) *IDs);
X free((char *) *sizes);
X return (-1);
X }
X if (strncmp(fromserver, "+OK ", 4)) {
X if (!strncmp(fromserver, "-ERR", 4))
X strncpy(pop_error, fromserver, ERROR_MAX);
X else
X strcpy(pop_error,
X "Unexpected response from server in pop_list");
X free((char *) *IDs);
X free((char *) *sizes);
X pop_close(server);
X return (-1);
X }
X (*IDs)[0] = atoi(&fromserver[4]);
X fromserver = index(&fromserver[4], ' ');
X if (!fromserver) {
X strcpy(pop_error,
X "Badly formatted response from server in pop_list");
X free((char *) *IDs);
X free((char *) *sizes);
X pop_close(server);
X return (-1);
X }
X (*sizes)[0] = atoi(fromserver);
X (*IDs)[1] = (*sizes)[1] = 0;
X return (0);
X } else {
X if (sendline(server, "LIST") || getok(server)) {
X free((char *) *IDs);
X free((char *) *sizes);
X return (-1);
X }
X for (i = 0; i < how_many; i++) {
X if (!(fromserver = getline(server))) {
X free((char *) *IDs);
X free((char *) *sizes);
X return (-1);
X }
X (*IDs)[i] = atoi(fromserver);
X fromserver = index(fromserver, ' ');
X if (!fromserver) {
X strcpy(pop_error,
X "Badly formatted response from server in pop_list");
X free((char *) *IDs);
X free((char *) *sizes);
X pop_close(server);
X return (-1);
X }
X (*sizes)[i] = atoi(fromserver);
X }
X if (gettermination(server)) {
X free((char *) *IDs);
X free((char *) *sizes);
X return (-1);
X }
X (*IDs)[i] = (*sizes)[i] = 0;
X return (0);
X }
X}
X
X/*
X * Function: pop_retrieve
X *
X * Purpose: Retrieve a specified message from the maildrop.
X *
X * Arguments:
X * server The server to retrieve from.
X * message The message number to retrieve.
X *
X * Return value: A string pointing to the message, if successful, or
X * null with pop_error set if not.
X *
X * Side effects: Closes the connection on error.
X */
Xchar *
Xpop_retrieve(server, message)
XPopServer server;
Xint message;
X{
X int *IDs, *sizes;
X char *ptr, *cp;
X
X if (pop_list(server, message, &IDs, &sizes))
X return (0);
X
X sprintf(pop_error, "RETR %d", message);
X if (sendline(server, pop_error) || getok(server)) {
X return (0);
X }
X cp = ptr = (char *) malloc(sizes[0]+1);
X free((char *) IDs);
X free((char *) sizes);
X
X if (!ptr) {
X strcpy(pop_error, "Out of memory in pop_retrieve");
X pop_close(server);
X return (0);
X }
X *cp = '\0';
X
X while (1) {
X char *fromserver = getline(server);
X int size;
X
X if (!fromserver) {
X free(ptr);
X pop_close(server);
X return (0);
X }
X if (fromserver[0] == '.') {
X if (!fromserver[1]) {
X return (ptr);
X }
X fromserver++;
X }
X size = strlen(fromserver);
X bcopy(fromserver, cp, size + 1);
X cp += size;
X *cp++ = '\n';
X *cp = '\0';
X }
X}
X
X/* Function: pop_delete
X *
X * Purpose: Delete a specified message.
X *
X * Arguments:
X * server Server from which to delete the message.
X * message Message to delete.
X *
X * Return value: 0 on success, non-zero with error in pop_error
X * otherwise.
X */
Xint
Xpop_delete(server, message)
XPopServer server;
Xint message;
X{
X sprintf(pop_error, "DELE %d", message);
X
X if (sendline(server, pop_error) || getok(server)) {
X pop_close(server);
X return (-1);
X }
X return (0);
X}
X
X/*
X * Function: pop_noop
X *
X * Purpose: Send a noop command to the server.
X *
X * Argument:
X * server The server to send to.
X *
X * Return value: 0 on success, non-zero with error in pop_error
X * otherwise.
X *
X * Side effects: Closes connection on error.
X */
Xint
Xpop_noop(server)
XPopServer server;
X{
X if (sendline(server, "NOOP") || getok(server))
X return (-1);
X
X return (0);
X}
X
X/*
X * Function: pop_last
X *
X * Purpose: Find out the highest seen message from the server.
X *
X * Arguments:
X * server The server.
X *
X * Return value: If successful, the highest seen message, which is
X * greater than or equal to 0. Otherwise, a negative number with
X * the error explained in pop_error.
X *
X * Side effects: Closes the connection on error.
X */
Xint
Xpop_last(server)
XPopServer server;
X{
X char *fromserver;
X
X if (sendline(server, "LAST"))
X return (-1);
X
X if (!(fromserver = getline(server)))
X return (-1);
X
X if (!strncmp(fromserver, "-ERR", 4)) {
X strncpy(pop_error, fromserver, ERROR_MAX);
X pop_close(server);
X return (-1);
X } else if (strncmp(fromserver, "+OK", 3)) {
X strcpy(pop_error, "Unexpected response from server in pop_last");
X pop_close(server);
X return (-1);
X } else {
X return (atoi(&fromserver[4]));
X }
X}
X
X/*
X * Function: pop_reset
X *
X * Purpose: Reset the server to its initial connect state
X *
X * Arguments:
X * server The server.
X *
X * Return value: 0 for success, non-0 with error in pop_error
X * otherwise.
X *
X * Side effects: Closes the connection on error.
X */
Xint
Xpop_reset(server)
XPopServer server;
X{
X if (sendline(server, "RSET") || getok(server)) {
X pop_close(server);
X return (-1);
X }
X return (0);
X}
X
X/*
X * Function: pop_quit
X *
X * Purpose: Quit the connection to the server,
X *
X * Arguments:
X * server The server to quit.
X *
X * Return value: 0 for success, non-zero otherwise with error in
X * pop_error.
X *
X * Side Effects: The PopServer passed in is unuseable after this
X * function is called, even if an error occurs.
X */
Xint
Xpop_quit(server)
XPopServer server;
X{
X int ret = 0;
X
X if (sendline(server, "QUIT") || getok(server))
X ret = -1;
X
X close(server->file);
X free((char *) server);
X
X return (ret);
X}
X
X/*
X * Function: socket_connection
X *
X * Purpose: Opens the network connection with the mail host, without
X * doing any sort of I/O with it or anything.
X *
X * Arguments:
X * host The host to which to connect.
X * flags Option flags.
X *
X * Return value: A file descriptor indicating the connection, or -1
X * indicating failure, in which case an error has been copied
X * into pop_error.
X */
Xstatic int
Xsocket_connection(host, flags)
Xchar *host;
Xint flags;
X{
X struct hostent *hostent;
X struct servent *servent;
X struct sockaddr_in addr;
X char found_port = 0;
X char *service;
X int sock;
X
X#ifdef KERBEROS
X KTEXT ticket;
X MSG_DAT msg_data;
X CREDENTIALS cred;
X Key_schedule schedule;
X int rem;
X
X#endif
X
X int try_count = 0;
X
X do {
X hostent = gethostbyname(host);
X try_count++;
X if ((!hostent) && ((h_errno != TRY_AGAIN) || (try_count == 5))) {
X strcpy(pop_error, "Could not determine POP server's address");
X return (-1);
X }
X } while (!hostent);
X
X bzero((char *) &addr, sizeof(addr));
X addr.sin_family = AF_INET;
X
X#ifdef KERBEROS
X service = (flags & POP_NO_KERBEROS) ? POP_SERVICE : KPOP_SERVICE;
X#else
X service = POP_SERVICE;
X#endif
X
X#ifdef HESIOD
X if (!(flags & POP_NO_HESIOD)) {
X servent = hes_getservbyname(service, "tcp");
X if (servent) {
X addr.sin_port = servent->s_port;
X found_port = 1;
X }
X }
X#endif
X if (!found_port) {
X servent = getservbyname(service, "tcp");
X if (servent) {
X addr.sin_port = servent->s_port;
X } else {
X#ifdef KERBEROS
X addr.sin_port = htons((flags & POP_NO_KERBEROS) ?
X POP_PORT : KPOP_PORT);
X#else
X addr.sin_port = htons(POP_PORT);
X#endif
X }
X }
X#define SOCKET_ERROR "Could not create socket for POP connection: "
X
X sock = socket(PF_INET, SOCK_STREAM, 0);
X if (sock < 0) {
X strcpy(pop_error, SOCKET_ERROR);
X strncat(pop_error, strerror(errno),
X ERROR_MAX - sizeof(SOCKET_ERROR));
X return (-1);
X
X }
X while (*hostent->h_addr_list) {
X bcopy(*hostent->h_addr_list, (char *) &addr.sin_addr,
X hostent->h_length);
X if (!connect(sock, (struct sockaddr *) & addr, sizeof(addr)))
X break;
X hostent->h_addr_list++;
X }
X
X#define CONNECT_ERROR "Could not connect to POP server: "
X
X if (!*hostent->h_addr_list) {
X (void) close(sock);
X strcpy(pop_error, CONNECT_ERROR);
X strncat(pop_error, strerror(errno),
X ERROR_MAX - sizeof(CONNECT_ERROR));
X return (-1);
X
X }
X#ifdef KERBEROS
X if (!(flags & POP_NO_KERBEROS)) {
X ticket = (KTEXT) malloc(sizeof(KTEXT_ST));
X rem = krb_sendauth(0L, sock, ticket, "pop", hostent->h_name,
X (char *) krb_realmofhost(hostent->h_name),
X (unsigned long) 0, &msg_data, &cred, schedule,
X (struct sockaddr_in *) 0,
X (struct sockaddr_in *) 0,
X "KPOPV0.1");
X free((char *) ticket);
X if (rem != KSUCCESS) {
X#define KRB_ERROR "Kerberos error connecting to POP server: "
X strcpy(pop_error, KRB_ERROR);
X strncat(pop_error, krb_err_txt[rem],
X ERROR_MAX - sizeof(KRB_ERROR));
X (void) close(sock);
X return (-1);
X }
X }
X#endif /* KERBEROS */
X
X return (sock);
X}/* socket_connection */
X
X/*
X * Function: getline
X *
X * Purpose: Get a line of text from the connection and return a
X * pointer to it. The carriage return and linefeed at the end of
X * the line are stripped, but periods at the beginnings of lines
X * are NOT dealt with in any special way.
X *
X * Arguments:
X * server The server from which to get the line of text.
X *
X * Returns: A non-null pointer if successful, or a null pointer on any
X * error, with an error message copied into pop_error.
X *
X * Notes: The line returned is overwritten with each call to getline.
X *
X * Side effects: Closes the connection on error.
X */
Xstatic char *
Xgetline(server)
XPopServer server;
X{
X#define GETLINE_ERROR "Error reading from server: "
X
X int ret;
X
X if (server->data) {
X char *cp = strstr(server->dp, "\r\n");
X
X if (cp) {
X char *found;
X
X *cp = '\0';
X server->data -= (&cp[2] - server->dp);
X found = server->dp;
X server->dp = &cp[2];
X
X if (pop_debug)
X fprintf(stderr, "<<< %s\n", found);
X return (found);
X } else {
X bcopy(server->dp, server->buffer, server->data);
X server->dp = server->buffer;
X }
X } else {
X server->dp = server->buffer;
X }
X
X while (server->data < GETLINE_MAX) {
X ret = read(server->file, &server->buffer[server->data],
X GETLINE_MAX - server->data);
X if (ret < 0) {
X strcpy(pop_error, GETLINE_ERROR);
X strncat(pop_error, strerror(errno),
X GETLINE_MAX - sizeof(GETLINE_ERROR));
X pop_close(server);
X return (0);
X } else if (ret == 0) {
X strcpy(pop_error, "Unexpected EOF from server in getline");
X pop_close(server);
X return (0);
X } else {
X char *cp = strstr(server->buffer, "\r\n");
X
X server->data += ret;
X
X if (cp) {
X *cp = '\0';
X server->data -= (&cp[2] - server->dp);
X server->dp = &cp[2];
X
X if (pop_debug)
X fprintf(stderr, "<<< %s\n", server->buffer);
X return (server->buffer);
X }
X }
X }
X
X strcpy(pop_error, "Line too long reading from server; compile pop.c with larger GETLINE_MAX");
X pop_close(server);
X return (0);
X}
X
X/*
X * Function: sendline
X *
X * Purpose: Sends a line of text to the POP server. The line of text
X * passed into this function should NOT have the carriage return
X * and linefeed on the end of it. Periods at beginnings of lines
X * will NOT be treated specially by this function.
X *
X * Arguments:
X * server The server to which to send the text.
X * line The line of text to send.
X *
X * Return value: Upon successful completion, a value of 0 will be
X * returned. Otherwise, a non-zero value will be returned, and
X * an error will be copied into pop_error.
X *
X * Side effects: Closes the connection on error.
X */
Xstatic int
Xsendline(server, line)
XPopServer server;
Xchar *line;
X{
X#define SENDLINE_ERROR "Error writing to POP server: "
X int ret;
X
X ret = fullwrite(server->file, line, strlen(line));
X if (ret >= 0) { /* 0 indicates that a blank line was written */
X ret = fullwrite(server->file, "\r\n", 2);
X }
X if (ret < 0) {
X pop_close(server);
X strcpy(pop_error, SENDLINE_ERROR);
X strncat(pop_error, strerror(errno),
X ERROR_MAX - sizeof(SENDLINE_ERROR));
X return (ret);
X }
X if (pop_debug)
X fprintf(stderr, ">>> %s\n", line);
X
X return (0);
X}
X
X/*
X * Procedure: fullwrite
X *
X * Purpose: Just like write, but keeps trying until the entire string
X * has been written.
X *
X * Return value: Same as write. Pop_error is not set.
X */
Xstatic int
Xfullwrite(fd, buf, nbytes)
Xint fd;
Xchar *buf;
Xint nbytes;
X{
X char *cp;
X int ret;
X
X cp = buf;
X while ((ret = write(fd, cp, nbytes)) > 0) {
X cp += ret;
X nbytes -= ret;
X }
X
X return (ret);
X}
X
X/*
X * Procedure getok
X *
X * Purpose: Reads a line from the server. If the return indicator is
X * positive, return with a zero exit status. If not, return with
X * a negative exit status.
X *
X * Arguments:
X * server The server to read from.
X *
X * Returns: 0 for success, else for failure and puts error in pop_error.
X *
X * Side effects: Closes the connection on error.
X */
Xstatic int
Xgetok(server)
XPopServer server;
X{
X char *fromline;
X
X if (!(fromline = getline(server))) {
X return (-1);
X }
X if (!strncmp(fromline, "+OK", 3))
X return (0);
X else if (!strncmp(fromline, "-ERR", 4)) {
X strncpy(pop_error, fromline, ERROR_MAX);
X pop_error[ERROR_MAX - 1] = '\0';
X pop_close(server);
X return (-1);
X } else {
X strcpy(pop_error,
X "Unknown response from server; expecting +OK or -ERR");
X pop_close(server);
X return (-1);
X }
X}
X
X/*
X * Function: gettermination
X *
X * Purpose: Gets the next line and verifies that it is a termination
X * line (nothing but a dot).
X *
X * Return value: 0 on success, non-zero with pop_error set on error.
X *
X * Side effects: Closes the connection on error.
X */
Xstatic int
Xgettermination(server)
XPopServer server;
X{
X char *fromserver;
X
X fromserver = getline(server);
X if (!fromserver)
X return (-1);
X
X if (strcmp(fromserver, ".")) {
X strcpy(pop_error,
X "Unexpected response from server in gettermination");
X pop_close(server);
X return (-1);
X }
X return (0);
X}
X
X/*
X * Function pop_close
X *
X * Purpose: Close a pop connection, sending a "RSET" command to try to
X * preserve any changes that were made and a "QUIT" command to
X * try to get the server to quit, but ignoring any responses that
X * are received.
X *
X * Side effects: The server is unuseable after this function returns.
X * Changes made to the maildrop since the session was started (or
X * since the last pop_reset) may be lost.
X */
Xvoid
Xpop_close(server)
XPopServer server;
X{
X sendline(server, "RSET");
X sendline(server, "QUIT");
X
X close(server->file);
X free((char *) server);
X
X return;
X}
X
X#endif /* POP3_SUPPORT */
SHAR_EOF
chmod 0644 pop.c || echo "restore of pop.c fails"
set `wc -c pop.c`;Sum=$1
if test "$Sum" != "22450"
then echo original size 22450, current size $Sum;fi
echo "x - extracting pmush.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > pmush.c &&
X/**************************************************************************
XNAME: Brian Buhrow
XDATE: September 17, 1991
XPURPOSE: This file contains the interface between the Mush program and the
X POP post-office calls which put mail into the system mailbox. Mail
X will be placed in the user's mailbox when Mush is first fired up and
X will be checked periodically as Mush is run.
X Note that these routines will only be called if the pre-processor
X variable POP3_SUPPORT is defined.
X**************************************************************************/
X
X#ifdef POP3_SUPPORT
X
X#include "config.h"
X#include "mush.h"
X#include "pop.h"
X
X/*
X * strstr - find first occurrence of wanted in s
X */
X
Xchar * /* found string, or NULL if none */
Xstrstr(s, wanted)
Xchar *s;
Xchar *wanted;
X{
X char *scan;
X long len;
X char firstc;
X
X /*
X * The odd placement of the two tests is so "" is findable.
X * Also, we inline the first char for speed.
X * The ++ on scan has been moved down for optimization.
X */
X firstc = *wanted;
X len = strlen(wanted);
X for (scan = s; *scan != firstc || strncmp(scan, wanted, len) != 0; )
X if (*scan++ == '\0')
X return NULL;
X return scan;
X}
X
X/* This routine forms the header line for the From and Date functions below.
X * It was written by John Kammens for use by UCSC's version of UCBmail running
X * on the ATHENA system.
X */
Xstatic char *
Xheader(msg, tag)
Xchar *msg, *tag;
X{
X char *val, *ptr, *eoh;
X
X val = malloc(strlen(tag) + 3);
X if (!val)
X return (0);
X
X sprintf(val, "\n%s:", tag);
X
X eoh = strstr(msg, "\n\n");
X if (!eoh)
X eoh = (char *) index(msg, '\0');
X
X ptr = strstr(msg, tag);
X
X if ((!ptr) || (ptr > eoh)) {
X sprintf(val, "%s:", tag);
X if (!strncmp(val, msg, strlen(val)))
X ptr = msg;
X else
X ptr = 0;
X }
X if (!ptr) {
X free(val);
X return (0);
X }
X ptr += strlen(val);
X
X while (*ptr && ((*ptr == ' ') || (*ptr == '\t')))
X ptr++;
X
X eoh = (char *) index(ptr, '\n');
X if (!eoh)
X eoh = (char *) index(ptr, '\0');
X
X val = realloc(val, (eoh - ptr) + 1);
X strncpy(val, ptr, (eoh - ptr));
X val[eoh - ptr] = '\0';
X
X return (val);
X}
X
X/* This routine comes up with the Unix Date line to insert into the mail
X * file. It was written by John Kammens for use with UCSC's UCBMail on
X * Athena.
X *
X * Modified to get rid of dependence on that hideous B-news yacc parser.
X * Mush already has a perfectly good date parser, let's use it. -- Bart
X */
Xstatic char *
Xdate(msg)
Xchar *msg;
X{
X char *real = 0, *machine = 0;
X long t;
X int size;
X
X real = header(msg, "Date");
X
X if (real) {
X machine = parse_date(real);
X free(real);
X if (machine) {
X machine = date_to_ctime(machine);
X }
X }
X if (!machine) {
X t = time((long *)0);
X machine = ctime(&t);
X }
X size = strlen(machine);
X machine[size - 1] = '\0'; /* get rid of newline */
X real = malloc(size);
X if (!real)
X return 0;
X strcpy(real, machine);
X
X return real;
X}
X
X/* This routine comes up with the Unix From line to insert into the mail
X * file. It was written by John Kammens for use with UCSC's UCBMail on
X * Athena.
X *
X * Modified to use get_name_n_addr() so we don't depend on regexec()
X * being available, which it usually isn't. -- Bart
X */
Xstatic char *
Xfrom_line(msg)
Xchar *msg;
X{
X char *real = header(msg, "From"), *real2;
X char addr[256];
X
X if (real) {
X addr[0] = 0;
X (void) get_name_n_addr(real, NULL, addr);
X if (addr[0]) {
X (void) bang_form(real, addr);
X return real;
X }
X }
X
X if (!real)
X real = malloc(8);
X if (!real)
X return 0;
X strcpy(real, "unknown");
X return real;
X}
X
X/* Retrieves mail from the system post office using the POP interface
X * routines as put together by John Kammens for the UCBmail program under
X * ATHENA. This routine will be called both when Mush begins executing to
X * check for new mail and when Mush is executing to see if new mail has
X * arrived during the Mush session.
X */
Xstatic void
Xloadmail()
X{
X PopServer postinfo;
X int msgcount, msgsize, i, flags = 0;
X char mailbox[MAXPATHLEN], *msgptr, *dateline, *fromline;
X FILE *mfstream;
X struct stat mfstat;
X static char pass[64];
X
X *mailbox = (char) NULL; /* Clear string */
X strcat(mailbox, getenv("HOME"));
X strcat(mailbox, "/");
X strcat(mailbox, MAILFILE);
X /* Get info about post drop */
X if (pass[0])
X flags = POP_NO_GETPASS;
X if (!(postinfo = pop_open(NULL, login, pass, flags))) {
X fprintf(stderr, "Error opening connection with post office: %s\n",
X pop_error);
X return;
X }
X if (pop_stat(postinfo, &msgcount, &msgsize)) {
X fprintf(stderr, "Error collecting status from post office: %s\n",
X pop_error);
X pop_close(postinfo);
X return;
X }
X if (!msgcount) {
X pop_quit(postinfo);
X return;
X }
X /* Begin loading mailbox */
X if (stat(mailbox, &mfstat)) {
X if (errno == ENOENT) {
X close(open(mailbox, O_WRONLY | O_CREAT | O_EXCL, 0600));
X }
X }
X if (!(mfstream = fopen(mailbox, "a"))) {
X perror("Error opening mailbox in loadmail");
X pop_close(postinfo);
X return;
X }
X for (i = 1; i <= msgcount; i++) { /* Load new messages */
X msgptr = pop_retrieve(postinfo, i);
X dateline = date(msgptr);
X fromline = from_line(msgptr);
X if (fprintf(mfstream, "\nFrom %s %s\n%s", fromline, dateline, msgptr)
X < (strlen(fromline) + strlen(dateline) + strlen(msgptr))) {
X fprintf(stderr, "Error writing mailbox file\n");
X pop_close(postinfo);
X cleanup(-1);
X }
X free(dateline);
X free(fromline);
X free(msgptr);
X if (pop_delete(postinfo, i)) {
X fprintf(stderr, "Error deleting message from post office: %s\n",
X pop_error);
X }
X }
X if (fclose(mfstream) == EOF) {
X perror("Error closing mailbox file in loadmail");
X pop_close(postinfo);
X return;
X }
X if (pop_quit(postinfo)) {
X fprintf(stderr, "Error closing post office: %s\n", pop_error);
X }
X return;
X}
X
X/* This routine merely calls loadmail to get mail initially from the post
X * office. There is no forking, and it is intended to be used when Mush is
X * first started.
X */
Xvoid
Xpopgetmail()
X{
X loadmail();
X}
X
X/* This function calls loadmail, after first forking, releasing stdin,
X * stdout and stderr and ignoring any signals that might be generated.
X * This function is invoked by the sigalrm signal. The parent resets
X * the alarm and returns.
X */
Xvoid
Xpopchkmail()
X{
X static int cpid = 0, numtries = 0;
X
X if (cpid > 0) {
X if (!kill(cpid, 0)) {
X numtries++;
X if (numtries > 10) {
X kill(cpid, SIGKILL);
X }
X return;
X } else {
X numtries = 0;
X }
X }
X if (!(cpid = fork())) {
X /* Ignore several signals for workability */
X signal(SIGCONT, SIG_IGN);
X signal(SIGQUIT, SIG_IGN);
X signal(SIGTSTP, SIG_IGN);
X signal(SIGSTOP, SIG_IGN);
X signal(SIGTERM, SIG_IGN);
X signal(SIGIO, SIG_IGN);
X signal(SIGPIPE, SIG_IGN);
X loadmail();
X _exit(0);
X } else {
X if (cpid == -1) {
X fprintf(stderr, "Unable to fork in popchkmail\n");
X }
X return;
X }
X}
X
X#endif /* POP3_SUPPORT */
SHAR_EOF
chmod 0644 pmush.c || echo "restore of pmush.c fails"
set `wc -c pmush.c`;Sum=$1
if test "$Sum" != "6973"
then echo original size 6973, current size $Sum;fi
echo "x - extracting xcreat.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > xcreat.c &&
X/************************************************************************
X * secure exclusive creat/lock v1.4 1992/04/27 *
X * (works even across NFS, which O_EXCL does *not*) *
X * *
X * Created 1990-1992, S.R. van den Berg, The Netherlands *
X * berg@pool.informatik.rwth-aachen.de *
X * berg@physik.tu-muenchen.de *
X * *
X * This file is donated to the public domain. *
X * *
X * Cleaned up 1992, Bart Schaefer, Z-Code Software Corp. *
X * schaefer@z-code.com *
X * schaefer@cse.ogi.edu *
X * Cleanup includes reformatting for readability, *
X * more comments, and using some file-name macros *
X * that Mush defines (removed calls to strpbrk() *
X * and avoided malloc()ing when max. size known). *
X * Also added XCTEST standalone test program mode. *
X * *
X * Usage: int xcreat(char *filename, int mode) *
X * *
X * returns 0:success -1:lock busy *
X * *
X * sets errno on failure *
X * *
X * To remove a `lockfile', simply unlink it. *
X * *
X ************************************************************************/
X
X#include "mush.h" /* For OS-specific include files and macros */
X
X#ifdef XCTEST_LOUDLY
X#ifndef XCTEST
X#define XCTEST
X#endif /* XCTEST */
X#endif /* XCTEST_LOUDLY */
X
X#ifdef XCTEST
X#define hostname() "xctest"
X#else
Xextern char **ourname;
X#define hostname() ourname[0]
X#endif /* XCTEST */
X
X#ifdef DECLARE_ERRNO
Xextern int errno;
X#endif /* DECLARE_ERRNO */
X
X#ifndef O_SYNC
X#define O_SYNC 0
X#endif
X#ifndef O_CREAT
X#define copen(path,type,mode) creat(path,mode)
X#else
X#define copen(path,type,mode) open(path,type,mode)
X#endif
X
X#define UNIQ_PREFIX '_' /* Any unlikely character works */
X#define charsULTOAN 4 /* # of chars output by ultoan() */
X
X#ifndef MAXNAMLEN
X#if defined(BSD) || defined(IRIX4) || defined(HPUX)
X#define MAXNAMLEN (MAXPATHLEN/2) /* Any fairly large number works */
X#else /* !SYSV */
X#define MAXNAMLEN 14 /* 14 is SysVr3 standard */
X#endif /* BSD */
X#endif /* MAXNAMLEN */
X
X#define HOSTNAMElen (MAXNAMLEN-charsULTOAN-1)
X
X/* Define a bit rotation to generate pseudo-unique numbers in "sequence" */
X#define bitsSERIAL (6*charsULTOAN)
X#define maskSERIAL ((1L<<bitsSERIAL)-1)
X#define rotbSERIAL 2
X#define mrotbSERIAL ((1L<<rotbSERIAL)-1)
X
X#define XCserialize(n,r) \
X ((u_long) maskSERIAL&((u_long)(r)<<bitsSERIAL-mrotbSERIAL)+(u_long)(n))
X
X/* Generate an almost-unique 4-character string from an unsigned long */
Xstatic
Xultoan(val, dest)
Xunsigned long val;
Xchar *dest; /* convert to a number */
X{
X register i; /* within the set [0-9A-Za-z-_] */
X
X#ifdef XCTEST_LOUDLY
X printf("Converting %lu to ascii.\n", val);
X#endif /* XCTEST_LOUDLY */
X
X do {
X i = val & 0x3f;
X *dest++ = i+(i < 10? '0' :
X i < 10+26? 'A'-10 :
X i < 10+26+26? 'a'-10-26 :
X i == 10+26+26 ? '-'-10-26-26 :
X '_'-10-26-27);
X }
X while (val >>= 6);
X *dest = '\0';
X}
X
X/* create unique file name */
Xstatic
Xunique(full, p, mode)
Xchar *full;
Xchar *p;
Xint mode;
X{
X unsigned long retry = 3;
X int i;
X
X do {
X#ifdef XCTEST_LOUDLY
X printf("Using PID = %d: ", getpid());
X#endif /* XCTEST_LOUDLY */
X ultoan(XCserialize(getpid(),retry), p + 1);
X *p = UNIQ_PREFIX;
X strncat(p, hostname(), HOSTNAMElen);
X } /* casually check if it already exists (highly unlikely) */
X while (0 > (i = copen(full, O_WRONLY|O_CREAT|O_EXCL|O_SYNC, mode)) &&
X errno == EEXIST && retry--);
X if (i < 0)
X return 0;
X close(i);
X return 1;
X}
X
X/* rename MUST fail if already existent */
Xstatic
Xmyrename(old, newn)
Xchar *old, *newn;
X{
X int i, serrno;
X struct stat stbuf;
X
X#ifdef XCTEST_LOUDLY
X printf("Renaming %s to %s\n", old, newn);
X#endif /* XCTEST_LOUDLY */
X
X link(old, newn);
X serrno = errno;
X i = stat(old, &stbuf);
X unlink(old);
X errno = serrno;
X return stbuf.st_nlink == 2 ? i : -1;
X}
X
X/* an NFS secure exclusive file open */
Xxcreat(name, mode)
Xchar *name;
Xint mode;
X{
X char buf[MAXPATHLEN];
X char *p, *q;
X int j = -2, i;
X
X q = rindex(name, '/');
X if (q)
X i = q - name;
X else {
X i = 0; /* Creating in the current directory */
X }
X p = strncpy(buf, name, i);
X if (unique(p, p + i, mode))
X j = myrename(p, name); /* try and rename it, fails if nonexclusive */
X free(p);
X return j;
X}
X
X#ifdef XCTEST
X
Xmain(argc, argv)
Xint argc;
Xchar **argv;
X{
X if (argc > 1)
X exit(xcreat(argv[1], 0444) < 0);
X}
X
X#endif /* XCTEXT */
SHAR_EOF
chmod 0644 xcreat.c || echo "restore of xcreat.c fails"
set `wc -c xcreat.c`;Sum=$1
if test "$Sum" != "4396"
then echo original size 4396, current size $Sum;fi
exit 0
--
Bart Schaefer schaefer@zigzag.z-code.com
Z-Code Software Corp. schaefer@z-code.com
exit 0 # Just in case...