/**************************************************
 * genpasswd -- generates a random password	  *
 * 		consisting of random characters	  *
 * 		and numbers.			  *
 *						  *
 * Usage					  *
 * genpasswd [-l<length>] [-c<chars>] [-a<chars>] *
 * 						  *
 * Options					  *
 * 						  *
 **************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <time.h>

#define PNAME	"genpasswd"	/* program name */
#define MAXBUF	128		/* max size of pwdstr and of the generated password */
#define DLENGTH	8		/* default length for password */
#define DCHARS	"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVQXYZ_"	/* default string of valid characters in password */

/**************************************************
 * void usage(void) -- output short usage message.*
 **************************************************/
void usage(void)
{
	fprintf(stderr, "Usage: %s [-l<length>] [-c<chars>] [-a<chars>]\n\n", PNAME);
}

/**************************************************
 * void susage(void) -- output small usage msg.	  *
 **************************************************/
void susage(void)
{
	usage();
	fprintf(stderr, "Try %s -h for more info.\n", PNAME);
}

/**************************************************
 * void lusage(void) -- output long usage msg.	  *
 **************************************************/
void lusage(void)
{
	usage();
	fprintf(stderr, "Options\n");
	fprintf(stderr, "-l<length>\t\tLength of password. Default is %d characters.\n", DLENGTH);
	fprintf(stderr, "-c<chars>\t\tValid characters in password. Default is listed below.\n");
	fprintf(stderr, "-a<chars>\t\tAdd chars to the default password character string.\n");
	fprintf(stderr, "\n-h\t\t\tDisplay this help information and exit.\n");
	fprintf(stderr, "\nDefault string of valid characters in password:\n");
	fprintf(stderr, "%s\n", DCHARS);
}

/**************************************************
 * void genpasswd(char *dest, const char *pwdstr, *
 * const int length) -- generates a password,	  *
 * 			putting it in *dest.	  *
 **************************************************/
void genpasswd(char *dest, const char *pwdstr, int length)
{
	const double f = strlen(pwdstr) / (RAND_MAX + 1.0);

	for(; length > 0; length--, dest++){
		*dest = pwdstr[(int)(f * rand())];
	}
	
	dest[length] = '\0'; /* close dest */
}



int main(int argc, char *argv[])
{
	int length = DLENGTH;	/* length of password */
	char pwdstr[MAXBUF] = DCHARS;	/* password string */

	char passwd[MAXBUF]; /* the generated password */

	/* get arguments */
	while(argc > 1){
		if(argv[1][0] != '-'){
			fprintf(stderr, "%s: Invalid option %s specified.\n", PNAME, argv[1]);
			susage();
			return -1;
		}
		switch(argv[1][1]){
			case 'l':
				if(!argv[1][2]){
					fprintf(stderr, "%s: Option -%c requires an argument.\n", PNAME, argv[1][1]);
					susage();
					return -1;
				}
				
				sscanf(&argv[1][2], "%d", &length);
				
				if(length > MAXBUF){
					fprintf(stderr, "%s: Length of password too long. Maximum length of passwords is %d characters.\n", PNAME, MAXBUF);
					return -2;
				}
				
				break;
			case 'c':
				if(!argv[1][2]){
					fprintf(stderr, "%s: Option -%c requires an argument.\n", PNAME, argv[1][1]);
					susage();
					return -1;
				}

				if(strlen(&argv[1][2]) > MAXBUF){
					fprintf(stderr, "%s: Your valid characters string is too long (%d chars)! Maximum length of the string is %d characters.\n", PNAME, strlen(&argv[1][2]), MAXBUF);
					return -2;
				}
				
				strcpy(pwdstr, &argv[1][2]);
				break;
			case 'a':
				if(!argv[1][2]){
					fprintf(stderr, "%s: Option -%c requires an argument.\n", PNAME, argv[1][1]);
					susage();
					return -1;
				}

				strcpy(pwdstr, DCHARS);
				
				if((strlen(pwdstr) + strlen(&argv[1][2])) > MAXBUF){
					fprintf(stderr, "%s: Your valid characters string is too long (%d chars)! Maximum length of the string is %d characters.\n", PNAME, strlen(pwdstr) + strlen(&argv[1][2]), MAXBUF);
					return -2;
				}

				strcat(pwdstr, &argv[1][2]);
				break;
			case 'h':
				lusage();
				return 0;
			default:
				fprintf(stderr, "%s: Invalid option %s specified.\n", PNAME, argv[1]);
				susage();
				return -1;
				break;
		}
		argv++;
		argc--;
	}

	/* seed the random generator */
	struct timeval tv;

	gettimeofday(&tv, NULL);
	
	srand(tv.tv_usec);

	/* generate password */
	genpasswd(passwd, pwdstr, length);

	printf("Random %d chars password generated: %s\n", length, passwd);
	
	return 0;
}
