/*Id:$*/
/*Name:$*/

#include "stralloc.h"
#include "surf.h"
#include "uint32.h"
#include "makehash.h"

typedef struct {
  uint32 seed[32];
  uint32 sum[8];
  uint32 out[8];
  uint32 in[12];
  int todo;
} surfpcs;

#define SURFPCS_LEN 32

static void surfpcs_init(s,k)
surfpcs *s;
uint32 k[32];
{
  int i;
  for (i = 0;i < 32;++i) s->seed[i] = k[i];
  for (i = 0;i < 8;++i) s->sum[i] = 0;
  for (i = 0;i < 12;++i) s->in[i] = 0;
  s->todo = 0;
}

static uint32 littleendian[8] = {
  50462976, 117835012, 185207048, 252579084,
  319951120, 387323156, 454695192, 522067228
} ;
#define end ((unsigned char *) littleendian)

#define data ((unsigned char *) s->in)
#define outdata ((unsigned char *) s->out)

static void surfpcs_addlc(s,x,n)
	/* modified from Dan's surfpcs_add by skipping ' ' & '\t' and */
	/* case-independence */
surfpcs *s;
unsigned char *x;
unsigned int n;
{
  register unsigned char ch;
  int i;
  while (n--) {
    ch = *x++;
    if (ch == ' ' || ch == '\t') continue;
    if (ch >= 'A' && ch <= 'Z')
      data[end[s->todo++]] = ch - 'A' + 'a';
    else
      data[end[s->todo++]] = ch;
    if (s->todo == 32) {
      s->todo = 0;
      if (!++s->in[8])
        if (!++s->in[9])
          if (!++s->in[10])
            ++s->in[11];
      surf(s->out,s->in,s->seed);
      for (i = 0;i < 8;++i)
	s->sum[i] += s->out[i];
    }
  }
}

static void surfpcs_out(s,h)
surfpcs *s;
unsigned char h[32];
{
  int i;
  surfpcs_addlc(s,".",1);
  while (s->todo) surfpcs_addlc(s,"",1);
  for (i = 0;i < 8;++i) s->in[i] = s->sum[i];
  for (;i < 12;++i) s->in[i] = 0;
  surf(s->out,s->in,s->seed);
  for (i = 0;i < 32;++i) h[i] = outdata[end[i]];
}

void makehash(indata,inlen,hash)
char *indata;
unsigned int inlen;
char *hash;
	/* makes hash[COOKIE=20] from stralloc *indata, ignoring case and */
	/* SPACE/TAB */
{
  unsigned char h[32];
  surfpcs s;
  uint32 seed[32];
  int i;

  for (i = 0;i < 32;++i) seed[i] = 0;
  surfpcs_init(&s,seed);
  surfpcs_addlc(&s,indata,inlen);
  surfpcs_out(&s,h);
  for (i = 0;i < 20;++i)
    hash[i] = 'a' + (h[i] & 15);
}

static stralloc dummy = {0};

void mkauthhash(s,len,h)
char *s; unsigned int len; char *h;
/* This is a string that should be the same for all messages from a given   */
/* author. Doesn't have to be the real rfc822 address. We look for a '@'    */
/* and grab everything up to the next '>', ' ', or ';'. We go back the same */
/* way, then take everything up to the '@' or the first '-'. The latter     */
/* avoids problems with posters that band their addresses.                  */
{
  unsigned int i,j,k,l;
  register char ch;

  j = k = l = 0;
  i = byte_rchr(s,len,'@');
  if (i < len) {		/* if not then i=sa->len, j=k=l=0 */
    j = i;
    while (++j < len) {		/* if not found, then j=sa->len */
      ch = s[j];
      if (ch == '>' || ch == ' ' || ch == ';') break;
    }
    k = i;
    while (k > 0) {		/* k <= i */
      ch = s[--k];
      if (ch == '<' || ch == ' ' || ch == ';') break;
    }
    l = k;			/* k <= l <= i; */
    while (l < i && s[l] != '-') ++l;
    if (!stralloc_copyb(&dummy,s + k, l - k)) die_nomem();
    if (!stralloc_catb(&dummy,s + i, j - i)) die_nomem();
    makehash(dummy.s,dummy.len,h);
  } else			/* use entire line if no '@' found */
    makehash(s,len,h);
}


