// This may look like C code, but it is really -*- C++ -*-
// 
// <copyright> 
//  
//  Copyright (c) 1997
//  wer auch immer ...
//  
// </copyright> 
// 
// 
// <file> 
// 
// Name:        dbcontr_utils.C
// 
// Purpose:     
// 
// Created:     21 Feb 1997   Joerg Faschingbauer
// 
// Modified:    
// 
// Description: 
// 
// $Id: dbcontr_utils.C,v 1.1 1997/03/03 09:52:53 jfasch Exp $
// 
// $Log: dbcontr_utils.C,v $
// Revision 1.1  1997/03/03 09:52:53  jfasch
// Initial revision
//
// 
// </file> 
#include "dbcontr_utils.h"

#include <hyperg/utils/hgregexp.h>
#include <hyperg/utils/str.h>
#include <hyperg/utils/tcpmatch.h>
#include <hyperg/utils/verbose.h>

#include <stdlib.h>

// --------------------------------------------------------------------
const char* DbContrUtils :: version2 = "DbContrUtils: $Id: dbcontr_utils.C,v 1.1 1997/03/03 09:52:53 jfasch Exp $" ;

bool DbContrUtils :: isMainScope (const RString& s) {
   // not that effient, though. but nonetheless *not* time critical.
   RString tmp = s ;
   tmp.toLower() ;
   return !tmp.length() || tmp == "main" ;
}

bool DbContrUtils::TCP :: isTCP (const RString& s, RString& host, int& port) {
   static HgRegexp re ("^[ \t]*" /* leading whites */
                       "([^ \t]+)" /* host name or address */
                       "[ \t]*" /* whites */
                       "([0-9]+)" /* port number */
                       "[ \t]*" /* trailing whites */
                       "$") ;
   if (0 >= re.Match (s, s.length(), 0)) {
      DEBUGNL ("DbContrUtils::TCP::isTCP(const RString&,RString&,int&): "
               "not a TCP endpoint (was: \""<<s.string()<<"\")") ;
      return false ;
   }
   
   RString pstr (s.string() + re.BeginningOfMatch(2),
                 re.EndOfMatch(2) - re.BeginningOfMatch(2)) ;
   char* end = (char*)(pstr.string()) ; // hmm, I know, but ...
   int p = (int)::strtol (pstr.string(), &end, 10) ;
   if (pstr.string() == end) {
      DEBUGNL ("DbContrUtils::TCP::isTCP(const RString&,RString&,int&): "
               "not an integer port number (was: \""<<pstr.string()<<"\")") ;
      return false ;
   }
   
   port = p ;
   host = RString (s.string() + re.BeginningOfMatch(1),
                   re.EndOfMatch(1) - re.BeginningOfMatch(1)) ;
   return true ;
}

bool DbContrUtils::TCP :: isTCP (const RString& s, INETAddress& addr) {
   RString host ;
   int port ;
   if (! isTCP (s, host, port)) {
      DEBUGNL ("DbContrUtils::TCP::isTCP(const RString&,INETAddress&): "
               "cannot be a TCP endpoint (was: \""<<s.string()<<"\")") ;
      return false ;
   }
   INETAddress a (host.string(), port) ;
   if (! a) {
      DEBUGNL ("DbContrUtils::TCP::isTCP(const RString&,INETAddress&): "
               "not an IP address (was: \""<<host.string()<<"\")") ;
      return false ;
   }
   addr = a ;
   return true ;
}

