ftp.nice.ch/pub/next/connectivity/news/NewsBase.3.02.s.tar.gz#/NewsBase302.source/MMEdit/ftp.c

This is ftp.c in view mode; [Download] [Up]

/*
#define DEBUG
*/

// anonymous ftp routines.

#include <fcntl.h>
#include <sys/types.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <strings.h>
#include <errno.h>
#include <stdio.h>
#include <signal.h>

#ifndef NULL
#define NULL 0
#endif

#ifdef DEBUG
#define D(X) X
#else
#define D(X)
#endif

#define SERRNO 1
#define HERRNO 2
#define ERRNO 3

/*
main(argc, argv)
int argc;
char *argv[];
{
    exit(ftp(argv[1], argv[2], argv[3], argv[4]));
}
*/

// ftp does an anonymous ftp from 'host' of file 'path'/'file'.  Where
// 'user' is sent as password as requested by anonymous ftp server.

ftp(host, user, path, file)
char *host;
char *user;
char *path;
char *file;
{
    struct servent *sp;
    struct hostent *hp;
    int sd, sd1;
    struct sockaddr_in addr;
    int len;
    char cmd[256];
    int code;
    int reuse_addr;
    int fd;
    int child;

    if ((fd = open(file, O_WRONLY | O_CREAT | O_TRUNC, 0666)) == -1) {
        return(ERRNO);
    }
    if ((sp = getservbyname("ftp", "tcp")) == NULL) {
        return(SERRNO);
    }
    addr.sin_port = sp->s_port;
    if ((hp = gethostbyname(host))  == NULL) {
        return(HERRNO);
    }
    bcopy(hp->h_addr_list[0], (char *)&addr.sin_addr, hp->h_length);
    if ((sd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
        return(ERRNO);
    }
    addr.sin_family = PF_INET;
    if (connect(sd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
        return(ERRNO);
    }
    if ((code = read_reply(sd)) != 220) {
        return(code);
    }
    write(sd, "USER anonymous\r\n", 16);
    if ((code = read_reply(sd)) != 331) {
        write(sd, "QUIT\r\n", 6);
        return(code);
    }
    sprintf(cmd, "PASS %s\r\n", user);
    write(sd, cmd, strlen(cmd));
    if ((code = read_reply(sd)) != 230) {
        write(sd, "QUIT\r\n", 6);
        return(code);
    }
    write(sd, "TYPE I\r\n", 8);
    if ((code = read_reply(sd)) != 200) {
        write(sd, "QUIT\r\n", 6);
        return(code);
    }
    len = sizeof(addr);
    if (getsockname(sd, &addr, &len) == -1) {
       return(ERRNO);
    }
    if ((sd1 = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
        return(ERRNO);
    }
    reuse_addr = 1;
    if (setsockopt(sd1, SOL_SOCKET, SO_REUSEADDR, &reuse_addr,
        sizeof(reuse_addr)) == -1) {
        return(ERRNO);
    }
    if (bind(sd1, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
        return(ERRNO);
    }
    if (listen(sd1, 1) == -1) {
        return(ERRNO);
    }
    if ((child = fork()) == 0) {
        close(sd);
        exit(data_process(sd1, fd));
    } else if (child == -1) {
        close(sd);
        close(sd1);
        return(ERRNO);
    }
    close(sd1);
    close(fd);
    D(fprintf(stderr, "sending retr command\n");)
    sprintf(cmd, "retr %s\r\n", path);
    write(sd, cmd, strlen(cmd));
    if ((code = read_reply(sd)) != 150) {
        write(sd, "QUIT\r\n", 6);
        close(sd);
        kill(child, SIGKILL);
        return(code);
    }
    if ((code = read_reply(sd)) != 226) {
        write(sd, "QUIT\r\n", 6);
        close(sd);
        kill(child, SIGKILL);
        return(code);
    }
    write(sd, "QUIT\r\n", 6);
    close(sd);
    kill(child, SIGKILL);
    return(0);
}

int read_reply(sd)
int sd;
{
    char *line;
    int code, code1;
    char cont;
    char *read_line();

    line = read_line(sd);
    sscanf(line, "%d%c", &code, &cont);
    D(fprintf(stderr, "code = %d, cont = %c\n", code, cont);)
    if (cont == '-') {
        do {
            line = read_line(sd);
            sscanf(line, "%d%c", &code1, &cont);
            D(fprintf(stderr, "code = %d, cont = %c\n", code1, cont);)
        } while (cont != ' ' || code1 != code);
    }
    return(code);
}

char *read_line(sd)
int sd;
{
    static char buf[4096];
    static char *bufStart = NULL, *bufEnd = NULL;
    int len;
    char *lineStart, *lineEnd;

    if (bufStart == bufEnd) {
        len = read(sd, buf, sizeof(buf));
        bufStart = buf;
        bufEnd = buf + len;
    }    
  begin:
    if ((lineEnd = index(bufStart, '\r')) != 0) {
        *lineEnd = '\0';
        lineStart = bufStart;
        bufStart = lineEnd + 2;
        D(write(2, lineStart, strlen(lineStart));
        write(2, "\n", 1);)
        return(lineStart);
    } else {
        bcopy(bufStart, buf, bufEnd - bufStart);
        len = read(sd, buf + (bufEnd - bufStart),
            sizeof(buf) - (bufEnd - bufStart));
	bufEnd = buf + (bufEnd - bufStart) + len;
        bufStart = buf;
        goto begin;
    }
}

data_process(sd, fd)
int sd;
int fd;
{
    int dsd;
    struct sockaddr addr;
    int len;
    char buf[4096];
    int cnt;

    D(fprintf(stderr, "waiting for data connection\n");)
    if ((dsd = accept(sd, &addr, &len)) == -1) {
        return(-1);
    }
    close(sd);
    D(fprintf(stderr, "data connection accepted\n");)
    D(fflush(stderr);)
    while ((cnt = read(dsd, buf, sizeof(buf))) != -1) {
        D(write(2, buf, cnt);)
        write(fd, buf, cnt);
    }
    close(dsd);
    close(fd);
    return(0);
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.