/***************************************************************************
 *
 * Copyright (c) 2000-2001 BalaBit IT Ltd, Budapest, Hungary
 *
 * 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.
 *
 * $Id: telnet.h,v 1.8.2.1 2001/09/19 19:24:41 bazsi Exp $
 *
 ***************************************************************************/
#ifndef ZORP_MODULES_TELNET_H_INCLUDED
#define ZORP_MODULES_TELNET_H_INCLUDED

#include <zorp/zorp.h>
#include <zorp/proxy.h>
#include <zorp/poll.h>
#include <zorp/dimhash.h>

/* Telnet command codes */

/* RFC 854 */
#define TELNET_IAC 255
#define TELNET_CMD_SE 240
#define TELNET_CMD_NOP 241
#define TELNET_CMD_DATAMARK 242
#define TELNET_CMD_BRK 243
#define TELNET_CMD_IP 244
#define TELNET_CMD_AO 245
#define TELNET_CMD_AYT 246
#define TELNET_CMD_EC 247
#define TELNET_CMD_EL 248
#define TELNET_CMD_GA 249
#define TELNET_CMD_SB 250
#define TELNET_CMD_WILL 251
#define TELNET_CMD_WONT 252
#define TELNET_CMD_DO 253
#define TELNET_CMD_DONT 254
#define TELNET_CMD_IAC 255

/* Telnet option codes */

/* RFC 698 - TELNET extended ASCII */
#define TELNET_OPTION_EXTEND_ASCII 17
  /* suboptions:
   * IAC SB EXTASC high_byte low_byte IAC SE
   */

/* RFC 726 - TELNET remote controlling transmission and echoing */
#define TELNET_OPTION_RCTE 7
  /* suboptions:
   * IAC SB RCTE <cmd> [BC1 BC2] [TC1 TC2] IAC SE
   *   contains [BC1 BC2] if (cmd & 8)
   *   contains [TC1 TC2] if (cmd & 16)
   */

/* RFC 727 - TELNET logout */
#define TELNET_OPTION_LOGOUT 18
  /* suboptions: none
   */

/* RFC 735 - TELNET byte macro */
#define TELNET_OPTION_BM 19
  /* suboptions:
   * IAC SB BM <DEFINE> <macro byte> <count> <replacement string> IAC SE
   *   <DEFINE> is 1
   *   <macro byte> may not be IAC (255)
   *   <couny> is a 8-bit number, indicating the length of <replacement string>
   * IAC SB BM <ACCEPT> <macro byte> IAC SE
   *   <ACCEPT> is 2
   * IAC SB BM <REFUSE> <macro byte> <REASON> IAC SE
   *   <REFUSE> is 3
   *   <REASON> may be:
   *     <BAD-CHOICE> is 1
   *     <TOO-LONG> is 2
   *     <WRONG-LENGTH> is 3
   *     <OTHER-REASON> is 0
   * IAC SB BM <LITERAL> <macro byte> IAC SE
   *   <LITERAL> is 4
   * IAC SB BM <PLEASE CANCEL> <macro byte> <REASON> IAC SE
   *   <PLEASE CANCEL> is ?
   */

/* RFC 736 - TELNET SUPDUP support */
#define TELNET_OPTION_SUPDUP 21
  /* suboptions: none
   */

/* RFC 749 - TELNET SUPDUP output */
#define TELNET_OPTION_SUPDUP_OUTPUT 22
  /* suboptions:
   * IAC SB SUPDUP-OUTPUT 1 <terminal parameters> IAC SE
   *
   * IAC SB SUPDUP-OUTPUT 2 n TD1 TD2 .. TDn SCx SCy IAC SE
   *   n is the number of TD bytes
   */

