view src/scanner.cpp @ 6:cea50d98a6cf

start work on content url scanner
author carl
date Wed, 21 Apr 2004 22:39:46 -0700
parents
children 93ff6d1ef647
line wrap: on
line source

// normal stuff
#include <stdio.h>
#include <stdlib.h>

// needed for std c++ collections
#include <set>
#include <map>
#include <list>

// for the dns resolver
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <resolv.h>

// misc stuff needed here
#include <ctype.h>
#include <fstream>

static char* version="$Id$";

using namespace std;

enum status {oksofar,   // not rejected yet
             white,     // whitelisted by envelope from
             black,     // blacklisted by envelope from or to
             reject};   // rejected by a dns list

enum state {//u_init,         // url  decoder states

            m_init,         // mime decoder states
            m_eq,
            m_1,

            e_init,         // html entity decoder states
            e_amp,
            e_num,

            b_init,         // base64 decoder states
            b_lf,
            b_lf2,
            b_64,

            end_state,      // counter for number of columns in the table

            m_2,            // temporary mime states
            m_cr,
            m_nl,
            e_semi,
            b_cr,
           };

typedef state PARSE[end_state];

static PARSE parse_table[256] = {
  // m_init,    m_eq,   m_1,    e_init, e_amp,  e_num,  b_init, b_lf,   b_lf2,  b_64

    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x00
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x01
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x02
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x03
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x04
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x05
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x06
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x07
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x08
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x09
    {m_init,    m_nl,   m_init, e_init, e_init, e_init, b_lf,   b_init, b_lf2,  b_init,  },  // 0x0a <lf>
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x0b
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x0c
    {m_init,    m_cr,   m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_cr,    },  // 0x0d <cr>
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x0e
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x0f
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x10
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x11 xon char
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x12
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x13 xoff char
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x14
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x15
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x16
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x17
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x18
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x19
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x1a
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x1b
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x1c
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x1d
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x1e
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x1f
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x20 space
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x21 !
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x22 ""
    {m_init,    m_init, m_init, e_init, e_num,  e_init, b_init, b_init, b_init, b_init,  },  // 0x23 #
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x24 $
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x25 %
    {m_init,    m_init, m_init, e_amp,  e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x26 &
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x27 '
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x28 (
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x29 )
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x2A *
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_64,   b_64,   b_64,    },  // 0x2B +
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x2C ,
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x2D -
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x2E .
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_64,   b_64,   b_64,    },  // 0x2F /
    {m_init,    m_1,    m_2,    e_init, e_init, e_num,  b_init, b_64,   b_64,   b_64,    },  // 0x30 0
    {m_init,    m_1,    m_2,    e_init, e_init, e_num,  b_init, b_64,   b_64,   b_64,    },  // 0x31 1
    {m_init,    m_1,    m_2,    e_init, e_init, e_num,  b_init, b_64,   b_64,   b_64,    },  // 0x32 2
    {m_init,    m_1,    m_2,    e_init, e_init, e_num,  b_init, b_64,   b_64,   b_64,    },  // 0x33 3
    {m_init,    m_1,    m_2,    e_init, e_init, e_num,  b_init, b_64,   b_64,   b_64,    },  // 0x34 4
    {m_init,    m_1,    m_2,    e_init, e_init, e_num,  b_init, b_64,   b_64,   b_64,    },  // 0x35 5
    {m_init,    m_1,    m_2,    e_init, e_init, e_num,  b_init, b_64,   b_64,   b_64,    },  // 0x36 6
    {m_init,    m_1,    m_2,    e_init, e_init, e_num,  b_init, b_64,   b_64,   b_64,    },  // 0x37 7
    {m_init,    m_1,    m_2,    e_init, e_init, e_num,  b_init, b_64,   b_64,   b_64,    },  // 0x38 8
    {m_init,    m_1,    m_2,    e_init, e_init, e_num,  b_init, b_64,   b_64,   b_64,    },  // 0x39 9
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x3A :
    {m_init,    m_init, m_init, e_init, e_init, e_semi, b_init, b_init, b_init, b_init,  },  // 0x3B ;
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x3C <
    {m_eq,      m_init, m_init, e_init, e_init, e_init, b_init, b_64,   b_64,   b_64,    },  // 0x3D =
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x3E >
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x3F ?
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x40 @
    {m_init,    m_1,    m_2,    e_init, e_init, e_init, b_init, b_64,   b_64,   b_64,    },  // 0x41 A
    {m_init,    m_1,    m_2,    e_init, e_init, e_init, b_init, b_64,   b_64,   b_64,    },  // 0x42 B
    {m_init,    m_1,    m_2,    e_init, e_init, e_init, b_init, b_64,   b_64,   b_64,    },  // 0x43 C
    {m_init,    m_1,    m_2,    e_init, e_init, e_init, b_init, b_64,   b_64,   b_64,    },  // 0x44 D
    {m_init,    m_1,    m_2,    e_init, e_init, e_init, b_init, b_64,   b_64,   b_64,    },  // 0x45 E
    {m_init,    m_1,    m_2,    e_init, e_init, e_init, b_init, b_64,   b_64,   b_64,    },  // 0x46 F
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_64,   b_64,   b_64,    },  // 0x47 G
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_64,   b_64,   b_64,    },  // 0x48 H
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_64,   b_64,   b_64,    },  // 0x49 I
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_64,   b_64,   b_64,    },  // 0x4A J
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_64,   b_64,   b_64,    },  // 0x4B K
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_64,   b_64,   b_64,    },  // 0x4C L
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_64,   b_64,   b_64,    },  // 0x4D M
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_64,   b_64,   b_64,    },  // 0x4E N
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_64,   b_64,   b_64,    },  // 0x4F O
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_64,   b_64,   b_64,    },  // 0x50 P
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_64,   b_64,   b_64,    },  // 0x51 Q
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_64,   b_64,   b_64,    },  // 0x52 R
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_64,   b_64,   b_64,    },  // 0x53 S
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_64,   b_64,   b_64,    },  // 0x54 T
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_64,   b_64,   b_64,    },  // 0x55 U
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_64,   b_64,   b_64,    },  // 0x56 V
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_64,   b_64,   b_64,    },  // 0x57 W
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_64,   b_64,   b_64,    },  // 0x58 X
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_64,   b_64,   b_64,    },  // 0x59 Y
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_64,   b_64,   b_64,    },  // 0x5A Z
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x5B [
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x5C brace
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x5D ]
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x5E ^
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x5F _
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x60 `
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_64,   b_64,   b_64,    },  // 0x61 a
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_64,   b_64,   b_64,    },  // 0x62 b
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_64,   b_64,   b_64,    },  // 0x63 c
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_64,   b_64,   b_64,    },  // 0x64 d
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_64,   b_64,   b_64,    },  // 0x65 e
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_64,   b_64,   b_64,    },  // 0x66 f
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_64,   b_64,   b_64,    },  // 0x67 g
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_64,   b_64,   b_64,    },  // 0x68 h
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_64,   b_64,   b_64,    },  // 0x69 i
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_64,   b_64,   b_64,    },  // 0x6A j
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_64,   b_64,   b_64,    },  // 0x6B k
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_64,   b_64,   b_64,    },  // 0x6C l
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_64,   b_64,   b_64,    },  // 0x6D m
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_64,   b_64,   b_64,    },  // 0x6E n
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_64,   b_64,   b_64,    },  // 0x6F o
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_64,   b_64,   b_64,    },  // 0x70 p
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_64,   b_64,   b_64,    },  // 0x71 q
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_64,   b_64,   b_64,    },  // 0x72 r
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_64,   b_64,   b_64,    },  // 0x73 s
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_64,   b_64,   b_64,    },  // 0x74 t
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_64,   b_64,   b_64,    },  // 0x75 u
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_64,   b_64,   b_64,    },  // 0x76 v
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_64,   b_64,   b_64,    },  // 0x77 w
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_64,   b_64,   b_64,    },  // 0x78 x
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_64,   b_64,   b_64,    },  // 0x79 y
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_64,   b_64,   b_64,    },  // 0x7A z
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x7B {
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x7C |
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x7D }
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x7E ~
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x7f
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x80
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x81
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x82
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x83
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x84
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x85
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x86
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x87
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x88
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x89
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x8a
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x8b
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x8c
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x8d
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x8e
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x8f
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x90
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x91
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x92
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x93
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x94
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x95
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x96
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x97
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x98
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x99
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x9a
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x9b
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x9c
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x9d
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x9e
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0x9f
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xa0
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xa1
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xa2
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xa3
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xa4
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xa5
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xa6
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xa7
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xa8
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xa9
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xaa
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xab
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xac
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xad
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xae
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xaf
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xb0
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xb1
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xb2
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xb3
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xb4
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xb5
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xb6
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xb7
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xb8
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xb9
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xba
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xbb
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xbc
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xbd
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xbe
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xbf
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xc0
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xc1
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xc2
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xc3
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xc4
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xc5
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xc6
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xc7
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xc8
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xc9
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xca
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xcb
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xcc
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xcd
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xce
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xcf
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xd0
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xd1
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xd2
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xd3
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xd4
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xd5
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xd6
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xd7
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xd8
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xd9
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xda
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xdb
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xdc
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xdd
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xde
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xdf
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xe0
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xe1
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xe2
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xe3
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xe4
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xe5
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xe6
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xe7
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xe8
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xe9
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xea
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xeb
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xec
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xed
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xee
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xef
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xf0
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xf1
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xf2
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xf3
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xf4
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xf5
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xf6
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xf7
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xf8
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xf9
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xfa
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xfb
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xfc
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xfd
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xfe
    {m_init,    m_init, m_init, e_init, e_init, e_init, b_init, b_init, b_init, b_init,  },  // 0xff
};


u_char hex_decode[256] = {
    0,  // 0x00
    0,  // 0x01
    0,  // 0x02
    0,  // 0x03
    0,  // 0x04
    0,  // 0x05
    0,  // 0x06
    0,  // 0x07
    0,  // 0x08
    0,  // 0x09
    0,  // 0x0a
    0,  // 0x0b
    0,  // 0x0c
    0,  // 0x0d
    0,  // 0x0e
    0,  // 0x0f
    0,  // 0x10
    0,  // 0x11 xon char
    0,  // 0x12
    0,  // 0x13 xoff char
    0,  // 0x14
    0,  // 0x15
    0,  // 0x16
    0,  // 0x17
    0,  // 0x18
    0,  // 0x19
    0,  // 0x1a
    0,  // 0x1b
    0,  // 0x1c
    0,  // 0x1d
    0,  // 0x1e
    0,  // 0x1f
    0,  // 0x20 space
    0,  // 0x21 !
    0,  // 0x22 ""
    0,  // 0x23 #
    0,  // 0x24 $
    0,  // 0x25 %
    0,  // 0x26 &
    0,  // 0x27 '
    0,  // 0x28 (
    0,  // 0x29 )
    0,  // 0x2A *
    0,  // 0x2B +
    0,  // 0x2C ,
    0,  // 0x2D -
    0,  // 0x2E .
    0,  // 0x2F /
    0,  // 0x30 0
    1,  // 0x31 1
    2,  // 0x32 2
    3,  // 0x33 3
    4,  // 0x34 4
    5,  // 0x35 5
    6,  // 0x36 6
    7,  // 0x37 7
    8,  // 0x38 8
    9,  // 0x39 9
    0,  // 0x3A :
    0,  // 0x3B ;
    0,  // 0x3C <
    0,  // 0x3D =
    0,  // 0x3E >
    0,  // 0x3F ?
    0,  // 0x40 @
    10, // 0x41 A
    11, // 0x42 B
    12, // 0x43 C
    13, // 0x44 D
    14, // 0x45 E
    15, // 0x46 F
    0,  // 0x47 G
    0,  // 0x48 H
    0,  // 0x49 I
    0,  // 0x4A J
    0,  // 0x4B K
    0,  // 0x4C L
    0,  // 0x4D M
    0,  // 0x4E N
    0,  // 0x4F O
    0,  // 0x50 P
    0,  // 0x51 Q
    0,  // 0x52 R
    0,  // 0x53 S
    0,  // 0x54 T
    0,  // 0x55 U
    0,  // 0x56 V
    0,  // 0x57 W
    0,  // 0x58 X
    0,  // 0x59 Y
    0,  // 0x5A Z
    0,  // 0x5B [
    0,  // 0x5C brace
    0,  // 0x5D ]
    0,  // 0x5E ^
    0,  // 0x5F _
    0,  // 0x60 `
    10, // 0x61 a
    11, // 0x62 b
    12, // 0x63 c
    13, // 0x64 d
    14, // 0x65 e
    15, // 0x66 f
    0,  // 0x67 g
    0,  // 0x68 h
    0,  // 0x69 i
    0,  // 0x6A j
    0,  // 0x6B k
    0,  // 0x6C l
    0,  // 0x6D m
    0,  // 0x6E n
    0,  // 0x6F o
    0,  // 0x70 p
    0,  // 0x71 q
    0,  // 0x72 r
    0,  // 0x73 s
    0,  // 0x74 t
    0,  // 0x75 u
    0,  // 0x76 v
    0,  // 0x77 w
    0,  // 0x78 x
    0,  // 0x79 y
    0,  // 0x7A z
    0,  // 0x7B {
    0,  // 0x7C |
    0,  // 0x7D }
    0,  // 0x7E ~
    0,  // 0x7f
    0,  // 0x80
    0,  // 0x81
    0,  // 0x82
    0,  // 0x83
    0,  // 0x84
    0,  // 0x85
    0,  // 0x86
    0,  // 0x87
    0,  // 0x88
    0,  // 0x89
    0,  // 0x8a
    0,  // 0x8b
    0,  // 0x8c
    0,  // 0x8d
    0,  // 0x8e
    0,  // 0x8f
    0,  // 0x90
    0,  // 0x91
    0,  // 0x92
    0,  // 0x93
    0,  // 0x94
    0,  // 0x95
    0,  // 0x96
    0,  // 0x97
    0,  // 0x98
    0,  // 0x99
    0,  // 0x9a
    0,  // 0x9b
    0,  // 0x9c
    0,  // 0x9d
    0,  // 0x9e
    0,  // 0x9f
    0,  // 0xa0
    0,  // 0xa1
    0,  // 0xa2
    0,  // 0xa3
    0,  // 0xa4
    0,  // 0xa5
    0,  // 0xa6
    0,  // 0xa7
    0,  // 0xa8
    0,  // 0xa9
    0,  // 0xaa
    0,  // 0xab
    0,  // 0xac
    0,  // 0xad
    0,  // 0xae
    0,  // 0xaf
    0,  // 0xb0
    0,  // 0xb1
    0,  // 0xb2
    0,  // 0xb3
    0,  // 0xb4
    0,  // 0xb5
    0,  // 0xb6
    0,  // 0xb7
    0,  // 0xb8
    0,  // 0xb9
    0,  // 0xba
    0,  // 0xbb
    0,  // 0xbc
    0,  // 0xbd
    0,  // 0xbe
    0,  // 0xbf
    0,  // 0xc0
    0,  // 0xc1
    0,  // 0xc2
    0,  // 0xc3
    0,  // 0xc4
    0,  // 0xc5
    0,  // 0xc6
    0,  // 0xc7
    0,  // 0xc8
    0,  // 0xc9
    0,  // 0xca
    0,  // 0xcb
    0,  // 0xcc
    0,  // 0xcd
    0,  // 0xce
    0,  // 0xcf
    0,  // 0xd0
    0,  // 0xd1
    0,  // 0xd2
    0,  // 0xd3
    0,  // 0xd4
    0,  // 0xd5
    0,  // 0xd6
    0,  // 0xd7
    0,  // 0xd8
    0,  // 0xd9
    0,  // 0xda
    0,  // 0xdb
    0,  // 0xdc
    0,  // 0xdd
    0,  // 0xde
    0,  // 0xdf
    0,  // 0xe0
    0,  // 0xe1
    0,  // 0xe2
    0,  // 0xe3
    0,  // 0xe4
    0,  // 0xe5
    0,  // 0xe6
    0,  // 0xe7
    0,  // 0xe8
    0,  // 0xe9
    0,  // 0xea
    0,  // 0xeb
    0,  // 0xec
    0,  // 0xed
    0,  // 0xee
    0,  // 0xef
    0,  // 0xf0
    0,  // 0xf1
    0,  // 0xf2
    0,  // 0xf3
    0,  // 0xf4
    0,  // 0xf5
    0,  // 0xf6
    0,  // 0xf7
    0,  // 0xf8
    0,  // 0xf9
    0,  // 0xfa
    0,  // 0xfb
    0,  // 0xfc
    0,  // 0xfd
    0,  // 0xfe
    0,  // 0xff
};
u_char b64_decode[256] = {
    0,  // 0x00
    0,  // 0x01
    0,  // 0x02
    0,  // 0x03
    0,  // 0x04
    0,  // 0x05
    0,  // 0x06
    0,  // 0x07
    0,  // 0x08
    0,  // 0x09
    0,  // 0x0a
    0,  // 0x0b
    0,  // 0x0c
    0,  // 0x0d
    0,  // 0x0e
    0,  // 0x0f
    0,  // 0x10
    0,  // 0x11 xon char
    0,  // 0x12
    0,  // 0x13 xoff char
    0,  // 0x14
    0,  // 0x15
    0,  // 0x16
    0,  // 0x17
    0,  // 0x18
    0,  // 0x19
    0,  // 0x1a
    0,  // 0x1b
    0,  // 0x1c
    0,  // 0x1d
    0,  // 0x1e
    0,  // 0x1f
    0,  // 0x20 space
    0,  // 0x21 !
    0,  // 0x22 ""
    0,  // 0x23 #
    0,  // 0x24 $
    0,  // 0x25 %
    0,  // 0x26 &
    0,  // 0x27 '
    0,  // 0x28 (
    0,  // 0x29 )
    0,  // 0x2A *
    62, // 0x2B +
    0,  // 0x2C ,
    0,  // 0x2D -
    0,  // 0x2E .
    63, // 0x2F /
    52, // 0x30 0
    53, // 0x31 1
    54, // 0x32 2
    55, // 0x33 3
    56, // 0x34 4
    57, // 0x35 5
    58, // 0x36 6
    59, // 0x37 7
    60, // 0x38 8
    61, // 0x39 9
    0,  // 0x3A :
    0,  // 0x3B ;
    0,  // 0x3C <
    0,  // 0x3D =
    0,  // 0x3E >
    0,  // 0x3F ?
    0,  // 0x40 @
     0, // 0x41 A
     1, // 0x42 B
     2, // 0x43 C
     3, // 0x44 D
     4, // 0x45 E
     5, // 0x46 F
     6, // 0x47 G
     7, // 0x48 H
     8, // 0x49 I
     9, // 0x4A J
    10, // 0x4B K
    11, // 0x4C L
    12, // 0x4D M
    13, // 0x4E N
    14, // 0x4F O
    15, // 0x50 P
    16, // 0x51 Q
    17, // 0x52 R
    18, // 0x53 S
    19, // 0x54 T
    20, // 0x55 U
    21, // 0x56 V
    22, // 0x57 W
    23, // 0x58 X
    24, // 0x59 Y
    25, // 0x5A Z
    0,  // 0x5B [
    0,  // 0x5C brace
    0,  // 0x5D ]
    0,  // 0x5E ^
    0,  // 0x5F _
    0,  // 0x60 `
    26, // 0x61 a
    27, // 0x62 b
    28, // 0x63 c
    29, // 0x64 d
    30, // 0x65 e
    31, // 0x66 f
    32, // 0x67 g
    33, // 0x68 h
    34, // 0x69 i
    35, // 0x6A j
    36, // 0x6B k
    37, // 0x6C l
    38, // 0x6D m
    39, // 0x6E n
    40, // 0x6F o
    41, // 0x70 p
    42, // 0x71 q
    43, // 0x72 r
    44, // 0x73 s
    45, // 0x74 t
    46, // 0x75 u
    47, // 0x76 v
    48, // 0x77 w
    49, // 0x78 x
    50, // 0x79 y
    51, // 0x7A z
    0,  // 0x7B {
    0,  // 0x7C |
    0,  // 0x7D }
    0,  // 0x7E ~
    0,  // 0x7f
    0,  // 0x80
    0,  // 0x81
    0,  // 0x82
    0,  // 0x83
    0,  // 0x84
    0,  // 0x85
    0,  // 0x86
    0,  // 0x87
    0,  // 0x88
    0,  // 0x89
    0,  // 0x8a
    0,  // 0x8b
    0,  // 0x8c
    0,  // 0x8d
    0,  // 0x8e
    0,  // 0x8f
    0,  // 0x90
    0,  // 0x91
    0,  // 0x92
    0,  // 0x93
    0,  // 0x94
    0,  // 0x95
    0,  // 0x96
    0,  // 0x97
    0,  // 0x98
    0,  // 0x99
    0,  // 0x9a
    0,  // 0x9b
    0,  // 0x9c
    0,  // 0x9d
    0,  // 0x9e
    0,  // 0x9f
    0,  // 0xa0
    0,  // 0xa1
    0,  // 0xa2
    0,  // 0xa3
    0,  // 0xa4
    0,  // 0xa5
    0,  // 0xa6
    0,  // 0xa7
    0,  // 0xa8
    0,  // 0xa9
    0,  // 0xaa
    0,  // 0xab
    0,  // 0xac
    0,  // 0xad
    0,  // 0xae
    0,  // 0xaf
    0,  // 0xb0
    0,  // 0xb1
    0,  // 0xb2
    0,  // 0xb3
    0,  // 0xb4
    0,  // 0xb5
    0,  // 0xb6
    0,  // 0xb7
    0,  // 0xb8
    0,  // 0xb9
    0,  // 0xba
    0,  // 0xbb
    0,  // 0xbc
    0,  // 0xbd
    0,  // 0xbe
    0,  // 0xbf
    0,  // 0xc0
    0,  // 0xc1
    0,  // 0xc2
    0,  // 0xc3
    0,  // 0xc4
    0,  // 0xc5
    0,  // 0xc6
    0,  // 0xc7
    0,  // 0xc8
    0,  // 0xc9
    0,  // 0xca
    0,  // 0xcb
    0,  // 0xcc
    0,  // 0xcd
    0,  // 0xce
    0,  // 0xcf
    0,  // 0xd0
    0,  // 0xd1
    0,  // 0xd2
    0,  // 0xd3
    0,  // 0xd4
    0,  // 0xd5
    0,  // 0xd6
    0,  // 0xd7
    0,  // 0xd8
    0,  // 0xd9
    0,  // 0xda
    0,  // 0xdb
    0,  // 0xdc
    0,  // 0xdd
    0,  // 0xde
    0,  // 0xdf
    0,  // 0xe0
    0,  // 0xe1
    0,  // 0xe2
    0,  // 0xe3
    0,  // 0xe4
    0,  // 0xe5
    0,  // 0xe6
    0,  // 0xe7
    0,  // 0xe8
    0,  // 0xe9
    0,  // 0xea
    0,  // 0xeb
    0,  // 0xec
    0,  // 0xed
    0,  // 0xee
    0,  // 0xef
    0,  // 0xf0
    0,  // 0xf1
    0,  // 0xf2
    0,  // 0xf3
    0,  // 0xf4
    0,  // 0xf5
    0,  // 0xf6
    0,  // 0xf7
    0,  // 0xf8
    0,  // 0xf9
    0,  // 0xfa
    0,  // 0xfb
    0,  // 0xfc
    0,  // 0xfd
    0,  // 0xfe
    0,  // 0xff
};

