/*
 *  nwbpadd.c
 *
 *  Set 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>

static char *progname;

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

static void
help(void)
{
        printf("\n");
        printf("usage: %s [options] [values]\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 accessed object\n"
	       "-t type        Object type (decimal value)\n"
	       "-p property    Name of property to be touched\n"
	       "value          value to be added\n"
	       "\n"
	       "If property is of type SET, value is an object id (hex)\n"
	       "Otherwise, value is either a string value to be written, or\n"
	       "a count of bytes to be written. The latter is assumed if\n"
	       "more than one value argument is given. The count is decimal,\n"
	       "and the following arguments are interpreted as bytes in\n"
	       "hexadecimal notation.\n"
	       "\n");
}

int
main(int argc, char *argv[])
{
	struct ncp_conn *conn;
	char *object_name = NULL;
	int object_type = -1;
	char *property_name = NULL;
	char *value = NULL;
	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:v:")) != 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':
			value = optarg;
			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 (optind > argc-1)
	{
		fprintf(stderr, "%s: You must specify a property value\n",
			argv[0]);
		goto finished;
	}

	value = argv[optind];
	optind += 1;

	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;
	}

	if ((info.property_flags & 2) != 0)
	{
		/* Property is of type SET */
		struct ncp_bindery_object o;

		if (optind != argc)
		{
			fprintf(stderr, "%s: For the SET property %s, you must"
				" specify an object id as value\n",
				progname, property_name);
			goto finished;
		}

		if (ncp_get_bindery_object_name(conn,
						ntohl(strtol(value, NULL, 16)),
						&o) != 0)
		{
			fprintf(stderr, "%s: %s is not a valid object id\n",
				progname, value);
			goto finished;
		}

		if (ncp_add_object_to_set(conn, object_type, object_name,
					  property_name,
					  o.object_type, o.object_name) != 0)
		{
			fprintf(stderr, "%s: could not add object %s\n",
				progname, o.object_name);
			goto finished;
		}		
	}
	else
	{
		/* Property is of type ITEM */
		char contents[255*128];
		int segno = 1;
		int length;

		memset(contents, 0, sizeof(contents));

		if (optind == argc)
		{
			/* value is the string to add */
			length = strlen(value);
			if (length >= sizeof(contents))
			{
				fprintf(stderr, "%s: Value too long\n",
					progname);
				goto finished;
			}
			strcpy(contents, value);
		}
		else
		{
			/* value is the byte count */
			int i;
			length = atoi(value);
			if (length >= sizeof(contents))
			{
				fprintf(stderr, "%s: Value too long\n",
					progname);
				goto finished;
			}
			if (optind != argc - length)
			{
				fprintf(stderr, "%s: Byte count does not match"
					" number of bytes\n", progname);
				goto finished;
			}
			i = 0;
			while (optind < argc)
			{
				contents[i] = strtol(argv[optind], NULL, 16);
				i += 1;
				optind += 1;
			}
		}

		for (segno = 1; segno <= 255; segno++)
		{
			struct nw_property segment;
			int offset = (segno-1)*128;

			if ( offset > length )
			{
				/* everything written */
				break;
			}
			memcpy(segment.value, &(contents[offset]), 128);
			segment.more_flag = segno*128 < length;
			if (ncp_write_property_value(conn, object_type,
						     object_name,
						     property_name,
						     segno, &segment) != 0)
			{
				fprintf(stderr, "%s: Could not write "
					"property\n", progname);
				goto finished;
			}
		}
	}
	result = 0;

 finished:
	ncp_close(conn);
	return result;
}
