
/*
    LinuxWare daemon - Netware like server for Linux

    Copyright (C) 1994, 1995  Ales Dryak <e-mail: A.Dryak@sh.cvut.cz>

    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.

*/
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "config.h"
#include "logging.h"
#include "mangle.h"

typedef
struct tagMangleItem
{
  char name[256];
  char mangled[MAX_MANGLED_FILENAME];
} MangleItem;

typedef
struct tagMangleList
{
  MangleItem item;
  struct tagMangleList* next;
} MangleList;

static int stat_mangle=0;
static int stat_mdirect=0;
static int stat_mhit=0;
static int stat_merrins=0;
static int stat_mcol=0;

static int stat_unmangle=0;
static int stat_ulookup=0;
static int stat_udirect=0;

static MangleList* mlist=NULL;

static MangleItem* lookup_name(char* name)
{
  MangleList* p;
  for(p=mlist;p!=NULL;p=p->next)
  {
    if (strcmp(p->item.name,name)==0) return &(p->item);
  }
  return NULL;
}

static MangleItem* lookup_mangled(char* mangled)
{
  MangleList* p;
  for(p=mlist;p!=NULL;p=p->next)
  {
    if (strcmp(p->item.mangled,mangled)==0) return &(p->item);
  }
  return NULL;
}

static MangleItem* insert_mangled(char* name,char* mangled)
{
  MangleList* p;
/*  LPRINTF(LL_INFO,("insert: name:%s mangled:%s size: %u size2: %u strlen: %u\n",name,mangled,sizeof(*p),sizeof(p->item.mangled),strlen(name)));*/
  if ((p=malloc(sizeof(*p)))==NULL) return NULL;
/*  LPRINTF(LL_INFO,("insert: malloc2\n"));*/
/*  if ((p->item.name=malloc(256))==NULL)
  {
    free(p);
    return NULL;
  }*/
/*  LPRINTF(LL_INFO,("insert: strcpy\n"));*/
  strcpy(p->item.name,name);
/*  p->item.name[0]=0;*/
/*  LPRINTF(LL_INFO,("insert: strncpy\n"));*/
/*  p->item.mangled[0]='X';
  p->item.mangled[1]='X';
  p->item.mangled[2]=0;*/
  strncpy(p->item.mangled,mangled,sizeof(p->item.mangled));
/*  LPRINTF(LL_INFO,("insert: =\n"));*/
  p->item.mangled[sizeof(p->item.mangled)-1]=0;
  p->next=mlist;
  mlist=p;
/*  LPRINTF(LL_INFO,("after insert: %s %s %p %p\n",p->item.name,p->item.mangled,p->next,p));*/
  return &(p->item);
}

static char dos_char[256];

#define EXT_SEPARATOR '.'
#define MANGLE_CHAR '~'

static int not83(unsigned char* src)
{
  /* test for valid names*/
  unsigned char* p;
  
  if (strcmp(src,".")==0) return 0;
  if (strcmp(src,"..")==0) return 0;
  for(p=src;*p;p++)
  {
    if (!dos_char[*p])
    {
      if (*p==EXT_SEPARATOR && p>src) break;
      return 1;
    }
    if (p-src>=8) return 1;
  }
  if (*p==0) return 0;
  p++;
  if (*p==0) return 1;
  if (!dos_char[*p]) return 1;
  if (*p==MANGLE_CHAR && *(p+1)!=0 && *(p+2)!=0) return 2;
  p++;
  if (*p==0) return 0;
  if (!dos_char[*p]) return 1;
  p++;
  if (*p==0) return 0;
  if (!dos_char[*p]) return 1;
  p++;
  return *p!=0?1:0;
}

#define DEFAULT_NAME "FILE"

static char* name83(char* dst,char* src)
{
  char* p;
  char* q;
  for(p=dst,q=src;!dos_char[tolower(*q)];q++)
  {
    if (*q==0)
    {
      strcpy(dst,DEFAULT_NAME);
      return dst;
    }
  }
  for(;*q && dos_char[tolower(*q)] && (p-dst)<8;p++,q++)
  {
    *p=toupper(*q);
  }
  *p=0;
  return dst;
}

