/*
 * Copyright (c) 1998 Kungliga Tekniska Högskolan
 * (Royal Institute of Technology, Stockholm, Sweden).
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *      This product includes software developed by the Kungliga Tekniska
 *      Högskolan and its contributors.
 * 
 * 4. Neither the name of the Institute nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#include <milko_locl.h>

RCSID("$Id: afsacl.c,v 1.2 1998/11/09 20:43:59 lha Exp $");

/*
 * AFS ACL
 *
 * The structure of the acl on the net is the following:
 *
 * pos entries: int32_t
 * neg entries: int32_t
 * entries:
 *   name: char *
 *   SPC/TAB
 *   acl: int
 *   RET
 */

int
afsacl_parse(void *data, size_t len, struct AFSAcl **racl)
{
    char *ptr = data;
    char *next;
    struct AFSAcl *acl;
    struct AFSAcl *acl2;
    int i, j;

    assert (racl && data);

    *racl = NULL;
    acl = calloc(1, sizeof(*acl));
    if (acl == NULL)
	return ENOMEM;

    ptr[len-1] = '\0';

    acl->acl_pos = strtol(ptr, &next, 0);
    acl->acl_pos = ntohl(acl->acl_pos);
    len -= next - ptr;
    ptr = next;
    while (*ptr != '\n' && len > 0) ptr++, len--;
    if (len <= 0) {
	free(acl);
	return EINVAL;
    }

    acl->acl_neg = strtol(ptr, &next, 0);
    acl->acl_neg = ntohl(acl->acl_neg);
    len -= next - ptr;
    ptr = next;
    while (*ptr != '\n' && len > 0) ptr++, len--;
    if (len <= 0) {
	free(acl);
	return EINVAL;
    }

    acl2 = realloc(acl, 
		   (acl->acl_pos + acl->acl_neg - 1)*sizeof(struct AFSAclEntry)
		   + sizeof(struct AFSAcl));

    if (acl2 == NULL) {
	free(acl);
	return ENOMEM;
    }
    acl = acl2;
    
    i = 0;
    while (i < acl->acl_pos +  acl->acl_neg && len > 0) {
	j = 0;
	while(len > 0 && !isspace(acl->acl_entry[i].acle_name[j] = *ptr)) {
	    --len; ++j; ++ptr;
	}
	if (len <= 0) {
	    free(acl);
	    return EINVAL;
	}
	/* strtol clean off isspace() */
	acl->acl_entry[i].acle_right = strtol(ptr, &next, 0);
	acl->acl_entry[i].acle_right  = ntohl(acl->acl_entry[i].acle_right);
	len -= next - ptr;
	ptr = next;
	while (*ptr != '\n' && len > 0) ptr++, len--;
	if (len <= 0) {
	    free(acl);
	    return EINVAL;
	}
	++i;
    }
    *racl = acl;
    return 0;
}

/*
 *
 */

int
afsacl_generate(struct AFSAcl *acl, void **data, size_t *len)
{
    int i, left;
    size_t size;
    char *str, *ptr;
    char *tmp;

    assert(acl && data && len);

    *data = NULL;
    *len = 0;

    size = 10;
    str = NULL;

    /* Repeat until it will fit */
    do {
	if (str)
	    free(str);
	size *= 2;
	str = malloc(size);   /* to hold %d\n%d\n */
	if (str == NULL)
	    return ENOMEM;

	i = snprintf(str, size, "%d\n%d\n");
    } while (i > size); 

    ptr = str;
    ptr += i;
    left = size - i;
    
    for (i = 0 ; i < acl->acl_pos + acl->acl_neg ; ++i) {
	int j;

	do {
	    j = snprintf(ptr, left, "%s\t%d\n", acl->acl_entry[i].acle_name,
			 acl->acl_entry[i].acle_right);

	    if (left < j) {
		size += PR_MAXNAMELEN;
		left += PR_MAXNAMELEN;
		
		tmp = realloc(str, size);
		if (tmp == NULL) {
		    free(str);
		    return ENOMEM;
		}
	    } else {
		ptr += j;
		break;  /* EXIT HERE */
	    }
	} while (1);
    }

    size -= left;
    tmp = realloc(str, left);
    if (tmp) {
	free(str);
	return ENOMEM;
    }

    *len = size; 
    *data = str;
    return 0;
}


