Hi , 

I am  planning to write tftp (Trivial file transfer protocol ) client
on lwip . I have some exclusive free source  for tftp client , but do
not know how to adopt the code  to run it on lwip . I mean to say,
what changes do I need to make in the tftp code, so that this can
communicate with lwip to send and receive files.

  I had compiled some examples under contrib and got an idea on
compiling and linking projects under lwip , I know ,I should make use
of the lwip API to do this , but want to know the procedure to do this
. The tftp source is not part of the lwip , so I just want to tell my
tftp source to use lwip to send and receive files and make it as a
part of my project and compile it as a whole package. As a reference I
am here with sending the tftp.c client file and main.c  file  so that
you guys can have an idea of this .I am using it on linux  with a gcc
compiler and gnu make.Please suggest me in this regard, as I need this
as a part of my work .

I would be thankful to any kind of suggestions.


PS:  tftp.c , main.c  files for an idea .....
        tftp uses udp as the transport protocol - tftp/udp/ip 
also http://rfc.net/rfc1350.html - for TFTP protocol reference


Thanks and Regards

Durga Prasad Chivukula
Infineon Technologies AG
/* $Id: tftp.c,v 1.17 2004/01/08 20:47:00 hpa Exp $ */

/* $OpenBSD: tftp.c,v 1.4 1997/08/06 06:43:45 deraadt Exp $     */
/* $NetBSD: tftp.c,v 1.5 1995/04/29 05:55:25 cgd Exp $  */

/*
 * Copyright (c) 1983, 1993
 *      The Regents of the University of California.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *      This product includes software developed by the University of
 *      California, Berkeley and its contributors.
 * 4. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#include "tftpsubs.h"

#ifndef lint
/* static char sccsid[] = "@(#)tftp.c   8.1 (Berkeley) 6/6/93"; */
/* static char rcsid[] = "$OpenBSD: tftp.c,v 1.4 1997/08/06 06:43:45 deraadt 
Exp $"; */
static const char *rcsid UNUSED =
"tftp-hpa $Id: tftp.c,v 1.17 2004/01/08 20:47:00 hpa Exp $";
#endif /* not lint */

/* Many bug fixes are from Jim Guyton <[EMAIL PROTECTED]> */

/*
 * TFTP User Program -- Protocol Machines
 */
#include "extern.h"

extern  struct sockaddr_in peeraddr;    /* filled in by main */
extern  int     f;                      /* the opened socket */
extern  int     trace;
extern  int     verbose;
extern  int     rexmtval;
extern  int     maxtimeout;

#define PKTSIZE    SEGSIZE+4
char    ackbuf[PKTSIZE];
int     timeout;
sigjmp_buf      toplevel;
sigjmp_buf      timeoutbuf;

static void nak(int, const char *);
static int makerequest(int, const char *, struct tftphdr *, const char *);
static void printstats(const char *, unsigned long);
static void startclock(void);
static void stopclock(void);
static void timer(int);
static void tpacket(const char *, struct tftphdr *, int);

/*
 * Send the requested file.
 */
