/* PIPClient - A client for finger protocol v2
*
* Copyright (C) 1999 Michael Baumer
*
* 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 <config.h>
#include <gtk/gtk.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif /* HAVE_STRINGS_H */
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <ctype.h>
#if HAVE_SYS_WAIT_H
# include <sys/wait.h>
#endif
#ifndef WEXITSTATUS
# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
#endif
#ifndef WIFEXITED
# define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
#endif
#include "parser.h"
#include "configfile.h"
#include "conn.h"
#include "request.h"
#include "compat.h"
#ifndef HAVE_GETOPT_DECL
int getopt(int argc, char **argv, char *optstring);
extern char *optarg;
extern int optind;
#endif
int debug = 0;
int gnufinger = 0;
int realnames = 0;
int test = 0;
Node *cf;
char *configfile;
extern void addText(char *txt, int font);
extern void create_gui_gtk();
extern void gui_add_user(char *name, int status);
/* Create the GUI
*/
void create_gui()
{
create_gui_gtk();
}
/* Start the in.fingerd via exec & pipes
*
* Used for testing a fresh compilation of in.fingerd
* Note: in.fingerd is started in the current working dir!
*
* parameters:
* debug: verbose output or not
* cmd : the command string to send. Must include "</pip>"
*/
void test_connection(int debug, char *cmd)
{
/* make a sample connection for testing the client */
int pid;
int status;
int pin[2];
int pout[2];
if (setvbuf(stdout, NULL, _IOLBF, 0) < 0) {
perror("setvbuf(stdout)");
exit(1);
}
/* open pipes */
if (pipe(pin) ||
pipe(pout)) {
perror("opening pipe");
exit(1);
}
/* fork */
pid = fork();
if(!pid) {
/* child */
/* redirect filedes */
/* pin[read] auf stdin legen*/
close(0);
dup(pin[0]);
/*pout[write] auf stdout legen*/
close(1);
dup(pout[1]);
close(pin[1]);
close(pout[0]);
close(pin[0]);
close(pout[1]);
if (gnufinger)
execl("in.fingerd", "in.fingerd", "-g", NULL);
else
execl("in.fingerd", "in.fingerd", NULL);
perror("Starting child");
exit(-15);
}
if (debug)
printf("started client : pid=%d\n", pid);
/*
* parent
*/
close(pin[0]);
close(pout[1]);
send_request(pin[1], pout[0], cmd);
if (debug)
printf("Waiting for Child to terminate\n");
wait(&status);
if (debug)
printf("Child terminated with status: %d\n", status);
/* close all open filedesc */
close(pin[1]);
close(pout[0]);
}
void show_online_user(Node *node)
{
Node *subnode;
Node *s2node;
char *login;
char *realname;
int status;
subnode = node->child;
while(subnode) {
login = NULL;
status = 0;
s2node = subnode->child;
while (s2node) {
if (!strcmp(s2node->id, "login")) {
login = s2node->value;
}
else
if (!strcmp(s2node->id, "status")) {
if (!strcmp(s2node->value, "active"))
status = 1;
}
else
if (!strcmp(s2node->id, "realname")) {
realname = s2node->value;
}
s2node = s2node->next;
}
if (login) {
if (realnames)
gui_add_user(realname, status);
else
gui_add_user(login, status);
}
subnode = subnode->next;
}
}
/* Show userinfo */
void show_userinfo(Node *node)
{
Node *cur_node;
char txt[120];
/* Output everything */
cur_node = node->child;
while (cur_node) {
if (!strcmp(cur_node->id, "userinfo")) {
cur_node = cur_node->child;
while(cur_node) {
/* Handle specials */
/*
if (strcmp(cur_node->id, "first") &&
strcmp(cur_node->id, "last")) {
*/
/* Make it simple */
/* this is probably a hack */
cur_node->id[0] = toupper(cur_node->id[0]);
if (!*cur_node->value) {
sprintf(txt, "\n%s\n", cur_node->id);
addText(txt, 2);
}
else {
if (index(cur_node->value, '\n'))
sprintf(txt, "%s: \n", cur_node->id);
else
sprintf(txt, "%s: ", cur_node->id);
addText(txt, (strcmp(cur_node->id, "Plan")) ? 0 : 2);
addText(cur_node->value, (strcmp(cur_node->id, "Plan")) ? 1 : 0);
addText("\n", 0);
}
/*
}
*/
if (cur_node->child)
cur_node = cur_node->child;
else {
while (!cur_node->next) {
if (!cur_node->parent)
break;
cur_node = cur_node->parent;
}
cur_node = cur_node->next;
}
}
} else
cur_node = cur_node->next;
}
}
/* Send a request in finger v1 protocol and hope...
* Since the output is arbitrary this may fail miserably
* If the user doesn't help us, we try to do the best...
*
* At least we should be compatible to GNU Finger, Win NT Finger
* and Sun's Finger.
*
* Since we only want to know the online status we dont ask for a username.
* We can only check for a userlist because we simply search the output
* for these names. If we want to have a list of all poeple online, we should
* parse the output which is currently not implemented. This also means we
* don't have any idle time information.
*/
int send_request_v1(int fdin, int fdout, char **username)
{
int retval = 0;
char *nl = "\r\n";
int nread;
int len;
char *scan;
char *line;
int offset;
int i;
char inbuf[2048];
/* Send a newline to get all online users */
write(fdin, nl, sizeof(nl)+1);
scan = inbuf;
len = sizeof(inbuf) - 1;
offset = 0;
line = inbuf;
while ((nread = read(fdout, inbuf+offset, len-offset))) {
if (nread == -1) {
perror("Reading from remote end");
break;
}
offset += nread;
inbuf[offset] = '\0';
if (debug)
printf("inbuf:%s\n", inbuf);
while(scan < inbuf + offset) {
if ((*scan == '\n') || (*scan == '\r')) {
*scan = '\0';
if (line<scan) {
i = 0;
while(username[i]) {
if (strlen(username[i]) &&
(!strncmp(line, username[i], strlen(username[i])))) {
gui_add_user(username[i], 2);
username[i] = "";
}
i++;
}
}
scan++;
line = scan;
}
else
scan++;
}
}
return retval;
}
void init()
{
setHandler("online_reply", show_online_user);
setHandler("finger_reply", show_userinfo);
}
void poll_servers()
{
int s;
char *cmd = "<online></online></pip>\n";
char *usertest[3];
usertest[0] = "felix";
usertest[1] = "chris";
usertest[2] = NULL;
if (test) {
/* Test the local in.fingerd via pipes
* Useful for testing the compilation before
* installing it
*/
test_connection(0, cmd);
s = make_conn("some.host", NULL);
if (s >=0)
send_request_v1(s, s, usertest);
return;
}
s = make_conn("localhost", NULL);
send_request(s, s, cmd);
close(s);
return;
/* only a test yet */
s = make_conn("some.host", NULL);
if (s >=0)
send_request_v1(s, s, usertest);
}
void Usage(char *progname)
{
printf("Usage: %s [-c file] [-h] [-V] [-d] [-t]\n", progname);
printf("\t-c file\tuse \"file\" as configuration file\n"
"\t-h\tprint this screen and exit\n"
"\t-V\tprint version number and exit\n"
"\t-d\tdebug modus\n"
"\t-t\ttest modus: start in.fingerd locally\n");
}
int main( int argc, char *argv[] )
{
int flag;
char *progname;
char *home;
/* extraxt base name */
progname = strrchr(argv[0], '/');
if (!progname)
progname = argv[0];
else
progname++;
/* set defaults */
configfile = ".fingerconf";
if ((home = getenv("HOME"))) {
configfile = (char *)malloc(strlen(configfile) + strlen(home) + 3);
sprintf(configfile, "%s/.fingerconf", home);
}
/* parse the command line arguments */
while ((flag = getopt(argc, argv,
"c:Vdghrt")) != EOF)
switch (flag) {
case 'c':
configfile = strdup(optarg);
break;
case 'V':
printf("%s: %s Version %s\n", progname, PACKAGE, VERSION);
exit(0);
case 'd':
debug = 1;
break;
case 'g':
gnufinger = 1;
break;
case 't':
test = 1;
break;
case 'r':
realnames = 1;
break;
case 'h':
default:
Usage(progname);
exit(0);
break;
}
gtk_init (&argc, &argv);
create_gui();
init();
cf = readFingerconf(configfile);
if (cf) {
}
poll_servers();
gtk_main();
return(0);
}
syntax highlighted by Code2HTML, v. 0.9.1