/*
 * Configurable Finger Display routine
 */

#include "cfingerd.h"

void parse_username(char *username, char **uname, char **room, char **wp,
		    char **hp, char **other)
{
    char *r1 = NULL, *r2 = NULL, *r3 = NULL, *r4 = NULL, *r5 = NULL,
	 *p = NULL;

    r1 = ((p = strsep(&username, ",")) && *p) ? strdup(p) : NULL;
    r2 = ((p = strsep(&username, ",")) && *p) ? strdup(p) : NULL;
    r3 = ((p = strsep(&username, ",")) && *p) ? strdup(p) : NULL;
    r4 = ((p = strsep(&username, ",")) && *p) ? strdup(p) : NULL;
    r5 = ((p = strsep(&username, ",")) && *p) ? strdup(p) : NULL;

    if ((r1 == NULL) || (strlen(r1) == 1)) strmcpy(&r1, "(No info)");
    if ((r2 == NULL) || (strlen(r2) == 1)) strmcpy(&r2, "(No info)");
    if ((r3 == NULL) || (strlen(r3) == 1)) strmcpy(&r3, "(No info)");
    if ((r4 == NULL) || (strlen(r4) == 1)) strmcpy(&r4, "(No info)");
    if ((r5 == NULL) || (strlen(r5) == 1)) strmcpy(&r5, "(No info)");

    *uname = r1;
    *room = r2;
    *wp = r3;
    *hp = r4;
    *other = r5;
}

int indent(int length)
{
    int i;

    if (length > 0) {
	for (i = 0; i < length; i++)
	    printf(" ");
    }

    return length;
}

int format_display(int line_length, char *d1, char *d2)
{
    int ret = 0;

    printf("%s%s", d1, d2);
    if (line_length > 0) {
	line_length = 0;
	printf("\n");
    } else {
	ret = 40 - (strlen(d1) + strlen(d2));
    }

    ret = indent(ret);

    return(ret);
}