void
tftp_sendfile(int fd, const char *name, const char *mode)
{
        struct tftphdr *ap;        /* data and ack packets */
        struct tftphdr *dp;
        int n;
        volatile int is_request;
        volatile u_short block;
        volatile int size, convert;
        volatile off_t amount;
        struct sockaddr_in from;
        int fromlen;
        FILE *file;
        u_short ap_opcode, ap_block;

        startclock();           /* start stat's clock */
        dp = r_init();          /* reset fillbuf/read-ahead code */
        ap = (struct tftphdr *)ackbuf;
        convert = !strcmp(mode, "netascii");
        file = fdopen(fd, convert ? "rt" : "rb");
        block = 0;
        is_request = 1;         /* First packet is the actual WRQ */
        amount = 0;

        bsd_signal(SIGALRM, timer);
        do {
                if (is_request) {
                        size = makerequest(WRQ, name, dp, mode) - 4;
                } else {
                /*      size = read(fd, dp->th_data, SEGSIZE);   */
                        size = readit(file, &dp, convert);
                        if (size < 0) {
                                nak(errno + 100, NULL);
                                break;
                        }
                        dp->th_opcode = htons((u_short)DATA);
                        dp->th_block = htons((u_short)block);
                }
                timeout = 0;
                (void) sigsetjmp(timeoutbuf,1);

                if (trace)
                        tpacket("sent", dp, size + 4);
                n = sendto(f, dp, size + 4, 0,
                    (struct sockaddr *)&peeraddr, sizeof(peeraddr));
                if (n != size + 4) {
                        perror("tftp: sendto");
                        goto abort;
                }
                read_ahead(file, convert);
                for ( ; ; ) {
                        alarm(rexmtval);
                        do {
                                fromlen = sizeof(from);
                                n = recvfrom(f, ackbuf, sizeof(ackbuf), 0,
                                    (struct sockaddr *)&from, &fromlen);
                        } while (n <= 0);
                        alarm(0);
                        if (n < 0) {
                                perror("tftp: recvfrom");
                                goto abort;
                        }
                        peeraddr.sin_port = from.sin_port;      /* added */
                        if (trace)
                                tpacket("received", ap, n);
                        /* should verify packet came from server */
                        ap_opcode = ntohs((u_short)ap->th_opcode);
                        ap_block = ntohs((u_short)ap->th_block);
                        if (ap_opcode == ERROR) {
                                printf("Error code %d: %s\n", ap_block,
                                        ap->th_msg);
                                goto abort;
                        }
                        if (ap_opcode == ACK) {
                                int j;

                                if (ap_block == block) {
                                        break;
                                }
                                /* On an error, try to synchronize
                                 * both sides.
                                 */
                                j = synchnet(f);
                                if (j && trace) {
                                        printf("discarded %d packets\n",
                                                        j);
                                }
                                /*
                                 * RFC1129/RFC1350: We MUST NOT re-send the DATA
                                 * packet in response to an invalid ACK.  Doing 
so
                                 * would cause the Sorcerer's Apprentice bug.
                                 */
                        }
                }
                if ( !is_request )
                        amount += size;
                is_request = 0;
                block++;
        } while (size == SEGSIZE || block == 1);
abort:
        fclose(file);
        stopclock();
        if (amount > 0)
                printstats("Sent", amount);
}

/*
 * Receive a file.
 */
void
tftp_recvfile(int fd, const char *name, const char *mode)
{
        struct tftphdr *ap;
        struct tftphdr *dp;
        int n;
        volatile u_short block;
        volatile int size, firsttrip;
        volatile unsigned long amount;
        struct sockaddr_in from;
        int fromlen;
        FILE *file;
        volatile int convert;           /* true if converting crlf -> lf */
        u_short dp_opcode, dp_block;

        startclock();
        dp = w_init();
        ap = (struct tftphdr *)ackbuf;
        convert = !strcmp(mode, "netascii");
        file = fdopen(fd, convert ?"wt":"wb");
        block = 1;
        firsttrip = 1;
        amount = 0;

        bsd_signal(SIGALRM, timer);
        do {
                if (firsttrip) {
                        size = makerequest(RRQ, name, ap, mode);
                        firsttrip = 0;
                } else {
                        ap->th_opcode = htons((u_short)ACK);
                        ap->th_block = htons((u_short)block);
                        size = 4;
                        block++;
                }
                timeout = 0;
                (void) sigsetjmp(timeoutbuf,1);
send_ack:
                if (trace)
                        tpacket("sent", ap, size);
                if (sendto(f, ackbuf, size, 0, (struct sockaddr *)&peeraddr,
                    sizeof(peeraddr)) != size) {
                        alarm(0);
                        perror("tftp: sendto");
                        goto abort;
                }
                write_behind(file, convert);
                for ( ; ; ) {
                        alarm(rexmtval);
                        do  {
                                fromlen = sizeof(from);
                                n = recvfrom(f, dp, PKTSIZE, 0,
                                    (struct sockaddr *)&from, &fromlen);
                        } while (n <= 0);
                        alarm(0);
                        if (n < 0) {
                                perror("tftp: recvfrom");
                                goto abort;
                        }
                        peeraddr.sin_port = from.sin_port;      /* added */
                        if (trace)
                                tpacket("received", dp, n);
                        /* should verify client address */
                        dp_opcode = ntohs((u_short)dp->th_opcode);
                        dp_block = ntohs((u_short)dp->th_block);
                        if (dp_opcode == ERROR) {
                          printf("Error code %d: %s\n", dp_block, dp->th_msg);
                          goto abort;
                        }
                        if (dp_opcode == DATA) {
                                int j;

                                if (dp_block == block) {
                                        break;          /* have next packet */
                                }
                                /* On an error, try to synchronize
                                 * both sides.
                                 */
                                j = synchnet(f);
                                if (j && trace) {
                                        printf("discarded %d packets\n", j);
                                }
                                if (dp_block == (block-1)) {
                                        goto send_ack;  /* resend ack */
                                }
                        }
                }
        /*      size = write(fd, dp->th_data, n - 4); */
                size = writeit(file, &dp, n - 4, convert);
                if (size < 0) {
                        nak(errno + 100, NULL);
                        break;
                }
                amount += size;
        } while (size == SEGSIZE);
abort:                                          /* ok to ack, since user */
        ap->th_opcode = htons((u_short)ACK);    /* has seen err msg */
        ap->th_block = htons((u_short)block);
        (void) sendto(f, ackbuf, 4, 0, (struct sockaddr *)&peeraddr,
            sizeof(peeraddr));
        write_behind(file, convert);            /* flush last buffer */
        fclose(file);
        stopclock();
        if (amount > 0)
                printstats("Received", amount);
}