bool DbContrUtils::TCP :: isTCPMatch (const RString& s, TCPMatch& mret) {
   static HgRegexp re ("^[ \t]*" /* leading whites */
                       "([Nn][Ee][Gg]|[Pp][Oo][Ss])" /* address operator */
                       "[ \t]*" /* whites */
                       "([^ \t]+)" /* a.a.a.a */
                       "[ \t]+" /* whites */
                       "([^ \t]+)" /* m.m.m.m */
                       "[ \t]+" /* whites */
                       "([^ \t]+)" /* op */
                       "[ \t]+" /* whites */
                       "([^ \t]+)" /* port */
                       "[ \t]*" /* trailing whites */
                       "$") ;
   
   if (! s.length()) {
      DEBUGNL ("DbContrUtils::TCP::isTCPMatch(): null length string") ;
      return false ;
   }
   
   RString negpos, addr, mask, op, port ;

   if (0 < re.Match (s, s.length(), 0)) {
      negpos = RString (s.string() + re.BeginningOfMatch(1),
                        re.EndOfMatch(1) - 
                        re.BeginningOfMatch(1)) ;
      addr = RString (s.string() + re.BeginningOfMatch(2),
                      re.EndOfMatch(2) - 
                      re.BeginningOfMatch(2)) ;
      mask = RString (s.string() + re.BeginningOfMatch(3),
                      re.EndOfMatch(3) - 
                      re.BeginningOfMatch(3)) ;
      op = RString (s.string() + re.BeginningOfMatch(4),
                    re.EndOfMatch(4) - 
                    re.BeginningOfMatch(4)) ;
      port = RString (s.string() + re.BeginningOfMatch(5),
                      re.EndOfMatch(5) - 
                      re.BeginningOfMatch(5)) ;
   }
   else {
      DEBUGNL ("DbContrUtils::TCP::isTCPMatch(): no match (string was: \""<<s.string()<<"\")") ;
      return false ;
   }

   char* end = (char*)(port.string()) ; // hmm, I know, but ...
   int p = (int /*hmm. is there a better way? lacking strtoi.*/)
           ::strtol (port.string(), &end, 10) ;
   if (end == port.string()) {
      DEBUGNL ("DbContrUtils::TCP::isTCPMatch(): bad integer (was: \""<<port.string()<<"\")") ;
      return false ;
   }

   {
      // check if the ip is right
      INETAddress a_tmp (addr.string(), 1 /* dummy to check the ip, must be non-zero */) ;
      if (! a_tmp) {
         DEBUGNL ("DbContrUtils::TCP::isTCPMatch(): "
                  "bad IP address (was: \""<<addr.string()<<"\")") ;
         return false ;
      }
   }

   INETAddress a (addr.string(), p) ;

   INETAddress m_dummy (mask.string(), 
                        1 /*dummy port, must not be zero (see class INETAddress)*/) ;
   if (! m_dummy) {
      DEBUGNL ("DbContrUtils::TCP::isTCPMatch(): "
               "bad address mask (was: \""<<mask.string()<<"\")") ;
      return false ;
   }

   TCPMatch::AddrOp aop ;
   negpos.toLower() ;
   if (negpos == "neg")
      aop = TCPMatch::TA_NEG ;
   else if (negpos == "pos") 
      aop = TCPMatch::TA_POS ;
   else {
      DEBUGNL ("DbContrUtils::TCP::isTCPMatch(): "
               "invalid port operator (was: \""<<negpos.string()<<"\")") ;
      return false ;
   }
      
   TCPMatch::PortOp pop ;
   op.toLower() ;
   if (op == "eq")
      pop = TCPMatch::TP_EQ ;
   else if (op == "neq")
      pop = TCPMatch::TP_NE ;
   else if (op == "lt")
      pop = TCPMatch::TP_L ;
   else if (op == "gt")
      pop = TCPMatch::TP_G ;
   else if (op == "le")
      pop = TCPMatch::TP_LE ;
   else if (op == "ge")
      pop = TCPMatch::TP_GE ;
   else {
      DEBUGNL ("DbContrUtils::TCP::isTCPMatch(): "
               "invalid port operator (was: \""<<op.string()<<"\")") ;
      return false ;
   }

   mret = TCPMatch (a, m_dummy.sin_addr, aop, pop) ;
   return true ;
}