#define CRC_CHARS 37
#define CRC_SIZE (CRC_CHARS*CRC_CHARS)

static char crc_chars[CRC_CHARS]="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ~";

static unsigned int crc83(char* src)
{
  unsigned int res=0;
  unsigned char* p=(unsigned char*)src;
  for(;*p;p++)
  {
    res=(res*256+*p)%CRC_SIZE;
  }
  return res;
}

char* mangle83(char* dst,char* src)
{
/*  LPRINTF(LL_INFO,("mangle: %s\n",src));*/
  int stype;
  stat_mangle++;
  stype=not83(src);
  if (stype==0)
  {
    char* p;
    char* q;
    
    stat_mdirect++;
    for(p=dst,q=src;*q;p++,q++)
    {
      *p=toupper(*q);
    }
    *p=0;
/*    LPRINTF(LL_INFO,("mangle: return1\n"));*/
    return dst;
  }
/*  LPRINTF(LL_INFO,("mangle: cache lookup\n"));*/
  /* lookup in the cache first */
  {
    MangleItem* p;
    if ((p=lookup_name(src))!=NULL)
    {
      strcpy(dst,p->mangled);
      stat_mhit++;
/*      LPRINTF(LL_INFO,("mangle: return2\n"));*/
      return dst;
    }
  }
/*  LPRINTF(LL_INFO,("mangle: mangling\n"));*/
  if (stype==1)
  {
    int crc;
    char* p;
    
    crc=crc83(src);
    name83(dst,src);
    p=dst+strlen(dst);
    *p++='.';
    *p++=MANGLE_CHAR;
    *p++=crc_chars[crc/CRC_CHARS];
    *p++=crc_chars[crc%CRC_CHARS];
    *p++=0;
  }
  else
  {
    char* p;
    char* q;
    
    for(p=dst,q=src;*q;p++,q++)
    {
      *p=toupper(*q);
    }
    *p=0;
  }
  {
    MangleItem* mi;
    if ((mi=lookup_mangled(dst))!=NULL)
    {
      strcpy(mi->name,src);
      stat_mcol++;
      return dst;
    }
  }
/*  LPRINTF(LL_INFO,("mangle: inserting\n"));*/
  if (insert_mangled(src,dst)==NULL)
  {
    stat_merrins++;
    return NULL;
  }
/*  LPRINTF(LL_INFO,("mangle: return4\n"));
  fprint_mangle_stat(log_file);*/
  return dst;
}

char* unmangle83(char* dst,char* src)
{
  char* p;
  char* q;
  
  stat_unmangle++;
  for(p=src;*p;p++)
  {
    if (*p==EXT_SEPARATOR)
    {
      MangleItem* mi;
      p++;
      if (*p!=MANGLE_CHAR || *(p+1)==0 || *(p+2)==0) break;
      if ((mi=lookup_mangled(src))==NULL)
      {
        stat_ulookup++;
/*        return NULL;*/
        break;
      }
      strcpy(dst,mi->name);
      return dst;
    }
  }
  stat_udirect++;
  for(q=dst,p=src;*p;p++,q++)
  {
    *q=tolower(*p);
  }
  *q=0;
  return dst;
}

void fprint_mangle_stat(FILE* file)
{
  fprintf(file,"Mangling statistics:\nmangle: %i direct: %i cache_hit: %i collision: %i insert error: %i\n",stat_mangle,stat_mdirect,stat_mhit,stat_mcol,stat_merrins);
  fprintf(file,"unmangle: %i direct: %i lookup error: %i\n",stat_unmangle,stat_udirect,stat_ulookup);
}

/* !#$%&'()-0123456789@^_`abcdefghijklmnopqrstuvwxyz{}~ 
   - DOS filename characters */

static char dos_char[256]=
{
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  1,
  0,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  0,
  0,
  0,
  1,
  0,
  0,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  0,
  0,
  0,
  0,
  0,
  0,
  1,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  0,
  1,
  1,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0
};