#define PENDING_LIMIT 1000
struct fsa {
    u_char  pending[PENDING_LIMIT];
    int     count;
    state   st;
    state   init;
    fsa*    next;

    fsa(state init, fsa* next_);
    void push(u_char *buf, int len);
};

fsa::fsa(state init_, fsa* next_) {
    count = 0;
    st    = init_;
    init  = init_;
    next  = next_;
}

void fsa::push(u_char *buf, int len) {
    for (int i=0; i<len; i++) {
        u_char c = buf[i];
        // guard against buffer overflow
        if (count == PENDING_LIMIT-1) {
            if (next) next->push(pending, count);
            else {
                pending[count] = 0;
                fprintf(stdout, "%s", (char*)pending);
            }
            count = 0;
            st    = init;
        }
        pending[count++] = c;
        st = parse_table[c][st];
        switch (st) {

            //////////////////////////////
            //  mime decoder
            case m_2: {
                pending[0] = hex_decode[pending[1]] * 16 + hex_decode[pending[2]];
                count = 1;
                st    = m_init;
                } // fall thru

            case m_init: {
                if (next) next->push(pending, count);
                else {
                    pending[count] = 0;
                    fprintf(stdout, "%s", (char*)pending);
                }
                count = 0;
                } break;

            case m_cr: {
                count = 1;
                st    = m_eq;
                } break;

            case m_nl: {
                count = 0;
                st    = m_init;
                } break;

            //////////////////////////////
            //  html entity decoder
            case e_semi: {
                pending[--count] = '\0';  // null terminate the digit string by overwriting the semicolon
                pending[0] = atoi((const char *)pending+2);
                count = 1;
                st    = e_init;
                } // fall thru

            case e_init: {
                if (next) next->push(pending, count);
                else {
                    pending[count] = 0;
                    fprintf(stdout, "%s", (char*)pending);
                }
                count = 0;
                } break;

            //////////////////////////////
            //  base64 decoder
            case b_lf2: {
                count--;
                } break;

            case b_cr: {
                int cnt = 0;
                if ((count % 4) == 1) {
                    count--;
                    // might have proper b64 data
                    for (int i=0; i<count; i+=4) {
                        unsigned long a1 = b64_decode[pending[i]];
                        unsigned long a2 = b64_decode[pending[i+1]];
                        unsigned long a3 = b64_decode[pending[i+2]];
                        unsigned long a4 = b64_decode[pending[i+3]];
                        unsigned long a = (a1 << 18) | (a2 << 12) | (a3 << 6) | a4;
                        pending[cnt++] = (a & 0x00ff0000) >> 16;
                        pending[cnt++] = (a & 0x0000ff00) >>  8;
                        pending[cnt++] = (a & 0x000000ff);
                        if ((char)pending[i+3] == '=') cnt--;
                        if ((char)pending[i+2] == '=') cnt--;
                    }
                    count = cnt;
                    st    = b_lf2;
                }
                else st = b_init;
                } // fall thru

            case b_lf:
            case b_init: {
                if (next) next->push(pending, count);
                else {
                    pending[count] = 0;
                    fprintf(stdout, "%s", (char*)pending);
                }
                count = 0;
                } break;

            //////////////////////////////
            //  states that just accumulate characters in the pending buffer
            case e_amp:
            case e_num:
            case b_64:
            case m_eq:
            case m_1:
            default: {
                } break;
        }
    }
}