bool DbContrUtils::TCP :: isSOCKS4 (const RString& s, 
                                    INETAddress& socks_server, TCPMatch& match) {
   static HgRegexp re ("^[ \t]*" /* leading whites */
                       "[Ss][Oo][Cc][Kk][Ss]4?" /* SoCkS also does it */
                       "[ \t]*" /* whites */
                       "\\(" /* opening brace */
                       "([^,]+)" /* the socks server's address is everything before ',' */
                       "," 
                       /* up to the ')' there's the TCP match the socks should swallow */
                       "([^\\)]+)"
                       "\\)" /* closing brace */
                       "[ \t]*" /* trailing whites */
                       "$") ;
   if (0 >= re.Match (s, s.length(), 0))
      // actually, most lines wont be a SOCKS4 line. 
      return false ;
   
   RString s_tcpstr (s.string() + re.BeginningOfMatch(1),
                     re.EndOfMatch(1) - re.BeginningOfMatch(1)) ;
   INETAddress s_tcp ;
   if (! isTCP (s_tcpstr, s_tcp)) {
      DEBUGNL ("DbContrUtils::TCP::isSOCKS4(): "
               "not a valid SOCKS4 line (was: \""<<s.string()<<"\")") ;
      return false ;
   }

   RString s_matchstr (s.string() + re.BeginningOfMatch(2),
                       re.EndOfMatch(2) - re.BeginningOfMatch(2)) ;
   TCPMatch s_match ;
   if (! isTCPMatch (s_matchstr, s_match)) {
      DEBUGNL ("DbContrUtils::TCP::isSOCKS4(): "
               "not TCP match (was: \""<<s_matchstr.string()<<"\")") ;
      return false ;
   }
   
   socks_server = s_tcp ;
   match = s_match ;
   return true ;
}

bool DbContrUtils::TCP :: isDIRECT (const RString& s) {
   static HgRegexp re ("^[ \t]*" /* leading whites */
                       "[Dd][Ii][Rr][Ee][Cc][Tt]"
                       "[ \t]*" /* whites */
                       "$") ;

   if (0 >= re.Match (s, s.length(), 0))
      return false ;
   else
      return true ;
}

bool DbContrUtils::TCP :: isDIRECT (const RString& s, TCPMatch& m) {
   static HgRegexp re ("^[ \t]*" /* leading whites */
                       "[Dd][Ii][Rr][Ee][Cc][Tt]"
                       "[ \t]*" /* whites */
                       "\\(" /* opening brace */
                       "([^\\)]+)" /* a TCPMatch, ending somewhere before a closing brace */
                       "\\)" /* the closing brace */
                       "[ \t]*" /* trailing whites */
                       "$") ;

   if (0 >= re.Match (s, s.length(), 0))
      return false ;

   RString matchstr (s.string() + re.BeginningOfMatch(1),
                     re.EndOfMatch(1) - re.BeginningOfMatch(1)) ;

   TCPMatch tmpmatch ;
   if (! isTCPMatch (matchstr, tmpmatch)) {
      DEBUGNL ("DbContrUtils::TCP::isDIRECT(const RString&,TCPMatch&): "
               "not a valid TCP match (was: \""<<matchstr.string()<<"\")") ;
      return false ;
   }

   m = tmpmatch ;
   return true ;
}

bool DbContrUtils::TCP :: isDENY (const RString& s, TCPMatch& m) {
   static HgRegexp re ("^[ \t]*" /* leading whites */
                       "[Dd][Ee][Nn][Yy]"
                       "[ \t]*" /* whites */
                       "\\(" /* opening brace */
                       "([^\\)]+)" /* a TCPMatch, ending somewhere before a closing brace */
                       "\\)" /* the closing brace */
                       "[ \t]*" /* trailing whites */
                       "$") ;

   if (0 >= re.Match (s, s.length(), 0))
      return false ;

   RString matchstr (s.string() + re.BeginningOfMatch(1),
                     re.EndOfMatch(1) - re.BeginningOfMatch(1)) ;

   TCPMatch tmpmatch ;
   if (! isTCPMatch (matchstr, tmpmatch)) {
      DEBUGNL ("DbContrUtils::TCP::isDIRECT(const RString&,TCPMatch&): "
               "not a valid TCP match (was: \""<<matchstr.string()<<"\")") ;
      return false ;
   }

   m = tmpmatch ;
   return true ;
}



