
/*
Eagles Bulletin Board System
Copyright (C) 1994, Ray Rocker, rrrocker@rock.b11.ingr.com
                                rock@seabass.st.usm.edu
                                72673.2105@compuserve.com

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "server.h"
#include <unistd.h>

#define PROTOFILE "etc/protos"

/* 
   The PROTOFILE lists the available protocols for uploading/downloading.
   Format is:

   protoname:send-binary:receive-binary
*/

typedef struct _PROTOCOL {
  NAME name;
  PATH sendbin;
  PATH recvbin;
  SHORT recv_pipe;
} PROTOCOL;

protoent_to_proto(rec, proto)
char *rec;
PROTOCOL *proto;
{
  proto->recv_pipe = 0;
  rec = _extract_quoted(rec, proto->name, sizeof(proto->name));
  rec = _extract_quoted(rec, proto->sendbin, sizeof proto->sendbin);
  if (*rec == '|') {
    proto->recv_pipe = 1;
    rec++;
  }    
  _extract_quoted(rec, proto->recvbin, sizeof(proto->recvbin));
  return S_OK;
}

_lookup_protocol(pname, proto)
char *pname;
PROTOCOL *proto;
{
  int rc;
  memset(proto, 0, sizeof *proto);
  rc = _record_find(PROTOFILE, _match_first, pname, protoent_to_proto, proto);
  return rc;
}

/*ARGSUSED*/
_fill_protonames(indx, rec, list)
int indx;
char *rec;
NAMELIST *list;
{
  PROTOCOL proto;
  protoent_to_proto(rec, &proto);
  add_namelist(list, proto.name, NULL);
  return S_OK;
}

local_bbs_protonames(list)
NAMELIST *list;
{
  create_namelist(list);
  _record_enumerate(PROTOFILE, 0, _fill_protonames, list);  
  return S_OK;
}

#define ULDLFILE  "etc/ftplist"

/* 
   The ULDLFILE lists the directories available for upload/download.
   Format, for now, is:

   boardname:directory:description
*/

#define UPLOADBOARD "UPLOAD"

/*
   This is a special entry in the ULDLFILE which, if present, specifies
   the directory for uploads to go to. Downloading from it is not allowed.
*/

ftpent_to_board(rec, board)
char *rec;
BOARD *board;
{
  PATH bdir;  /* thrown away in this function */
  rec = _extract_quoted(rec, board->name, sizeof(board->name));
  rec = _extract_quoted(rec, bdir, sizeof bdir);
  rec = _extract_quoted(rec, board->description, sizeof(board->description));
  return S_OK;
}

ftpent_to_dir(rec, dir)
char *rec;
char *dir;
{
  NAME bname;  /* thrown away in this function */
  rec = _extract_quoted(rec, bname, sizeof(bname));
  rec = _extract_quoted(rec, dir, PATHLEN+1);
  return S_OK;
}

_lookup_ftpent(bname, board)
char *bname;
BOARD *board;
{
  int rc;
  memset(board, 0, sizeof *board);
  rc = _record_find(ULDLFILE, _match_first, bname, ftpent_to_board, board);
  if (!strcmp(board->name, UPLOADBOARD)) return S_NOTFOUND;
  return rc;
}

get_fileboard_directory(bname, dir)
char *bname;
char *dir;
{
  int rc;
  dir[0] = '\0';
  rc = _record_find(ULDLFILE, _match_first, bname, ftpent_to_dir, dir);
  return rc;
}

_enum_fileboards(indx, rec, en)
int indx;
char *rec;
struct enumstruct *en;
{
  BOARD board;
  memset(&board, '\0', sizeof board);
  ftpent_to_board(rec, &board);
  if (!strcmp(board.name, UPLOADBOARD)) return S_OK;
  if (en->fn(indx, &board, en->arg) == ENUM_QUIT) return ENUM_QUIT;
  return S_OK;
}

/*ARGSUSED*/
local_bbs_enum_fileboards(chunk, startrec, enumfn, arg)
SHORT chunk;
SHORT startrec;
int (*enumfn)();
void *arg;
{
  struct enumstruct en;
  en.fn = enumfn;
  en.arg = arg;
  _record_enumerate(ULDLFILE, startrec, _enum_fileboards, &en);
  return S_OK;
}

_fill_fileboardnames(indx, rec, list)
int indx;
char *rec;
NAMELIST *list;
{
  BOARD board;
  ftpent_to_board(rec, &board);
  if (strcmp(board.name, UPLOADBOARD)) {
    add_namelist(list, board.name, NULL);
  }
  return S_OK;
}

local_bbs_fileboardnames(list)
NAMELIST *list;
{
  create_namelist(list);
  _record_enumerate(ULDLFILE, 0, _fill_fileboardnames, list);  
  return S_OK;
}

_is_valid_fname(fname)
char *fname;
{
  /* To make sure no one tries to pull hanky panky, like asking to download
     /etc/passwd...*/

  if (strchr(fname, '/')) return 0;
  if (fname[0] == '\0' || fname[0] == '.') return 0;
  return 1;
}

local_bbs_upload(path, fname, protoname)
char *path;
char *fname;
char *protoname;
{
  int rc;
  char *outf = NULL;
  PROTOCOL proto;
  PATH execbuf;
  PATH upldir;

  if (get_fileboard_directory(UPLOADBOARD, upldir) != S_OK) {
    return S_DENIED;
  }

  if (protoname == NULL && path != NULL) {
    /* Special case -- just return the filename */
    strcpy(path, upldir);
    strcat(path, "/");
    strcat(path, fname);
    return S_OK;
  }

  if (_lookup_protocol(protoname, &proto) != S_OK)
    return S_INVALID;

  if (proto.recvbin[0] == '\0')
    return S_INVALID;

  if (!_is_valid_fname(fname)) return S_INVALID;

  strcpy(execbuf, proto.recvbin);
  if (!proto.recv_pipe) {
    strcat(execbuf, " ");
    strcat(execbuf, fname);
  }
  else outf = fname;

  bbslog(3, "UPLOAD %s proto %s by %s\n", fname, proto.name, my_userid());

  set_real_mode(M_ULDL);
  rc = execute(execbuf, upldir, NULL, outf, NULL, NULL, 0);
  set_real_mode(M_UNDEFINED);
      
  return (rc == 0 ? S_OK : S_SYSERR);
}

do_download(dir, fname, protoname)
char *dir;
char *fname;
char *protoname;
{
  int rc;
  PROTOCOL proto;
  PATH execbuf;

  if (_lookup_protocol(protoname, &proto) != S_OK)
    return S_INVALID;

  if (proto.sendbin[0] == '\0')
    return S_INVALID;

  if (!_is_valid_fname(fname)) return S_INVALID;

  strcpy(execbuf, proto.sendbin);
  strcat(execbuf, " ");
  strcat(execbuf, fname);

  bbslog(3, "DOWNLOAD %s proto %s by %s\n", fname, proto.name, my_userid());

  set_real_mode(M_ULDL);
  rc = execute(execbuf, dir, NULL, NULL, NULL, NULL, 0);
  set_real_mode(M_UNDEFINED);
      
  return (rc == 0 ? S_OK : S_SYSERR);
}