static int
makerequest(int request, const char *name,
            struct tftphdr *tp, const char *mode)
{
        char *cp;

        tp->th_opcode = htons((u_short)request);
        cp = (char *) &(tp->th_stuff);
        strcpy(cp, name);
        cp += strlen(name);
        *cp++ = '\0';
        strcpy(cp, mode);
        cp += strlen(mode);
        *cp++ = '\0';
        return (cp - (char *)tp);
}

static const char * const errmsgs[] =
{
  "Undefined error code",                       /* 0 - EUNDEF */
  "File not found",                             /* 1 - ENOTFOUND */
  "Access denied",                              /* 2 - EACCESS */
  "Disk full or allocation exceeded",           /* 3 - ENOSPACE */
  "Illegal TFTP operation",                     /* 4 - EBADOP */
  "Unknown transfer ID",                        /* 5 - EBADID */
  "File already exists",                        /* 6 - EEXISTS */
  "No such user",                               /* 7 - ENOUSER */
  "Failure to negotiate RFC2347 options"        /* 8 - EOPTNEG */
};
#define ERR_CNT (sizeof(errmsgs)/sizeof(const char *))

/*
 * Send a nak packet (error message).
 * Error code passed in is one of the
 * standard TFTP codes, or a UNIX errno
 * offset by 100.
 */
static void
nak(int error, const char *msg)
{
  struct tftphdr *tp;
  int length;
  
  tp = (struct tftphdr *)ackbuf;
  tp->th_opcode = htons((u_short)ERROR);
  tp->th_code = htons((u_short)error);

  if ( error >= 100 ) {
    /* This is a Unix errno+100 */
    if ( !msg )
      msg = strerror(error - 100);
    error = EUNDEF;
  } else {
    if ( (unsigned)error >= ERR_CNT )
      error = EUNDEF;
    
    if ( !msg )
      msg = errmsgs[error];
  }

  tp->th_code = htons((u_short)error);

  length = strlen(msg)+1;
  memcpy(tp->th_msg, msg, length);
  length += 4;                  /* Add space for header */

  if (trace)
    tpacket("sent", tp, length);
  if (sendto(f, ackbuf, length, 0, (struct sockaddr *)&peeraddr,
             sizeof(peeraddr)) != length)
    perror("nak");
}

static void
tpacket(const char *s, struct tftphdr *tp, int n)
{
        static const char *opcodes[] =
           { "#0", "RRQ", "WRQ", "DATA", "ACK", "ERROR", "OACK" };
        char *cp, *file;
        u_short op = ntohs((u_short)tp->th_opcode);

        if (op < RRQ || op > ERROR)
                printf("%s opcode=%x ", s, op);
        else
                printf("%s %s ", s, opcodes[op]);
        switch (op) {

        case RRQ:
        case WRQ:
                n -= 2;
                file = cp = (char *) &(tp->th_stuff);
                cp = strchr(cp, '\0');
                printf("<file=%s, mode=%s>\n", file, cp + 1);
                break;

        case DATA:
                printf("<block=%d, %d bytes>\n", ntohs(tp->th_block), n - 4);
                break;

        case ACK:
                printf("<block=%d>\n", ntohs(tp->th_block));
                break;

        case ERROR:
                printf("<code=%d, msg=%s>\n", ntohs(tp->th_code), tp->th_msg);
                break;
        }
}

struct timeval tstart;
struct timeval tstop;

static void
startclock(void)
{
        (void)gettimeofday(&tstart, NULL);
}

static void
stopclock(void)
{

        (void)gettimeofday(&tstop, NULL);
}

static void
printstats(const char *direction, unsigned long amount)
{
        double delta;

        delta = (tstop.tv_sec+(tstop.tv_usec/100000.0)) -
                (tstart.tv_sec+(tstart.tv_usec/100000.0));
        if (verbose) {
          printf("%s %lu bytes in %.1f seconds", direction, amount, delta);
          printf(" [%.0f bit/s]", (amount*8.)/delta);
          putchar('\n');
        }
}

