/* nwho.c */
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/wait.h>
#include "lib.h"

#define S(a,b)		str_copy(a,b)
#define SN(a,b,c)	str_copynz(a,b,c)
#define SF(a,b,c)	fmt_str_(a,b,c)
#define N(a,b,c,d)	fmt_nmb_(a,b,c,d)

void usage(char *buf) {
  write(1,buf,str_copy(buf, "usage: nwho [-alpquw] [file]\n"));
  _exit(1);
}

int main(int argc, char **argv) {
  struct tm *tm;
  struct stat st;
  char *montab = "JanFebMarAprMayJunJulAugSepOctNovDec";
  char buf[1024];
  time_t id;
  char *ipasc, mesg, *p;
  unsigned char flagaddr = 0;
  char flagpid = 0;
  char flagcheck = 1;
  char flagup = 0;
  char flagmesg = 0;
#ifdef USE_LIBC_UTMP
  struct utmp_type *ut;
#else
  struct utmp_type ut[1];
  int fd;
#endif

  argc--; argv++;
  while (argc>0) {
    p = argv[0];
    if (*p != '-') break;
    for (++p; *p; ++p) 
      switch (*p) {
      case 'q': flagcheck = 0; break;
      case 'l': ++flagaddr; break;
      case 'p': flagpid = 1; break;
      case 'u': flagup = 1; break;
      case 'w': flagmesg = 1; break;
      case 'a': flagup=1; flagpid=1; ++flagaddr; flagmesg=1; break;
      default: usage(buf);
      }
    argc--; argv++;
  }

#ifdef USE_LIBC_UTMP
  if (argc>0)  f_utmpname(argv[0]);
  setutent();
#else
  if (argc>0)  p = argv[0];
  else p = Utmp_File;

  fd = open(p, O_RDONLY);
  if (fd == -1) {write(1,"error open input\n",17); _exit(1);}
#endif

  while (f_getutent()) {
    if (ut->ut_type != USER_PROCESS) continue;
    if (flagcheck)
      if (kill(ut->ut_pid, 0) && errno == ESRCH) continue;

    id = ut->ut_tv.tv_sec;
    id += get_tz(id);
    tm = nv_gmtime(&id);

    mesg = '?';
    id = -1;

    S(buf, "/dev/");
    buf[5 + SN(buf+5, ut->ut_line, sizeof(ut->ut_line))] = '\0';

    if (!stat(buf, &st)) {
      if ((st.st_mode & 0020) == 0020) mesg = '+';
      else mesg = '-';
      id = (time(0) - st.st_mtime)/60;
    }

    /*----------------------------------------------*/
    p = buf;
    p += SF(p, ut->ut_user,12); 

    if (flagmesg) {
      *p++ = mesg;                 *p++ = ' ';}

    p += SF(p, ut->ut_line, 7);    *p++ = ' ';
    if (flagpid) {
      p += N(p, ut->ut_pid,  5,0); *p++ = ' ';}

    p += SN(p, montab + (tm->tm_mon)*3,  3);   *p++ = ' ';
    p += N(p, tm->tm_mday, 2,0);   *p++ = ' ';
    p += N(p, tm->tm_hour, 2,0);   *p++ = ':';
    p += N(p, tm->tm_min,  2,1);   *p++ = ' ';

    if (flagup) {
      if (id >= 24*60) {
	id /= 60;
	p += N(p, id/24, 3,0);   p += S(p,"d+"); 
	p += N(p, id%24, 2,1);   p += S(p,"h "); 
      } else if (id > 0) {
	p += N(p, id/60, 2,0);   *p++ = ':';
	p += N(p, id%60, 2,1);   *p++ = ' ';
      } else if (id == 0) {
	p += SF(p,"  .",6);
      } else
	p += SF(p,"  ?",6);
    }

    *p++ = '(';
    ipasc = p;
    p += fmt_utmp_ip(p, (char *)ut->ut_addr_v6);

    if (flagaddr>1 ||
	(flagaddr && str_diffn(ipasc, ut->ut_host, sizeof(ut->ut_host)))) {
      *p++ = '=';
      p += SN(p,ut->ut_host,90);
    }
    *p++ = ')'; *p++ = '\n';

    write(1,buf, p-buf);
  }
  f_endutent();
  return 0;
}
