#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <pwd.h>
#include <unistd.h>

/* copy from GNU finger-1.37 include/packet.h till END */
#define USERNAME_LEN 16
#define HOSTNAME_LEN 64
#define REALNAME_LEN 64
#define TTYNAME_LEN 32
#define TTYLOC_LEN 128
#define WHAT_LEN 16

typedef struct {
  char name[USERNAME_LEN];
  char real_name[REALNAME_LEN];
  char host[HOSTNAME_LEN];
  long login_time;
  long idle_time;
  char ttyname[TTYNAME_LEN];
  char ttyloc[TTYLOC_LEN];
  char what[WHAT_LEN];
} FINGER_PACKET;

/* END */

#define USERDATA "/usr/local/etc/fingerdir/userdata"
#define MIN_UID 1000

extern char *optarg;
extern int optind, opterr, optopt;

#define NAMEFLAG    0x01
#define REALFLAG    0x02
#define HOSTFLAG    0x04
#define LOGINFLAG   0x08
#define IDLEFLAG    0x10
#define TTYNAMEFLAG 0x20
#define TTYLOCFLAG  0x40
#define WHATFLAG    0x80

void
usage() {
    fputs("usage: rgfd [-f userdata -urhlityw]\n", stderr);
    fputs("\t-f GNU finger userdata file(default: " USERDATA ")\n", stderr);
    fputs("\t-u print user name\n", stderr);
    fputs("\t-r print real name\n", stderr);
    fputs("\t-h print host name\n", stderr);
    fputs("\t-l print login time\n", stderr);
    fputs("\t-i print idle time\n", stderr);
    fputs("\t-t print tty name\n", stderr);
    fputs("\t-y print tty location\n", stderr);
    fputs("\t-w print what\n", stderr);
    fputs("\t print options' order is used for print order\n", stderr);
    fputs("\t (-ul and -lu is not equivalent).\n", stderr);
}

int 
main(int argc, char *argv[]){
    FINGER_PACKET data;
    int file;
    char logintime[20];	/* "1998/01/01 00:00:00NULL" */
    char idletime[20];	/* "1998/01/01 00:00:00NULL" */
    struct passwd *passwd_entry;
    int c;
    int n = 0;
    int options[8] = {0, 0, 0, 0, 0, 0, 0, 0};
    char *userdata = USERDATA;

    while ((c = getopt(argc, argv, "urhlitywf:")) != EOF) {
	switch(c) {
	case 'u': options[n] = NAMEFLAG; n++; break;
	case 'r': options[n] = REALFLAG; n++; break;
	case 'h': options[n] = HOSTFLAG; n++; break;
	case 'l': options[n] = LOGINFLAG; n++; break;
	case 'i': options[n] = IDLEFLAG; n++; break;
	case 't': options[n] = TTYNAMEFLAG; n++; break;
	case 'y': options[n] = TTYLOCFLAG; n++; break;
	case 'w': options[n] = WHATFLAG; n++; break;
	case 'f': userdata = optarg; break;
	case '?': usage(); exit(1);
	}
    }

    file = open(userdata, O_RDONLY, 0666);
    while (read (file, &data, sizeof (data)) == sizeof (data)) {
	if ((passwd_entry = getpwnam(data.name)) == NULL)
	    continue;		/* expired user name */
	if (passwd_entry->pw_uid < MIN_UID)
	    continue;		/* system user */

	(void)strftime(logintime, sizeof(logintime), "%Y/%m/%d %H:%M:%S",
		 localtime(&data.login_time));
	(void)strftime(idletime, sizeof(idletime), "%Y/%m/%d %H:%M:%S",
		 localtime(&data.idle_time));

	if (n == 0) {
	    printf("%19s %-8s (uid=%5d, %s)\n", 
		   logintime, data.name, (int)passwd_entry->pw_uid, data.real_name);
	} else {
	    for (c = 0; c < n; c++) {
		switch(options[c]) {
		case NAMEFLAG:    printf("%-8s ", data.name); break;
		case REALFLAG:    printf("%s ", data.real_name); break;
		case HOSTFLAG:    printf("%s ", data.host); break;
		case LOGINFLAG:   printf("%s ", logintime); break;
		case IDLEFLAG:    printf("%s ", idletime); break;
		case TTYNAMEFLAG: printf("%s ", data.ttyname); break;
		case TTYLOCFLAG:  printf("%s ", data.ttyloc); break;
		case WHATFLAG:    printf("%s ", data.what); break;
		}
	    }
	    printf("\n");
	}
    }
    return 0;
}