static void
timer(int sig)
{
        int save_errno = errno;

        (void)sig;              /* Shut up unused warning */

        timeout += rexmtval;
        if (timeout >= maxtimeout) {
                printf("Transfer timed out.\n");
                errno = save_errno;
                siglongjmp(toplevel, -1);
        }
        errno = save_errno;
        siglongjmp(timeoutbuf, 1);
}
/*      $OpenBSD: main.c,v 1.4 1997/01/17 07:13:30 millert Exp $        */
/*      $NetBSD: main.c,v 1.6 1995/05/21 16:54:10 mycroft Exp $ */

/*
 * Copyright (c) 1983, 1993
 *      The Regents of the University of California.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *      This product includes software developed by the University of
 *      California, Berkeley and its contributors.
 * 4. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#include "tftpsubs.h"

#ifndef lint
static const char *copyright UNUSED =
"@(#) Copyright (c) 1983, 1993\n\
        The Regents of the University of California.  All rights reserved.\n";
/* static char sccsid[] = "@(#)main.c   8.1 (Berkeley) 6/6/93"; */
/* static char rcsid[] = "$OpenBSD: main.c,v 1.4 1997/01/17 07:13:30 millert 
Exp $"; */
static const char *rcsid UNUSED =
 "tftp-hpa $Id: main.c,v 1.21 2004/01/08 20:47:00 hpa Exp $";
#endif /* not lint */

/* Many bug fixes are from Jim Guyton <[EMAIL PROTECTED]> */

/*
 * TFTP User Program -- Command Interface.
 */
#include <sys/file.h>
#include <ctype.h>
#include <netdb.h>
#ifdef WITH_READLINE
#include <readline/readline.h>
#ifdef HAVE_READLINE_HISTORY_H
#include <readline/history.h>
#endif
#endif

#include "extern.h"

#define TIMEOUT         5               /* secs between rexmt's */
#define LBUFLEN         200             /* size of input buffer */

struct modes {
  const char *m_name;
  const char *m_mode;
  int m_openflags;
};

static const struct modes modes[] = {
        { "netascii", "netascii", O_TEXT },
        { "ascii",    "netascii", O_TEXT },
        { "octet",    "octet",    O_BINARY },
        { "binary",   "octet",    O_BINARY },
        { "image",    "octet",    O_BINARY },
        { 0, 0, 0 }
};
#define MODE_OCTET    (&modes[2])
#define MODE_NETASCII (&modes[0])
#define MODE_DEFAULT  MODE_NETASCII

struct  sockaddr_in peeraddr;
int     f;
u_short port;
int     trace;
int     verbose;
int     connected;
const struct modes *mode;
#ifdef WITH_READLINE
char   *line = NULL;
#else
char    line[LBUFLEN];
#endif
int     margc;
char    *margv[20];
const char *prompt = "tftp> ";
sigjmp_buf      toplevel;
void    intr(int);
struct  servent *sp;

void    get (int, char **);
void    help (int, char **);
void    modecmd (int, char **);
void    put (int, char **);
void    quit (int, char **);
void    setascii (int, char **);
void    setbinary (int, char **);
void    setpeer (int, char **);
void    setrexmt (int, char **);
void    settimeout (int, char **);
void    settrace (int, char **);
void    setverbose (int, char **);
void    status (int, char **);

static void command (void);

static void getusage (char *);
static void makeargv (void);
static void putusage (char *);
static void settftpmode (const struct modes *);

#define HELPINDENT (sizeof("connect"))

struct cmd {
        const char *name;
        const char *help;
        void    (*handler) (int, char **);
};

struct cmd cmdtab[] = {
  { "connect",
    "connect to remote tftp",
    setpeer },
  { "mode",
    "set file transfer mode",
    modecmd },
  { "put",
    "send file",
    put },
  { "get",
    "receive file",
    get },
  { "quit",
    "exit tftp",
    quit },
  { "verbose",
    "toggle verbose mode",
    setverbose },
  { "trace",
    "toggle packet tracing",
    settrace },
  { "status",
    "show current status",
    status },
  { "binary",
    "set mode to octet",
    setbinary },
  { "ascii",
    "set mode to netascii",
    setascii },
  { "rexmt",
    "set per-packet transmission timeout",
    setrexmt },
  { "timeout",
    "set total retransmission timeout",
    settimeout },
  { "?",
    "print help information",
    help },
  { "help",
    "print help information",
    help },
  { 0, 0, 0 }
};

