#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <pwd.h>

#define SERV_PORT 1337
#define BANNER "********Toe daemon********\n> "
#define LISTENQ 1024
#define RECV_BUF_SIZE 4096
#define MAX_CMD_LEN 16
#define MAX_ARG_LEN 112
#define INFINITE_LOOP 1

struct command {
  char cmd[MAX_CMD_LEN];
  char arg[MAX_ARG_LEN];
};

char *exec_cmd (struct command *c);
void service_client (int sockfd);
struct command *parse (char *input);

int
main (int argc, char *argv[])
{
  int listenfd;
  int connfd;
  socklen_t clilen;
  struct sockaddr_in cliaddr;
  struct sockaddr_in servaddr;
  
  listenfd = socket (PF_INET, SOCK_STREAM, 0);
  
  bzero (&servaddr, sizeof (servaddr));
  servaddr.sin_family = AF_INET;
  servaddr.sin_addr.s_addr = htonl (INADDR_ANY);
  servaddr.sin_port = htons (SERV_PORT);
  
  bind (listenfd, (struct sockaddr *) &servaddr, sizeof (servaddr));
  listen (listenfd, LISTENQ);
  
  while (INFINITE_LOOP)
    {
      clilen = sizeof (cliaddr);
      connfd = accept (listenfd, (struct sockaddr *) &cliaddr, &clilen);
      
      service_client (connfd);
      close (connfd);
    }
  exit (EXIT_FAILURE); /* Should never be reached */
}

void
service_client (int sockfd)
{
  /* I'm not here to service you, I'm here to service these young boys. */
  char buf[RECV_BUF_SIZE];
  char *response;
  struct command *c;
  write (sockfd, BANNER, strlen (BANNER));
  read (sockfd, buf, RECV_BUF_SIZE);
  if (NULL == (c = parse (buf)))
    {
      return;
    }
  response = exec_cmd (c);
  write (sockfd, response, strlen (response));
}

char *
exec_cmd (struct command *c)
{
  struct passwd *pw;
	printf("c->arg: [%s]\n", c->arg);
  if (!strcmp(c->cmd, "USERNAME"))
    {
      if (NULL == (pw = getpwnam (c->arg)))
        {
          return "None";
        }
      return pw->pw_gecos;
    }
  else if (!strcmp(c->cmd, "REALNAME"))
    {
      setpwent ();
      while (NULL != (pw = getpwent ()))
        {
          if (!strcmp (pw->pw_gecos, c->arg))
            {
              return pw->pw_name;
            }
        }
      return "None";
    }
  else
    {
      return "Error";
    }
}

struct command *
parse (char *input)
{
  struct command *ret;
  int delim_idx;
  int total_len;
  int i;

  ret = (struct command *) malloc (sizeof (struct command));
  
  /* Find the delimiter */
  total_len = 0;
  for (i = 0; input[i] != '\n'; i++)
    {
      if (':' == input[i])
        {
          delim_idx = i;
        }
      else
        {
          total_len++;
        }
    }
    
  if (total_len > (MAX_CMD_LEN - 1) + (MAX_ARG_LEN - 1)) /* -1 for NUL */
    {
      /* One of the inputs is too large */
      return NULL;
    }
  
  strncpy (ret->cmd, input, delim_idx);
  ret->cmd[delim_idx] = '\0';
  strncpy (ret->arg, &input[delim_idx+1], total_len - delim_idx);
	ret->arg[total_len - delim_idx] = '\0';
  
  return ret;
}

