/* PIPServer - A deamon for finger protocol v2
 *
 * Copyright (C) 1999 Michael Baumer <baumi@vis.ethz.ch>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

#include <pwd.h>
#include <sys/types.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

#include "in.fingerd.h"
#include "local_user.h"
#include "parser.h"
#include "finger.h"
#include "file.h"
#include "configfile.h"

typedef struct finger_options {
  int plan;
  int mailinfo;
  int project;
  int tty;
  int login;
} finger_options;

/* Show answer to finger */
void finger_show(finger_options *opt, finger_userinfo *uinfo)
{
  char *filename;
  Node *node, *cur;
  int i;

  fprintf(stdout, "<userinfo>\n");
  fprintf(stdout, "<login>%s</login>\n", uinfo->pw_name);

  filename = findUserFile(uinfo, "fingerconf");
  if (filename && (node = readFingerconf(filename))) {
    cur = node->child;

    /* Print all info like it is in the config file
     * Ugly but it works
     */
    while(cur) {
      if (!strcmp(cur->id, "userinfo")) {
	cur = cur->child;
	while (cur) {
	  if (!cur->child) {
	    fprintf(stdout, "<%s>%s</%s>\n", cur->id, cur->value, cur->id);
	    while (!cur->next) {
	      if (!cur->parent->parent->parent)
		break;
	      cur = cur->parent;
	      fprintf(stdout, "</%s>\n", cur->id);
	    }
	    cur = cur->next;
	  }
	  else {
	    fprintf(stdout, "<%s>%s", cur->id, cur->value);
	    cur = cur->child;
	  }
	}
      }
      else 
	cur = cur->next;
    }
  }
  else {
    /* No information available, use the GECOS field */
    fprintf(stdout, "<realname>%s</realname>\n", uinfo->pw_realname);
  }

  /* print .plan file 
   *
   * Note: GNU Finger 1.x allows the plan file to be parsed by cpp
   * for replacing some strings (e.g. Date, Time).
   * I don't think that is absolutely necessary and is non-standard.
   */

  if (opt->plan) 
    if ((filename = findUserFile(uinfo, "plan"))) {
      /* send the file */
      fprintf(stdout, "<plan>\r\n");
      print_file(filename, 1);
      fprintf(stdout, "</plan>\n");
    }

  i = 0;
  while(config.validfile[i]) {
    if (strcmp(config.validfile[i], "plan") &&
	(filename = findUserFile(uinfo, config.validfile[i]))) {

      /* report the file */

      fprintf(stdout, "<file>%s\r\n", config.validfile[i]);
      if (config.filedesc[i])
	fprintf(stdout, "<desc>%s</desc>\r\n", config.filedesc[i]);
      fprintf(stdout, "</file>\r\n");
    }
    i++; 
  }
  
  fprintf(stdout, "</userinfo>\n");
}

/* answer to a finger request
 *
 */

void finger_handler(Node *node)
{
  finger_options opt;
  Node *subnode;
  char *username = NULL;
  char *tmp;
  finger_userinfo *uinfo;

  /* set default options */
  opt.plan = TRUE;
  opt.mailinfo = TRUE;
  opt.tty = 0;
  opt.login = TRUE;
  opt.project = 0;

  /* parse finger packets */

  subnode = node->child;
  while(subnode) {
    switch (subnode->type) {
    case OPTION:
      break;
    case NOOPTION:
      break;
    default:
      if (!strcmp(subnode->id, "user")) {
	username = subnode->value;
      }
    }
    subnode = subnode->next;
  }

  fprintf(stdout, "<finger_reply>\n");
  
  if (username) {

    /* entspace it */

    while (*username && isspace(*username))
      username++;
    tmp = username + strlen(username) - 1;
    while((tmp >= username) && (isspace(*tmp))) {
      *tmp = '\0';
      tmp--;
    }

    /*
     * 1. match login, if found print output and exit
     * 2. match remote logins, if found print output and exit
     * 3. match local users and their realnames
     * 4. match remote users and their realnames
     *
     * That way we are able to provide on/offline information for matching
     * Users and are able to search for non-matching users.
     * The problem is that we can't provide a useful search that way,
     * if the login name exists. Abbreviations must be used in that case.
     */

    /* search for local users by login name */
    uinfo = pwd_search_login(username, 1);
    if (uinfo) {
      
      finger_show(&opt, uinfo);
      
    } else {
      
      /* search for local users by real name */
      
      /* rewind passwd file */
      setpwent();
      while ((uinfo = pwd_search_realname(username))) 
	finger_show(&opt, uinfo);
    }  
  }

  fprintf(stdout, "</finger_reply>\n");
  
  /* free subtree */
  /* todo: */
  /*  parstree_free(node); */
}


syntax highlighted by Code2HTML, v. 0.9.1