struct  cmd *getcmd(char *);
char    *tail(char *);

char *xstrdup(const char *);

const char *program;

static inline void usage(int errcode)
{
  fprintf(stderr, "Usage: %s [-v][-m mode] [host [port]] [-c command]\n", 
program);
  exit(errcode);
}

int
main(int argc, char *argv[])
{
  struct sockaddr_in s_in;
  int arg;
  static int pargc, peerargc;
  static int iscmd = 0;
  char **pargv;
  const char *optx;
  char *peerargv[3];

  program = argv[0];

  mode = MODE_DEFAULT;

  peerargv[0] = argv[0];
  peerargc = 1;

  for ( arg = 1 ; !iscmd && arg < argc ; arg++ ) {
    if ( argv[arg][0] == '-' ) {
      for ( optx = &argv[arg][1] ; *optx ; optx++ ) {
        switch ( *optx ) {
        case 'v':
          verbose = 1;
          break;
        case 'V':
          /* Print version and configuration to stdout and exit */
          printf("%s\n", TFTP_CONFIG_STR);
          exit(0);
        case 'm':
          if ( ++arg >= argc )
            usage(EX_USAGE);
          {
            const struct modes *p;
            
            for ( p = modes ; p->m_name ; p++ ) {
              if (!strcmp(argv[arg], p->m_name))
                break;
            }
            if (p->m_name) {
              settftpmode(p);
            } else {
              fprintf(stderr, "%s: invalid mode: %s\n", argv[0], argv[arg]);
              exit(EX_USAGE);
            }
          }
          break;
        case 'c':
          iscmd = 1;
          break;
        case 'h':
        default:
          usage(*optx == 'h' ? 0 : EX_USAGE);
        }
      }
    } else {
      if ( peerargc >= 3 )
        usage(EX_USAGE);

      peerargv[peerargc++] = argv[arg];
    }
  }
  
  pargv = argv + arg;
  pargc = argc - arg;
  
  sp = getservbyname("tftp", "udp");
  if (sp == 0) {
    /* Use canned values */
    if (verbose)
      fprintf(stderr, "tftp: tftp/udp: unknown service, faking it...\n");
    sp = xmalloc(sizeof(struct servent));
    sp->s_name    = (char *)"tftp";
    sp->s_aliases = NULL;
    sp->s_port    = htons(IPPORT_TFTP);
    sp->s_proto   = (char *)"udp";
  }
  port = sp->s_port;            /* Default port */
  f = socket(AF_INET, SOCK_DGRAM, 0);
  if (f < 0) {
    perror("tftp: socket");
    exit(EX_OSERR);
  }
  bzero((char *)&s_in, sizeof (s_in));
  s_in.sin_family = AF_INET;
  if (bind(f, (struct sockaddr *)&s_in, sizeof (s_in)) < 0) {
    perror("tftp: bind");
    exit(EX_OSERR);
  }
  bsd_signal(SIGINT, intr);

  if ( peerargc ) {
    /* Set peer */
    if (sigsetjmp(toplevel,1) != 0)
      exit(EX_NOHOST);
    setpeer(peerargc, peerargv);
  }

  if ( iscmd && pargc ) {
    /* -c specified; execute command and exit */
    struct cmd *c;
    
    if (sigsetjmp(toplevel,1) != 0)
      exit(EX_UNAVAILABLE);
    
    c = getcmd(pargv[0]);
    if ( c == (struct cmd *)-1 || c == (struct cmd *)0 ) {
      fprintf(stderr, "%s: invalid command: %s\n", argv[0], pargv[1]);
      exit(EX_USAGE);
    }   
    (*c->handler)(pargc, pargv);
    exit(0);
  }
  if (sigsetjmp(toplevel,1) != 0)
    (void)putchar('\n');
  
#ifdef WITH_READLINE
#ifdef HAVE_READLINE_HISTORY_H
  using_history();
#endif
#endif
  
  command();
  
  return 0;             /* Never reached */
}

char    *hostname;

/* Called when a command is incomplete; modifies
   the global variable "line" */
static void
getmoreargs(const char *partial, const char *mprompt)
{
#ifdef WITH_READLINE
  char *eline;
  int len, elen;
  
  len = strlen(partial);
  eline = readline(mprompt);
  if (!eline)
          exit(0);              /* EOF */
  
  elen = strlen(eline);

  if (line)
          free(line);
  line = xmalloc(len+elen+1);
  strcpy(line, partial);
  strcpy(line+len, eline);
  free(eline);

#ifdef HAVE_READLINE_HISTORY_H
  add_history(line);
#endif
#else
  int len = strlen(partial);
  
  strcpy(line, partial);
  fputs(mprompt, stdout);
  if ( fgets(line+len, LBUFLEN-len, stdin) == 0 )
          if ( feof(stdin) )
                  exit(0);      /* EOF */
#endif
}

