/*
 *  nwbpvalues.c
 *
 *  List the contents of a SET property of a bindery object on a NetWare server
 *
 *  Copyright (C) 1996 by Volker Lendecke
 *
 */

#include "ncplib.h"
#include <unistd.h>
#include <stdlib.h>
#include <ctype.h>

static char *progname;

static void
print_property(char *prop_name, __u8 *val, int segments);

static void
usage(void)
{
	fprintf(stderr, "usage: %s [options]\n", progname);
}

static void
help(void)
{
        printf("\n");
        printf("usage: %s [options]\n", progname);
        printf("\n"
	       "-h             Print this help text\n"
	       "-S server      Server name to be used\n"
               "-U username    Username sent to server\n"
               "-P password    Use this password\n"
               "-n             Do not use any password\n"
               "-C             Don't convert password to uppercase\n"
	       "\n"
	       "-o object_name Name of object\n"
	       "-t type        Object type (decimal value)\n"
	       "-p property    Name of property to be listed\n"
	       "-v             Verbose object listing\n"
	       "-c             Canonical output, for use with nwbpadd\n"
	       "\n");
}

int
main(int argc, char *argv[])
{
	struct ncp_conn *conn;
	char *object_name = NULL;
	int object_type = -1;
	char *property_name = NULL;
	__u8 property_value[255*128];
	int segno;
	int verbose = 0;
	int canonical = 0;
	struct nw_property segment;
	struct ncp_property_info info;
	long err;

	int result = 1;
	
	int opt;

	progname = argv[0];

	if ((conn = ncp_initialize(&argc, argv, 1, &err)) == NULL)
	{
		com_err(argv[0], err, "when initializing");
		goto finished;
	}

	while ((opt = getopt(argc, argv, "h?o:t:p:vc")) != EOF)
	{
		switch(opt) {
		case 'o':
			object_name = optarg;
			str_upper(object_name);
			break;
		case 't':
			object_type = atoi(optarg);
			break;
		case 'p':
			property_name = optarg;
			if (strlen(property_name) > 15)
			{
				fprintf(stderr, "%s: Property Name too long\n",
					argv[0]);
				exit(1);
			}
			str_upper(property_name);
			break;
		case 'v':
			verbose = 1;
			break;
		case 'c':
			canonical = 1;
			break;
		case 'h':
		case '?':
			help();
			goto finished;
		default:
			usage();
			goto finished;
		}
	}

	if (object_type < 0)
	{
		fprintf(stderr, "%s: You must specify an object type\n",
			argv[0]);
		goto finished;
	}

	if (object_name == NULL)
	{
		fprintf(stderr, "%s: You must specify an object name\n",
			argv[0]);
		goto finished;
	}

	if (property_name == NULL)
	{
		fprintf(stderr, "%s: You must specify a property name\n",
			argv[0]);
		goto finished;
	}

	if (ncp_scan_property(conn, object_type, object_name,
			      0xffffffff, property_name, &info) != 0)
	{
		fprintf(stderr, "%s: Could not find property\n", argv[0]);
		goto finished;
	}

	segno = 1;
	while (ncp_read_property_value(conn, object_type, object_name,
				       segno, property_name, &segment) == 0)
	{
		memcpy(&(property_value[(segno-1)*128]), segment.value, 128);
		if ((segment.more_flag == 0) || (segno == 255))
		{
			break;
		}
		segno += 1;
	}

	if (canonical != 0)
	{
		printf("%-4.4x\n%s\n", object_type, object_name);
		printf("%s\n%d\n%x\n",
		       info.property_name, info.property_flags, info.property_security);

	}

	if ((info.property_flags & 2) == 0)
	{
		/* ITEM property */
		if (canonical != 0)
		{
			int i;
			for (i = 0; i < segno*128; i++)
			{
				printf("%-2.2x\n", property_value[i]);
			}
		}
		else
		{
			print_property(property_name, property_value, segno);
		}
	}
	else
	{
		int objects = 32 * segno;
		__u32 *value = (__u32 *)property_value;
		int i = 0;

		while (i < objects)
		{
			struct ncp_bindery_object o;

			if ((value[i] == 0) || (value[i] == 0xffffffff))
			{
				/* Continue with next segment */
				i = ((i/32) + 1) * 32;
				continue;
			}
			if (ncp_get_bindery_object_name(conn, ntohl(value[i]),
							&o) == 0)
			{
				if (canonical != 0)
				{
					printf("%-4.4x\n%s\n",
					       (unsigned int) o.object_type,
					       o.object_name);
				}
				else if (verbose != 0)
				{
					printf("%s %08X %04X\n",
					       o.object_name,
					       (unsigned int) o.object_id,
					       (unsigned int) o.object_type);
				}
				else
				{
					printf("%s\n", o.object_name);
				}
			}
			i += 1;
		}
	}
	result = 0;
			
 finished:
	ncp_close(conn);
	return result;
}

