/*
 * File:	reply.c
 *
 * Author:	Ulli Horlacher (framstag@rus.uni-stuttgart.de)
 *
 * History:	
 * 
 *   10 Sep 95   Framstag	initial version
 *   21 Dec 95   Framstag	changed multi-line format
 *   17 Mar 95   Framstag	replaced uname() with gethostname()
 *    8 Apr 96   Framstag	changed signature command
 *   10 May 96   Framstag	uname() is used back again
 *   13 May 96   Framstag	uname() and gethostname()
 *   24 Sep 96   Framstag	better host.domain-name determination
 *    2 Dec 96   Framstag	even better domain-name determination
 *   29 Dec 96   Framstag	included get_domainname
 *   21 Jan 97   Framstag	added reply 414
 *   23 Feb 97   Framstag	extended with TYPE=MIME
 *   24 Feb 97   Framstag	sprintf() -> snprintf()
 *    7 Dec 97   Framstag	added reply 532
 *   19 Dec 97   Framstag	added reply 540 and 541
 *   12 Mar 98   Framstag	reply 523 -> 430 (same text)
 *  2001-02-06   Framstag	added reply 429
 *
 * Send the appropiate reply code and reply text conforming to NVT telnet
 * standard. Inspired by RFC-959 (ftp).
 *
 * Copyright © 1995-2001 Ulli Horlacher
 * This file is covered by the GNU General Public License
 */

#include "config.h"		/* various #defines */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include "io.h"			/* socket and file IO extensions */

#ifdef ULTRIX
  struct utsname {
    char    sysname[32];
    char    nodename[32];
    char    release[32];
    char    version[32];
    char    machine[32];
  };
  int uname (struct utsname *);
#else
  #include <sys/utsname.h>
#endif

#if defined(SOLARIS2)
  int gethostname(char *, int);
#endif

#if defined(LINUX)
  int gethostname(char *, size_t);
#endif

#include "string.h"		/* extended string functions */


/*
 * get_domainname  - add domainname to host-string
 * 
 * INPUT:  host	- hostname
 * 
 * OUTPUT: host	- hostname.domainname or hostname (if no domain was found)
 * 
 * This is an ugly hack: we determin the domain by looking at /etc/resolf.conf
 * if not set in sendfile.cf
 */
void get_domainname(char *host) {
  char line[MAXLEN];
  char *cp;
  extern char domain[FLEN];
  FILE *inf;

  /* global variable domain set (in sendfiled.c)? */
  if (*domain) {
    
    if ((cp=strchr(host,'.'))) *(++cp)=0;

  } else {

    /* if host-name contains already a '.', we are ready */
    if (strchr(host,'.')) return;
      
    /* look in resolver config-file */
    inf=rfopen("/etc/resolv.conf","r");
    if (!inf) return;
  
    while (fgetl(line,inf)) {
      str_trim(line);
      
      /* is there the domain or search option set? */
      if (str_beq(line,"domain") || str_beq(line,"search")) {
	
	/* isolate the domain name */
	if ((cp=strchr(line,' '))) {
	  strcpy(domain,++cp);
	  if ((cp=strchr(domain,' '))) *cp=0;
	  break;
	}

      }
    }
    
    fclose(inf);
  }

  strcat(host,".");
  strcat(host,domain);

}


/*
 * reply - send string conforming to NVT telnet standard
 *
 * INPUT:  rc  - reply code
 *
 * terminates program on fatal error
 */