void
setpeer(int argc, char *argv[])
{
        struct hostent *host;

        if (argc < 2) {
                getmoreargs("connect ", "(to) ");
                makeargv();
                argc = margc;
                argv = margv;
        }
        if ((argc < 2) || (argc > 3)) {
                printf("usage: %s host-name [port]\n", argv[0]);
                return;
        }

        host = gethostbyname(argv[1]);
        if (host == 0) {
                connected = 0;
                printf("%s: unknown host\n", argv[1]);
                return;
        }
        peeraddr.sin_family = host->h_addrtype;
        bcopy(host->h_addr, &peeraddr.sin_addr, host->h_length);
        hostname = xstrdup(host->h_name);

        port = sp->s_port;
        if (argc == 3) {
                struct servent *usp;
                usp = getservbyname(argv[2], "udp");
                if ( usp ) {
                        port = usp->s_port;
                } else {
                        unsigned long myport;
                        char *ep;
                        myport = strtoul(argv[2], &ep, 10);
                        if (*ep || myport > 65535UL) {
                                printf("%s: bad port number\n", argv[2]);
                                connected = 0;
                                return;
                        }
                        port = htons((u_short)myport);
                }
        }

        if (verbose) {
                printf("Connected to %s (%s), port %u\n",
                       hostname, inet_ntoa(peeraddr.sin_addr),
                       (unsigned int)ntohs(port));
        }
        connected = 1;
}

void
modecmd(int argc, char *argv[])
{
        const struct modes *p;
        const char *sep;

        if (argc < 2) {
                printf("Using %s mode to transfer files.\n", mode->m_mode);
                return;
        }
        if (argc == 2) {
                for (p = modes; p->m_name; p++)
                        if (strcmp(argv[1], p->m_name) == 0)
                                break;
                if (p->m_name) {
                        settftpmode(p);
                        return;
                }
                printf("%s: unknown mode\n", argv[1]);
                /* drop through and print usage message */
        }

        printf("usage: %s [", argv[0]);
        sep = " ";
        for (p = modes; p->m_name; p++) {
                printf("%s%s", sep, p->m_name);
                if (*sep == ' ')
                        sep = " | ";
        }
        printf(" ]\n");
        return;
}

void
setbinary(int argc, char *argv[])
{      
        (void)argc; (void)argv; /* Quiet unused warning */
        settftpmode(MODE_OCTET);
}

void
setascii(int argc, char *argv[])
{
        (void)argc; (void)argv; /* Quiet unused warning */
        settftpmode(MODE_NETASCII);
}

static void
settftpmode(const struct modes *newmode)
{
        mode = newmode;
        if (verbose)
                printf("mode set to %s\n", mode->m_mode);
}


/*
 * Send file(s).
 */
void
put(int argc, char *argv[])
{
        int fd;
        int n;
        char *cp, *targ;

        if (argc < 2) {
                getmoreargs("send ", "(file) ");
                makeargv();
                argc = margc;
                argv = margv;
        }
        if (argc < 2) {
                putusage(argv[0]);
                return;
        }
        targ = argv[argc - 1];
        if (strchr(argv[argc - 1], ':')) {
                struct hostent *hp;

                for (n = 1; n < argc - 1; n++)
                        if (strchr(argv[n], ':')) {
                                putusage(argv[0]);
                                return;
                        }
                cp = argv[argc - 1];
                targ = strchr(cp, ':');
                *targ++ = 0;
                hp = gethostbyname(cp);
                if (hp == NULL) {
                        fprintf(stderr, "tftp: %s: ", cp);
                        herror((char *)NULL);
                        return;
                }
                bcopy(hp->h_addr, &peeraddr.sin_addr, hp->h_length);
                peeraddr.sin_family = hp->h_addrtype;
                connected = 1;
                hostname = xstrdup(hp->h_name);
        }
        if (!connected) {
                printf("No target machine specified.\n");
                return;
        }
        if (argc < 4) {
                cp = argc == 2 ? tail(targ) : argv[1];
                fd = open(cp, O_RDONLY|mode->m_openflags);
                if (fd < 0) {
                        fprintf(stderr, "tftp: "); perror(cp);
                        return;
                }
                if (verbose)
                        printf("putting %s to %s:%s [%s]\n",
                                cp, hostname, targ, mode->m_mode);
                peeraddr.sin_port = port;
                tftp_sendfile(fd, targ, mode->m_mode);
                return;
        }
                                /* this assumes the target is a directory */
                                /* on a remote unix system.  hmmmm.  */
        cp = strchr(targ, '\0'); 
        *cp++ = '/';
        for (n = 1; n < argc - 1; n++) {
                strcpy(cp, tail(argv[n]));
                fd = open(argv[n], O_RDONLY|mode->m_openflags);
                if (fd < 0) {
                        fprintf(stderr, "tftp: "); perror(argv[n]);
                        continue;
                }
                if (verbose)
                        printf("putting %s to %s:%s [%s]\n",
                                argv[n], hostname, targ, mode->m_mode);
                peeraddr.sin_port = port;
                tftp_sendfile(fd, targ, mode->m_mode);
        }
}