////////////////////////////////////////////////
//  ask a dns question and get an A record answer
//
static unsigned long dns_interface(char *question);
static unsigned long dns_interface(char *question) {
    u_char answer[NS_PACKETSZ];
    int length = res_search(question, ns_c_in, ns_t_a, answer, sizeof(answer));
    if (length < 0) return oksofar;     // error in getting answer
    // parse the answer
    ns_msg handle;
    ns_rr  rr;
    if (ns_initparse(answer, length, &handle) != 0) return oksofar;
    int rrnum = 0;
    while (ns_parserr(&handle, ns_s_an, rrnum++, &rr) == 0) {
        if (ns_rr_type(rr) == ns_t_a) {
            unsigned long address;
            memcpy(&address, ns_rr_rdata(rr), sizeof(address));
            return reject;
        }
    }
    return 0;
}

////////////////////////////////////////////////
//  check a single dnsbl - we don't try very hard, just
//  using the default resolver retry settings. If we cannot
//  get an answer, we just accept the mail. The caller
//  must ensure thread safety.
//
static status check_single(int ip, char *suffix);
static status check_single(int ip, char *suffix) {
    // make a dns question
    const u_char *src = (const u_char *)&ip;
    if (src[0] == 127) return oksofar;  // don't do dns lookups on localhost
    char question[NS_MAXDNAME];
    snprintf(question, sizeof(question), "%u.%u.%u.%u.%s.", src[3], src[2], src[1], src[0], suffix);
    // ask the question, if we get an A record it implies a blacklisted ip address
    unsigned long ans = dns_interface(question);
    return (ans) ? reject : oksofar;
}


////////////////////////////////////////////////
//  scan a file for URLs
//
static void scan_file(char *fn, fsa& parser);
static void scan_file(char *fn, fsa& parser) {
    const int LINE_SIZE = 2000;
    char line[LINE_SIZE];
    ifstream is(fn);
    while (!is.eof()) {
        is.getline(line, LINE_SIZE-1);
        int n = strlen(line);
        line[n++] = '\n';
        parser.push((u_char*)line, n);
    }
    is.close();
}


int main(int argc, char**argv)
{
    char *fn = argv[1];
    fsa *html_parser = new fsa(e_init, NULL);
    fsa *mime_parser = new fsa(m_init, html_parser);
    fsa *b64_parser  = new fsa(b_init, mime_parser);
    if (fn) scan_file(fn, *b64_parser);
    return 0;
}