static char rcsid[]="$Id: localmap.c,v 2.3 2000/02/03 12:45:56 sxw Exp $";

/*
 *  localmap.c -- Carry out local mapping wildcard and tilde expansions
 *
 *  Use -DAFS_HESIOD_FILSYS to include AFS / Hesiod options for tilde
 *      exansion
 *
 *  DEBUG: none
 *  AUTHOR: Bruce R. Lewis
 *
 *  Harvest Indexer http://www.tardis.ed.ac.uk/harvest/
 *  ---------------------------------------------------
 *
 *  The Harvest Indexer is a continued development of code developed by
 *  the Harvest Project. Development is carried out by numerous individuals
 *  in the Internet community, and is not officially connected with the
 *  original Harvest Project or its funding sources.
 *
 *  Please mail harvest@tardis.ed.ac.uk if you are interested in participating
 *  in the development effort.
 *
 *  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 <string.h>
#include <stdio.h>
#include <pwd.h>
#include "url.h"
#include "config.h"

#ifdef AFS_HESIOD_FILSYS
#include "/usr/athena/include/hesiod.h"
#endif

/* return codes */
#define URL_MATCHDOES (0)
#define URL_MATCHNOT  (1)
#define URL_MATCHERR  (2)

/* macros to make code more readable */
#define AT_END(ptr) (*(ptr)=='\0')
#define WILD(ptr) (*(ptr)=='*')

/*  If localfile is of form "~brlewis/foo", put
 *  "/u1/brlewis/foo" in expandedfile and return 0.
 *  Return 1 if not of that form,
 *  Return 2 if not enough space in expandedfile.
 */
int url_tildeExpand(localfile, expandedfile, expandlength)
     char *localfile;
     char expandedfile[];
     int expandlength;
{
  char *restptr;		/* point to "/foo" in "~brlewis/foo" */
  char uname[1024];		/* username */

#ifdef AFS_HESIOD_FILSYS
  char **hes_results;
  char *afs_path_end;
  int afs_path_len;
#endif /* AFS_HESIOD_FILSYS */

  struct passwd *pwent;

  /* Make sure is of form "~brlewis/foo" */
  if (*localfile != '~') return(1);

  /* Point restptr at "/foo" in "~brlewis/foo" */
  restptr= strchr(localfile, '/');
  if (!restptr) restptr= localfile+strlen(localfile);

  /* Get username */
  if (restptr-localfile > 1022) return(1); /* Not of right form. */
  strncpy(uname, localfile+1, restptr-localfile-1);
  uname[restptr-localfile-1]= '\0';

#ifdef AFS_HESIOD_FILSYS
  hes_results= hes_resolve(uname, "filsys");
  if (hes_results
      && *hes_results
      && !strncmp(*hes_results, "AFS ", 4))
    {
      afs_path_end= strchr(4 + *hes_results, ' ');
      if (afs_path_end)
	{
	  afs_path_len= afs_path_end - (*hes_results + 4);
	  if (strlen(restptr) + afs_path_len >= expandlength)
	    return(2);
	  strncpy(expandedfile, 4 + *hes_results, afs_path_len);
	  expandedfile[afs_path_len]='\0';
	  strcat(expandedfile, restptr);
	  return(0);
	}
    }
#endif /* AFS_HESIOD_FILSYS */

  /* get passwd entry */
  pwent= getpwnam(uname);
  if (!pwent) return(1);	/* not a real username */
  if (strlen(pwent->pw_dir)+strlen(restptr) >= expandlength)
    return(2);
  strcat(strcpy(expandedfile, pwent->pw_dir),
	 restptr);
  return(0);
}

int url_wildcard_match(pattern, string, nmatch, match_starts, match_ends)
     char *pattern, *string;
     int nmatch;
     char **match_starts, **match_ends;
{
  register char *ptr_p, *ptr_s, *possible_match_start;

  ptr_p = pattern;
  ptr_s = string;

  while(1)
    {
      /* trivial case: "" matches "" */
      if (AT_END(ptr_p) && AT_END(ptr_s))
	{
	  *match_starts = *match_ends = (char *)0;
	  return(URL_MATCHDOES);
	}

      /* wildcard */
      if (WILD(ptr_p))
	{
	  /* we've gone too deep in wildcards if: */
	  if (nmatch <= 0) return(URL_MATCHERR);

	  /* if pattern = * ... */
	  if (AT_END(ptr_p+1))
	    {
	      /* we just match the rest */
	      *match_starts = ptr_s;
	      *match_ends = ptr_s + strlen(ptr_s);
	      return(URL_MATCHDOES);
	    }

	  /* otherwise do url_wildcard_match on the rest */
	  possible_match_start = ptr_s;
	  while (!AT_END(ptr_s))
	    {
	      if (url_wildcard_match(ptr_p+1, ptr_s, nmatch-1,
				 &(match_starts[1]), &(match_ends[1]))
		  == URL_MATCHDOES)
		{
		  *match_starts = possible_match_start;
		  *match_ends = ptr_s;
		  return(URL_MATCHDOES);
		}
	      ptr_s++;
	    }

	  /* no wildcard match */
	  return(URL_MATCHNOT);
	}

      /* not trivial or wildcard; just compare characters */
      if (*ptr_p != *ptr_s) return(URL_MATCHNOT);
      ptr_p++;
      ptr_s++;
    }
  /*NOTREACHED*/
}

int url_matchAndSub(pattern, string, sub_pattern, buf, buflen)
     char *pattern, *string, *sub_pattern, buf[];
     int buflen;
{
  register char *ptr_p, *ptr_b;
  int retval, nmatch, matchlen;
  char *match_starts[URL_WILDCARD_LIMIT], *match_ends[URL_WILDCARD_LIMIT];

  /* see if the string matches the pattern */
  retval = url_wildcard_match(pattern, string, URL_WILDCARD_LIMIT,
			      match_starts, match_ends);
  if (retval != URL_MATCHDOES) return(retval);

  /* it does; substitute the wildcards */
  for (ptr_p = sub_pattern, ptr_b = buf, nmatch=0;
       !(AT_END(ptr_p));
       ptr_p++)
    {
      if (buflen <= 0) return(URL_MATCHERR);
      if (WILD(ptr_p))
	{
	  if (!match_starts[nmatch]) return(URL_MATCHERR);
	  matchlen = match_ends[nmatch] - match_starts[nmatch];
	  buflen -= matchlen;
	  if (buflen <= 0) return(URL_MATCHERR);
	  strncpy(ptr_b, match_starts[nmatch], matchlen);
	  ptr_b += matchlen;
	  nmatch++;
	}
      else
	{
	  *(ptr_b++) = *ptr_p;
	  buflen--;
	}
    }
  *ptr_b='\0';
  return(retval);
}