static void
putusage(char *s)
{
        printf("usage: %s file ... host:target, or\n", s);
        printf("       %s file ... target (when already connected)\n", s);
}

/*
 * Receive file(s).
 */
void
get(int argc, char *argv[])
{
        int fd;
        int n;
        char *cp;
        char *src;

        if (argc < 2) {
                getmoreargs("get ", "(files) ");
                makeargv();
                argc = margc;
                argv = margv;
        }
        if (argc < 2) {
                getusage(argv[0]);
                return;
        }
        if (!connected) {
                for (n = 1; n < argc ; n++)
                        if (strchr(argv[n], ':') == 0) {
                                getusage(argv[0]);
                                return;
                        }
        }
        for (n = 1; n < argc ; n++) {
                src = strchr(argv[n], ':');
                if (src == NULL)
                        src = argv[n];
                else {
                        struct hostent *hp;

                        *src++ = 0;
                        hp = gethostbyname(argv[n]);
                        if (hp == NULL) {
                                fprintf(stderr, "tftp: %s: ", argv[n]);
                                herror((char *)NULL);
                                continue;
                        }
                        bcopy(hp->h_addr, (caddr_t)&peeraddr.sin_addr,
                            hp->h_length);
                        peeraddr.sin_family = hp->h_addrtype;
                        connected = 1;
                        hostname = xstrdup(hp->h_name);
                }
                if (argc < 4) {
                        cp = argc == 3 ? argv[2] : tail(src);
                        fd = open(cp, 
O_WRONLY|O_CREAT|O_TRUNC|mode->m_openflags, 0666);
                        if (fd < 0) {
                                fprintf(stderr, "tftp: "); perror(cp);
                                return;
                        }
                        if (verbose)
                                printf("getting from %s:%s to %s [%s]\n",
                                        hostname, src, cp, mode->m_mode);
                        peeraddr.sin_port = port;
                        tftp_recvfile(fd, src, mode->m_mode);
                        break;
                }
                cp = tail(src);         /* new .. jdg */
                fd = open(cp, O_WRONLY|O_CREAT|O_TRUNC|mode->m_openflags, 0666);
                if (fd < 0) {
                        fprintf(stderr, "tftp: "); perror(cp);
                        continue;
                }
                if (verbose)
                        printf("getting from %s:%s to %s [%s]\n",
                                hostname, src, cp, mode->m_mode);
                peeraddr.sin_port = port;
                tftp_recvfile(fd, src, mode->m_mode);
        }
}

static void
getusage(char *s)
{
        printf("usage: %s host:file host:file ... file, or\n", s);
        printf("       %s file file ... file if connected\n", s);
}

int     rexmtval = TIMEOUT;

void
setrexmt(int argc, char *argv[])
{
        int t;

        if (argc < 2) {
                getmoreargs("rexmt-timeout ", "(value) ");
                makeargv();
                argc = margc;
                argv = margv;
        }
        if (argc != 2) {
                printf("usage: %s value\n", argv[0]);
                return;
        }
        t = atoi(argv[1]);
        if (t < 0)
                printf("%s: bad value\n", argv[1]);
        else
                rexmtval = t;
}

int     maxtimeout = 5 * TIMEOUT;

void
settimeout(int argc, char *argv[])
{
        int t;

        if (argc < 2) {
                getmoreargs("maximum-timeout ", "(value) ");
                makeargv();
                argc = margc;
                argv = margv;
        }
        if (argc != 2) {
                printf("usage: %s value\n", argv[0]);
                return;
        }
        t = atoi(argv[1]);
        if (t < 0)
                printf("%s: bad value\n", argv[1]);
        else
                maxtimeout = t;
}

