Thread View: comp.mail.mush
1 messages
1 total messages
Started by Bart Schaefer
Wed, 14 Oct 1992 09:15
Patch #5 for Mush 7.2, part 03/03
Author: Bart Schaefer
Date: Wed, 14 Oct 1992 09:15
Date: Wed, 14 Oct 1992 09:15
1630 lines
42374 bytes
42374 bytes
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
Thread Navigation
This is a paginated view of messages in the thread with full content displayed inline.
Messages are displayed in chronological order, with the original post highlighted in green.
Use pagination controls to navigate through all messages in large threads.
Back to All Threads