void reply(int rc) {
  char *text,		/* reply code and reply text */
       host[FLEN+1];	/* hostname */
#ifndef NEXT
  struct utsname sysname;
#endif

  switch (rc) {
    case 200: text="200 Command ok.";
              break;
    case 201: text="201 File has been received correctly.";
              break;
    case 202: text="202 Command not implemented, superfluous at this site.";
              break;
    case 203: text="203 *schnuffel* *schnuffel* =:3";
              break;
    case 205: text="205 Non-ASCII character in command line ignored.";
              break;
    case 214: text="214-The following commands are recognized:\r\n"
                   "214-   FROM    <sender> [<real name>]\r\n"
                   "214-   TO      <recipient>\r\n"
	           "214-   FILE    <name>\r\n"
                   "214-   SIZE    <bytes to transfer> <original file size uncompressed>\r\n"
                   "214-   TYPE    BINARY|SOURCE|MIME|TEXT=<character set name> [COMPRESSED|CRYPTED]\r\n"
                   "214-   DATE    <ISO-8601 date & time string (UTC)>\r\n"
                   "214-   SIGN    <pgp signature (armor)>\r\n"
                   "214-   ATTR    TAR|EXE|NONE\r\n"
                   "214-   MSG     <message>\r\n"
                   "214-   DEL\r\n"
                   "214-   RESEND\r\n"
                   "214-   DATA\r\n"
                   "214-   QUIT\r\n"
                   "214-All arguments have to be UTF-7 encoded.\r\n"
                   "214 You must specify at least FROM, TO, FILE, SIZE and "
                   "DATA to send a file.";
              break;
    case 215: text="215 sendfiled "VERSION"-"REVISION" for "SYSTEM;
              break;
    case 220: text=(char *) malloc(MAXLEN);
	      if (gethostname(host,FLEN)<0) 
                strcpy(host,"UNKNOWN");
              else
                get_domainname(host);
#ifdef NEXT
	      snprintf(text,MAXLEN-1,
		       "220 %s "PROTOCOL" server (sendfiled "VERSION
		       " on NeXTstep/Mach) ready.",host);
#else
              if (uname(&sysname)<0)
                snprintf(text,MAXLEN-1,"220 %s "PROTOCOL" server (sendfiled "
			 VERSION") ready.",host);
              else
		snprintf(text,MAXLEN-1,"220 %s "PROTOCOL" server (sendfiled "
			 VERSION" on %s) ready.",host,sysname.sysname);
#endif
              break;

    case 221: text="221 Goodbye.";
              break;
    case 230: text="230 <xxx Bytes already received>";
              break;
    case 231: text="231 <xxx Bytes will follow>";
              break;
    case 250: text="250 End of transfer.";
              break;
    case 260: text="260 DEBUG-OUTPUT";
              break;


    case 302: text="302 Header ok, send data.";
              break;
    case 331: text="331 <challenge: xxxxx>";
              break;


    case 401: text="401 Got unexpected EOF.";
              break;
    case 410: text="410 No access to spool directory (permission problems?).";
              break;
    case 411: text="411 Can't create user spool directory.";
              break;
    case 412: text="412 Can't write to user spool directory.";
              break;
    case 413: text="413 User spool file quota exceeded.";
              break;
    case 414: text="414 Can't start spool postprocessing.";
              break;
    case 415: text="415 TCP error: received too few data.";
              break;
    case 421: text="421 Service currently not available.";
              break;
    case 429: text="429 Timeout.";
              break;
    case 430: text="430 You are not allowed to send to this user.";
              break;
    case 451: text="451 Requested action aborted: server error.";
              break;
    case 452: text="452 Insufficient storage space.";
              break;
    case 453: text="453 Insufficient system resources.";
              break;
    case 460: text="460 Authentication error.";
              break;
    case 490: text="490 Internal error.";
              break;

    case 500: text="500 Syntax error, command unrecognized.";
              break;
    case 501: text="501 Syntax error in parameters or arguments.";
              break;
    case 502: text="502 Command not implemented.";
              break;
    case 503: text="503 Bad sequence of commands.";
              break;
    case 504: text="504 Command not implemented for that parameter.";
              break;
    case 505: text="505 Missing argument.";
              break;
    case 506: text="506 Command line too long.";
              break;
    case 507: text="507 Bad argument.";
              break;
    case 510: text="510 User has set a forward to xxx@yyy";
              text="510-This SAFT-server can only receive messages.\r\n"
                   "510 Send files to xxx@yyy";
              break;
    case 511: text="511 This SAFT-server can only receive files.\r\n";
              break;
    case 512: text="512 This SAFT-server can only receive messages.\r\n";
              break;
    case 520: text="520 User unknown.";
              break;
    case 521: text="521 User is not allowed to receive files or messages.";
              break;
    case 522: text="522 User cannot receive messages.";
              break;
    case 530: text="530 Authorization failed.";
              break;
    case 531: text="531 This file has been already received.";
              break;
    case 532: text="532 This file is currently transfered by you "
                        "within another process.";
              break;
    case 540: text="540 Secure mode enforced: you have to sign your files";
              break;
    case 541: text="541 Secure mode enforced: you have to encrypt your files";
              break;
    case 550: text="550 File not found.";
              break;
    default:  text="599 Unknown error.";
  }

  /* send string conforming to NVT standard */
  printf("%s\r\n",text);
  fflush(stdout);

  /* if a fatal and non recoverable error occured terminate the program */
  if (text[0]=='4') exit(1);
}


/*
 * from RFC-959 (ftp):
 *
 * 	 110 Restart marker reply.
 *           In this case, the text is exact and not left to the
 *           particular implementation, it must read:
 *                MARK yyyy=mmmm
 *           Where yyyy is User-process data stream marker, and mmmm
 *           server's equivalent marker (note the spaces between markers
 *	     and "=").
 *       120 Service ready in nnn minutes.
 *       125 Data connection already open, transfer starting.
 *       150 File status okay, about to open data connection.
 *
 *       200 Command okay.
 *       202 Command not implemented, superfluous at this site.
 *       211 System status, or system help reply.
 *       212 Directory status.
 *       213 File status.
 *       214 Help message.
 *           On how to use the server or the meaning of a particular
 *           non-standard command.  This reply is useful only to the
 *           human user.
 *       215 NAME system type.
 *           Where NAME is an official system name from the list in the
 *           Assigned Numbers document.
 *       220 Service ready for new user.
 *       221 Service closing control connection.
 *           Logged out if appropriate.
 *       225 Data connection open, no transfer in progress.
 *       226 Closing data connection.
 *           Requested file action successful (for example, file
 *           transfer or file abort).
 *       227 Entering Passive Mode (h1,h2,h3,h4,p1,p2).
 *       230 User logged in, proceed.
 *       250 Requested file action okay, completed.
 *       257 "PATHNAME" created.
 *
 *       331 User name okay, need password.
 *       332 Need account for login.
 *       350 Requested file action pending further information.
 *
 *       421 Service not available, closing control connection.
 *           This may be a reply to any command if the service knows it
 *           must shut down.
 *       425 Can't open data connection.
 *       426 Connection closed, transfer aborted.
 *       450 Requested file action not taken.
 *           File unavailable (e.g., file busy).
 *       451 Requested action aborted: local error in processing.
 *       452 Requested action not taken.
 *           Insufficient storage space in system.
 *       500 Syntax error, command unrecognized.
 *           This may include errors such as command line too long.
 *       501 Syntax error in parameters or arguments.
 *       502 Command not implemented.
 *       503 Bad sequence of commands.
 *       504 Command not implemented for that parameter.
 *       530 Not logged in.
 *       532 Need account for storing files.
 *       550 Requested action not taken.
 *           File unavailable (e.g., file not found, no access).
 *       551 Requested action aborted: page type unknown.
 *       552 Requested file action aborted.
 *           Exceeded storage allocation (for current directory or dataset).
 *       553 Requested action not taken.
 *           File name not allowed.
 */