static void
print_unknown(__u8 *val)
{
	int j = (128/16);
	while (1)
	{
		int i;
		for ( i = 0 ; i < 16 ; i++ )
		{
			printf ( "%02X " , val[i] );
		}
		printf ( "   [" );
		for ( i = 0 ; i < 16 ; i++ )
		{
			printf ( "%c" , isprint(val[i]) ? val[i] : '.');
		}
		j -= 1;
		if ( j == 0 )
		{
			printf ( "]\n" );
			return;
		}
		printf ( "]+\n" ) ;
		val += 16;
	}
}

static void
print_string(__u8 *val)
{
	puts(val);
}

static char *
print_station_addr(char *fmt, struct ncp_station_addr *addr, char *buff)
{
	char *ret = buff;

	while ( *fmt != 0 )
	{
		switch ( *fmt )
		{
		case '%':
			switch ( *(++fmt) )
			{
			case 'N': /* node */
			{
				int i ;
				for ( i = 0 ; i < 6 ; buff += 2 , i++ )
				{
					sprintf(buff, "%02X",addr->Node[i]);
				}
			}
				break;
			case 'S': /* Socket */
				sprintf(buff, "%04X", htons(addr->Socket));
				buff += 4 ;
				break ;
			case 'L': /* Lan */
				sprintf(buff, "%08lX", htonl(addr->NetWork));
				buff += 8 ;
				break ;
			case '%':
				*buff++ = '%';
			default:
				break ;
			}
			if (*fmt)
			{
				fmt++ ;
			}
			break ;
		default:
			*buff++ = *fmt++ ;
		}
	}
	*buff = 0 ;
	return ret ;
}