/* RFC 779 - TELNET SEND-LOCATION */
#define TELNET_OPTION_SEND_LOCATION 23
/* RFC 856 - TELNET binary transmission */
#define TELNET_OPTION_BINARY 0
/* RFC 857 - TELNET echo */
#define TELNET_OPTION_ECHO 1
/* RFC 858 - TELNET suppress go ahead */
#define TELNET_OPTION_SUPPRESS_GO_AHEAD 3
/* RFC 859 - TELNET status */
#define TELNET_OPTION_STATUS 5
/* RFC 860 - TELNET timing mark */
#define TELNET_OPTION_TIMING_MARK 6
/* RFC 861 - TELNET extended options list */
#define TELNET_OPTION_EXOPL 255
/* RFC 885 - TELNET end of record */
#define TELNET_OPTION_EOR 25
/* RFC 927 - TELNET TACACS user identification */
#define TELNET_OPTION_TUID 26
/* RFC 933 - TELNET output marking */
#define TELNET_OPTION_OUTMRK 27
/* RFC 946 - TELNET terminal location number */
#define TELNET_OPTION_TTYLOC 28
/* RFC 1041 - TELNET 3270 regime */
#define TELNET_OPTION_3270_REGIME 29
/* RFC 1043 - TELNET data entry terminal */
#define TELNET_OPTION_DET 20
/* RFC 1053 - TELNET X.3 PAD */
#define TELNET_OPTION_X3_PAD 30
/* RFC 1073 - TELNET windows size option */
#define TELNET_OPTION_NAWS 31
/* RFC 1079 - TELNET terminal speed */
#define TELNET_OPTION_TERMINAL_SPEED 32
/* RFC 1091 - TELNET terminal-type */
#define TELNET_OPTION_TERMINAL_TYPE 24
/* RFC 1096 - TELNET X display location */
#define TELNET_OPTION_X_DISPLAY_LOCATION 35
/* RFC 1184 - TELNET linemode */
#define TELNET_OPTION_LINEMODE 34
  /* new commands */
#define TELNET_OPTION_CMD_EOF 236
#define TELNET_OPTION_CMD_SUSP 237
#define TELNET_OPTION_CMD_ABORT 238
/* RFC 1372 - TELNET remote flow control */
#define TELNET_OPTION_TOGGLE_FLOW_CONTROL 33
/* RFC 1572 - TELNET environment option */
#define TELNET_OPTION_NEW_ENVIRON 39

/* proxy states */
#define TELNET_DATA 1
#define TELNET_GOT_IAC 2
#define TELNET_GOT_OPNEG 3
#define TELNET_GOT_SB 4
#define TELNET_IN_SB 5
#define TELNET_GOT_SB_IAC 6
#define TELNET_QUIT 7

/* option state codes */
#define SENT_WILL 1		/* 1/0: client sent WILL/WONT */
#define GOT_DO 2		/* 1/0: server sent DO/DONT */

/* option negotiation requests and responses */
#define WILL_OPTION 1
#define WONT_OPTION 2
#define DO_OPTION 3
#define DONT_OPTION 4

#define TELNET_BUFFER_SIZE 1024
#define TELNET_SUBOPTION_SIZE TELNET_BUFFER_SIZE

#define TELNET_CHECK_OK     1
#define TELNET_CHECK_REJECT 3
#define TELNET_CHECK_ABORT  4
#define TELNET_CHECK_DROP   5

/* policy constants */
#define TELNET_OPTION_ACCEPT 1
#define TELNET_OPTION_REJECT 3
#define TELNET_OPTION_ABORT  4
#define TELNET_OPTION_DROP   5
#define TELNET_OPTION_POLICY 6

/* macro to determine other endpoint */
#define OTHER_EP(x) ((EP_MAX - 1) - x)

/* macro to convert endpoint number to string */
#define WHICH_EP(x) (x ? "client" : "server")

struct _TelnetProxy;

typedef guint (*TelnetOptionFunction)(struct _TelnetProxy *, guint);

typedef struct _TelnetOptions {
  guint option;
  TelnetOptionFunction option_check;
} TelnetOptions;

typedef struct _ZIOBuffer
{
  guchar buf[TELNET_BUFFER_SIZE];
  guint ofs, end;
} ZIOBuffer;

typedef struct _ZIOBufferDyn
{
  guchar *buf;
  guint ofs, end, size;
} ZIOBufferDyn;

typedef struct _TelnetProxy
{
  ZProxy super;

  gint state[EP_MAX];
  gint ep;
  gint pri[EP_MAX];

  /* timeout in milliseconds */
  gint timeout;

  /* input buffers */
  ZIOBuffer read_buffers[EP_MAX];
  
  /* output buffers */
  ZIOBufferDyn write_buffers[EP_MAX];

  /* buffer to store suboption negotiation stream */
  ZIOBuffer suboptions[EP_MAX];
  
  /* option negotiation state */
  gchar options[256][EP_MAX];

  /* WILL_OPTION, WONT_OPTION, DO_OPTION or DONT_OPTION 
   * shows what was requested in TELNET_GOT_OPNEG state
   */
  guchar command[EP_MAX];

  guchar opneg_option[EP_MAX];

  /* suboption check function lookup table */
  TelnetOptionFunction telnet_options[256];
  
  /* policy hash */
  ZDimHashTable *telnet_policy;

  /* variables for the policy callbacks to be able to make changes */
  GString *policy_name, *policy_value;

  ZPoll *poll;
  
} TelnetProxy;

#endif