void
status(int argc, char *argv[])
{
        (void)argc; (void)argv; /* Quiet unused warning */
        if (connected)
                printf("Connected to %s.\n", hostname);
        else
                printf("Not connected.\n");
        printf("Mode: %s Verbose: %s Tracing: %s\n", mode->m_mode,
                verbose ? "on" : "off", trace ? "on" : "off");
        printf("Rexmt-interval: %d seconds, Max-timeout: %d seconds\n",
                rexmtval, maxtimeout);
}

void
intr(int sig)
{
        (void)sig;      /* Quiet unused warning */

        bsd_signal(SIGALRM, SIG_IGN);
        alarm(0);
        siglongjmp(toplevel, -1);
}

char *
tail(char *filename)
{
        char *s;
        
        while (*filename) {
                s = strrchr(filename, '/');
                if (s == NULL)
                        break;
                if (s[1])
                        return (s + 1);
                *s = '\0';
        }
        return (filename);
}

/*
 * Command parser.
 */
static void
command(void)
{
        struct cmd *c;

        for (;;) {
#ifdef WITH_READLINE
                if ( line )
                        free(line);
                line = readline(prompt);
                if ( !line )
                        exit(0); /* EOF */
#else
                fputs(prompt, stdout);
                if (fgets(line, LBUFLEN, stdin) == 0) {
                        if (feof(stdin)) {
                                exit(0);
                        } else {
                                continue;
                        }
                }
#endif
                if ((line[0] == 0) || (line[0] == '\n'))
                        continue;
#ifdef WITH_READLINE
#ifdef HAVE_READLINE_HISTORY_H
                add_history(line);
#endif
#endif
                makeargv();
                if (margc == 0)
                        continue;

                c = getcmd(margv[0]);
                if (c == (struct cmd *)-1) {
                        printf("?Ambiguous command\n");
                        continue;
                }
                if (c == 0) {
                        printf("?Invalid command\n");
                        continue;
                }
                (*c->handler)(margc, margv);
        }
}

struct cmd *
getcmd(char *name)
{
        const char *p;
        char *q;
        struct cmd *c, *found;
        int nmatches, longest;

        longest = 0;
        nmatches = 0;
        found = 0;
        for (c = cmdtab; (p = c->name) != NULL; c++) {
                for (q = name; *q == *p++; q++)
                        if (*q == 0)            /* exact match? */
                                return (c);
                if (!*q) {                      /* the name was a prefix */
                        if (q - name > longest) {
                                longest = q - name;
                                nmatches = 1;
                                found = c;
                        } else if (q - name == longest)
                                nmatches++;
                }
        }
        if (nmatches > 1)
                return ((struct cmd *)-1);
        return (found);
}

/*
 * Slice a string up into argc/argv.
 */
static void
makeargv(void)
{
        char *cp;
        char **argp = margv;

        margc = 0;
        for (cp = line; *cp;) {
                while (isspace(*cp))
                        cp++;
                if (*cp == '\0')
                        break;
                *argp++ = cp;
                margc += 1;
                while (*cp != '\0' && !isspace(*cp))
                        cp++;
                if (*cp == '\0')
                        break;
                *cp++ = '\0';
        }
        *argp++ = 0;
}

void
quit(int argc, char *argv[])
{
        (void)argc; (void)argv; /* Quiet unused warning */
        exit(0);
}

/*
 * Help command.
 */
void
help(int argc, char *argv[])
{
        struct cmd *c;

        printf("%s\n", VERSION);

        if (argc == 1) {
                printf("Commands may be abbreviated.  Commands are:\n\n");
                for (c = cmdtab; c->name; c++)
                        printf("%-*s\t%s\n", (int)HELPINDENT, c->name, c->help);
                return;
        }
        while (--argc > 0) {
                char *arg;
                arg = *++argv;
                c = getcmd(arg);
                if (c == (struct cmd *)-1)
                        printf("?Ambiguous help command %s\n", arg);
                else if (c == (struct cmd *)0)
                        printf("?Invalid help command %s\n", arg);
                else
                        printf("%s\n", c->help);
        }
}

void
settrace(int argc, char *argv[])
{
        (void)argc; (void)argv; /* Quiet unused warning */

        trace = !trace;
        printf("Packet tracing %s.\n", trace ? "on" : "off");
}

void
setverbose(int argc, char *argv[])
{
        (void)argc; (void)argv; /* Quiet unused warning */

        verbose = !verbose;
        printf("Verbose mode %s.\n", verbose ? "on" : "off");
}
_______________________________________________
lwip-users mailing list
[email protected]
http://lists.nongnu.org/mailman/listinfo/lwip-users

Reply via email to