void
print_login_control ( __u8 *val )
{
	int     i , j , mask;
	char    buff[32];
	struct ncp_prop_login_control *a =(struct ncp_prop_login_control *)val;
	static char *days[]
		= { "Sun" , "Mon" , "Tue" , "Wen" , "Thu" , "Fri" , "Sat" } ;

	if (a->LastLogin[2] || a->LastLogin[1] || a->LastLogin[0] ||
	    a->LastLogin[3] || a->LastLogin[4] || a->LastLogin[5])
	{
		printf("Last Login: %d.%d.%02d at %2d:%02d:%02d\n",
			a->LastLogin[2] , a->LastLogin[1] , a->LastLogin[0] ,
			a->LastLogin[3] , a->LastLogin[4] , a->LastLogin[5]);
	}
	else
	{
		printf("Never logged in\n");
	}
	if (a->Disabled != 0)
	{
		printf(" --- Account disabled ---\n");
	}
	if (a->AccountExpireDate[2] || a->AccountExpireDate[1] ||
	    a->AccountExpireDate[0])
	{
		printf("Account expires on:  %d.%d.%d\n",
		       a->AccountExpireDate[2],
		       a->AccountExpireDate[1],
		       a->AccountExpireDate[0]);
	}
	if (a->PasswordExpireDate[2] || a->PasswordExpireDate[1] ||
	    a->PasswordExpireDate[0])
	{
		printf("Password expires on: %d.%d.%d\n" ,
		       a->PasswordExpireDate[2],
		       a->PasswordExpireDate[1],
		       a->PasswordExpireDate[0]);
		printf("GraceLogins left: %d\nof max.         : %d\n",
		       a->GraceLogins, a->MaxGraceLogins);
		printf("PasswortChangeInterval   : %d days\n",
		       ntohs(a->PasswordExpireInterval));
	}
	if ((a->RestrictionMask & 2) != 0)
	{
		printf("New password must be different when changing\n");
	}
	if ((a->RestrictionMask & 1) != 0)
	{
		printf("User ist not allowed to change password\n");
	}
	printf("Minimal password length  : %d\n", a->MinPasswordLength);
	if (ntohs(a->MaxConnections) != 0)
	{
		printf("Maximum no of connections: %d\n",
		       ntohs(a->MaxConnections));
	}

	if ( a->MaxDiskUsage != 0xFFFFFF7FL )
	{
		printf("Maximum DiskQuota : %8ld blocks\n",
		       ntohl(a->MaxDiskUsage));
	}
	printf("Failed Logins: %5d\n", ntohs(a->BadLoginCount));

	if (a->BadLoginCountDown != 0L)
	{
		printf("Account disabled still %8ld seconds\n",
		       ntohl(a->BadLoginCountDown));
	}
	if (a->LastIntruder.NetWork != 0L)
	{
		printf("Last \'intruder\' address: %s\n" ,
		       print_station_addr("(%L): %N[%S]" ,
					  &(a->LastIntruder),buff));
	}
	if ( a->RestrictionMask & 0xFC )
	{
		printf("RestrictionMask : %02X\n", a->RestrictionMask);
	}

	for ( i = 0 ; i < 42 ; i++ )
	{
		if ( a->ConnectionTimeMask[i] != 0xFF )
		{
			i = 101;
		}
	}
	if ( i < 100 )
	{
		return;
	}
	val = a->ConnectionTimeMask;
	printf("Time restrictions:         1 1 1 1 1 1 1 1 1 1 2 2 2 2 ]\n");
	printf("  Day [0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 ]\n");

	for ( i = 0 ; i < 7 ; i++ )
	{
		printf ("  %s [" , days[i]);
		for ( j = 0 ; j < 6 ; j++ )
		{
			for ( mask = 1 ; mask < 0x100 ; mask <<= 1 )
			{
				putchar ( (*val & mask) ? '*' : ' ' ) ;
			}
			val++ ;
		}
		printf ( "]\n" ) ;
	}
}

void
print_addr( __u8 *val)
{
	char buff[50];
	print_station_addr("(%L): %N[%S]",
			   (struct ncp_station_addr *)val, buff);
	printf("%s\n", buff);
}

static struct {
    char    *pname ;
    void    (*func)(__u8 *) ;
}   formats[] = {
    { "DESCRIPTION"     , print_string } ,
    { "SURNAME"         , print_string } ,
    { "OBJECT_CLASS"    , print_string } ,
    { "DESCRIPTION"     , print_string } ,
    { "IDENTIFICATION"  , print_string } ,
    { "Q_DIRECTORY"     , print_string } ,
    { "LOGIN_CONTROL"   , print_login_control } ,
    { "NET_ADDRESS"     , print_addr } , 
    { NULL		, NULL }
};

static void
print_property(char *prop_name, __u8 *val, int segments)
{
	int i;
	void (*f)(__u8 *);

	for (i = 0; formats[i].pname != NULL; i++)
	{
		if (strcasecmp(prop_name, formats[i].pname) == 0)
		{
			break;
		}
	}
	f = formats[i].func;

	if (f != NULL)
	{
		f(val);
		return;
	}

	for (i = 0; i < segments; i++)
	{
		printf("Segment: %03d\n", i+1);
		print_unknown(&(val[i*128]));
		printf("\n");
	}
}
	