void main_finger_part(char *username)
{
    int line_length = 0, times_in, shown;
    char *room = NULL, *work_phone = NULL, *home_phone = NULL,
	 *other = NULL;
    struct passwd *passwd_entry;
    struct stat stat_buf;
    struct utmp *utmp_rec;

    passwd_entry = (struct passwd *) getpwnam(username);

    room = (char *) malloc(80);
    work_phone = (char *) malloc(80);
    home_phone = (char *) malloc(80);
    other = (char *) malloc(80);

    shown = FALSE;

    if (passwd_entry == NULL) {
	if ((((local_finger) || (trusted)) &&
	   prog_config.local_config_bits2 & SHOW_NOUSER) ||
	   (((!local_finger) && (!trusted)) &&
	   prog_config.config_bits2 & SHOW_NOUSER)) {
	    display_file(prog_config.no_user_banner_file);
	    return;
	} else {
	    printf("The user named %s does not exist on this system.\n", username);
#ifdef	SYSLOG
	    syslog(LOG_WARNING, "%s: No such user", username);
#endif
	    return;
	}
    }

    if (errno == ENOMEM) {
	printf("Internal error: No memory left to allocate passwd structure!\n");
#ifdef	SYSLOG
	syslog(LOG_ERR, "Fatal - No memory left for passwd structure");
#endif
	exit(PROGRAM_SYSLOG);
    }

#ifdef	DEBUG
#ifdef	SYSLOG
    syslog(LOG_NOTICE, "Username: %s", passwd_entry->pw_name);
    syslog(LOG_NOTICE, "Password: %s", passwd_entry->pw_passwd);
    syslog(LOG_NOTICE, "UserID  : %d", passwd_entry->pw_uid);
    syslog(LOG_NOTICE, "GroupID : %d", passwd_entry->pw_gid);
    syslog(LOG_NOTICE, "Realname: %s", passwd_entry->pw_gecos);
    syslog(LOG_NOTICE, "Home dir: %s", passwd_entry->pw_dir);
    syslog(LOG_NOTICE, "Shell   : %s", passwd_entry->pw_shell);
#endif
#endif

    if (setgid(((passwd_entry->pw_gid) ? passwd_entry->pw_gid : NO_PRIV_GID))) {
#ifdef	SYSLOG
	syslog(LOG_ERR, "%s", strerror(errno));
#endif
	exit(PROGRAM_SYSLOG);
    }

    if (setuid(((passwd_entry->pw_uid) ? passwd_entry->pw_uid : NO_PRIV_UID))) {
#ifdef	SYSLOG
	syslog(LOG_ERR, "%s", strerror(errno));
#endif
	exit(PROGRAM_SYSLOG);
    }

    parse_username(passwd_entry->pw_gecos, &passwd_entry->pw_gecos,
		   &room, &work_phone, &home_phone, &other);

    if ((prog_config.config_bits1 & SHOW_UNAME) ||
	(((local_finger) || (trusted)) &&
	(prog_config.local_config_bits1 & SHOW_UNAME))) {
	line_length = format_display(line_length, prog_config.p_strings[D_USERNAME],
				     passwd_entry->pw_name);
    }

    if ((prog_config.config_bits1 & SHOW_REALNAME) ||
	(((local_finger) || (trusted)) &&
	(prog_config.local_config_bits1 & SHOW_REALNAME))) {
	line_length = format_display(line_length, prog_config.p_strings[D_REALNAME],
				     passwd_entry->pw_gecos);
    }

    if ((prog_config.config_bits1 & SHOW_DIR) ||
	(((local_finger) || (trusted)) &&
	(prog_config.local_config_bits1 & SHOW_DIR))) {
	line_length = format_display(line_length, prog_config.p_strings[D_DIRECTORY],
				     passwd_entry->pw_dir);
    }

    if ((prog_config.config_bits1 & SHOW_SHELL) ||
	(((local_finger) || (trusted)) &&
	(prog_config.local_config_bits1 & SHOW_SHELL))) {
	line_length = format_display(line_length, prog_config.p_strings[D_SHELL],
				     passwd_entry->pw_shell);
    }

    if ((prog_config.config_bits1 & SHOW_ROOM) ||
	(((local_finger) || (trusted)) &&
	(prog_config.local_config_bits1 & SHOW_ROOM))) {
	line_length = format_display(line_length, prog_config.p_strings[D_ROOM],
				     room);
    }

    if ((prog_config.config_bits1 & SHOW_WPHONE) ||
	(((local_finger) || (trusted)) &&
	(prog_config.local_config_bits1 & SHOW_WPHONE))) {
	line_length = format_display(line_length, prog_config.p_strings[D_WORK_PHONE],
				     work_phone);
    }

    if ((prog_config.config_bits1 & SHOW_HPHONE) ||
	(((local_finger) || (trusted)) &&
	(prog_config.local_config_bits1 & SHOW_HPHONE))) {
	line_length = format_display(line_length, prog_config.p_strings[D_HOME_PHONE],
				     home_phone);
    }

    if ((prog_config.config_bits1 & SHOW_OTHER) ||
	(((local_finger) || (trusted)) &&
	(prog_config.local_config_bits1 & SHOW_OTHER))) {
	line_length = format_display(line_length, prog_config.p_strings[D_OTHER],
				     other);
    }

    if (line_length > 0)
	printf("\n\n");
    else
	printf("\n");

    if (((prog_config.config_bits1 & SHOW_LRMAIL) ||
	(prog_config.config_bits1 & SHOW_MRDATE)) ||
	(((local_finger) || (trusted)) &&
	((prog_config.local_config_bits1 & SHOW_LRMAIL) && 
	(prog_config.local_config_bits1 & SHOW_MRDATE)))) {
	char *mail_file = NULL;
	int stat_ret;
	BOOL no_unread = FALSE;

	mail_file = (char *) malloc(80);
	sprintf(mail_file, "/var/spool/mail/%s", username);

	stat_ret = stat(mail_file, &stat_buf);

	if ((prog_config.config_bits1 & SHOW_LRMAIL) ||
	    (((local_finger) || (trusted)) &&
	    (prog_config.local_config_bits1 & SHOW_LRMAIL))) {
	    if ((stat_ret == ENOENT) || (stat_buf.st_size == 0)) {
		printf("This user has no unread mail\n");
		no_unread = TRUE;
	    } else {
		printf("Has had unread mail since %s",
			ctime(&stat_buf.st_mtime));
	    }
	}

	if (((prog_config.config_bits1 & SHOW_MRDATE) &&
	    (!no_unread)) ||
	    (((local_finger) || (trusted)) &&
	    ((prog_config.local_config_bits1 & SHOW_MRDATE) && 
	    (!no_unread)))) {
	    printf("Last read mail on %s",
		    ctime(&stat_buf.st_atime));
	}
    }

    times_in = 0;
    while((utmp_rec = getutent()) != NULL) {
#ifdef __bsdi__
	if ((strcmp(utmp_rec->ut_name, "")) &&
	    (!strncmp(username, utmp_rec->ut_name, UT_NAMESIZE))) {
	    times_in++;
#else
	if ((utmp_rec->ut_type == USER_PROCESS) &&
	    (strcmp(utmp_rec->ut_user, "")) &&
	    (!strncmp(username, utmp_rec->ut_user, 8))) {
	    times_in++;
#endif

	    if ((times_in >= 1) && (!shown)) {
		if (((prog_config.config_bits1 & SHOW_LTON) &&
		    (!(prog_config.config_bits1 & SHOW_IFON))) ||
		    (((local_finger) || (trusted)) &&
		    ((prog_config.local_config_bits1 & SHOW_LTON) &&
		    (!(prog_config.local_config_bits1 & SHOW_IFON))))) {
		    char *strout = NULL;

		    strout = (char *) malloc(80);
		    strout = ctime(&utmp_rec->ut_time);
		    strout[strlen(strout)-1] = '\0';
		    printf("Last seen on %s ", strout);

		    shown = TRUE;
		} else {
		    char *device = NULL, *strout = NULL;
		    struct stat device_stat;

		    device = (char *) malloc(strlen(utmp_rec->ut_line));
		    strcpy(device, utmp_rec->ut_line);
		    strout = (char *) malloc(80);
		    strout = ctime(&utmp_rec->ut_time);
		    strout[strlen(strout)-1] = '\0';

		    stat(device, &device_stat);
		    if ((long) utmp_rec->ut_time > (long) device_stat.st_atime) {
			if ((local_finger) || (strcmp(utmp_rec->ut_host, ""))) {
			    if (((prog_config.config_bits1 & SHOW_IFON)) ||
				(((local_finger) || (trusted)) &&
				((prog_config.local_config_bits1 & SHOW_IFON))))
				printf("On since %s ", strout);
			}
		    }
		}

		if ((prog_config.config_bits1 & SHOW_FROM) ||
		    (((local_finger) || (trusted)) &&
		    (prog_config.local_config_bits1 & SHOW_FROM)))
		    if (strcmp(utmp_rec->ut_host, "")) {
			printf("from %s", utmp_rec->ut_host);
		    } else {
			printf("from localhost");
		    }

		shown = TRUE;
	    }
	}
    }

    if (times_in >= 1) {
	if (((prog_config.config_bits1 & SHOW_LTON) ||
		((prog_config.config_bits1 & SHOW_IFON))) ||
		(((local_finger) || (trusted)) &&
		((prog_config.local_config_bits1 & SHOW_LTON) ||
		((prog_config.local_config_bits1 & SHOW_IFON)))))
	printf(" (on %d tty%s)\n", times_in,
		(times_in == 1) ? "" : "s");
    } else {
	endutent();
	utmp_rec = getutent();

	if ((((local_finger) || (trusted)) && (prog_config.local_config_bits1 & SHOW_LTON)) ||
	    ((!local_finger) && (prog_config.config_bits1 & SHOW_LTON))) {
	    if (utmp_rec == NULL) {
		printf("This user has never logged in.\n");
	    } else {
		printf("Last login ");

		if (strcmp(utmp_rec->ut_host, "")) {
		    printf("from %s", utmp_rec->ut_host);
		} else {
		    printf("from localhost");
		}

		printf(" at ");

		printf("%s", ctime(&utmp_rec->ut_time));
	    }
	}
    }

    if ((prog_config.config_bits2 & SHOW_PLAN) ||
	(((local_finger) || (trusted)) &&
	(prog_config.local_config_bits2 & SHOW_PLAN))) {
	FILE *file;
	char buf[128];
	int bs;

	printf("\nPlan:\n");
	bs = sizeof(buf);
	sprintf(buf, "%s/%s", passwd_entry->pw_dir, prog_config.plan_file);
	if (!(file = fopen(buf, "r"))) {
	    printf("No plan.\n");
	} else {
	    while(fgets(buf, bs, file))
		fputs(buf, stdout);

#ifdef	DEBUG
#ifdef	SYSLOG
	    syslog(LOG_NOTICE, "%s file done.", prog_config.plan_file);
#endif
#endif
	}
    }

    if ((prog_config.config_bits2 & SHOW_PROJECT) ||
	(((local_finger) || (trusted)) &&
	(prog_config.local_config_bits2 & SHOW_PROJECT))) {
	FILE *file;
	char buf[128];
	int bs;

	printf("\nProject:\n");
	bs = sizeof(buf);
	sprintf(buf, "%s/%s", passwd_entry->pw_dir, prog_config.project_file);
	if (!(file = fopen(buf, "r"))) {
	    printf("No project.\n");
	} else {
	    while(fgets(buf, bs, file))
		fputs(buf, stdout);

#ifdef	DEBUG
#ifdef	SYSLOG
	    syslog(LOG_NOTICE, "%s file done.", prog_config.project_file);
#endif
#endif
	}
    }
}
