#ifndef LINT
static char *rcsid="$Id: clnt_common.c,v 1.11 2003/08/14 12:50:33 crosser Exp $";
#endif

/*
	$Log: clnt_common.c,v $
	Revision 1.11  2003/08/14 12:50:33  crosser
	Memory leak in the client code (ilya@glas.net)
	Changes to recent autoconf/automake (woods@weird.com)
	use pidfile() if it exists (woods@weird.com)
	
	Revision 1.10  1999/07/27 17:17:18  crosser
	remove include version.h
	
	Revision 1.9  1998/07/26 14:06:40  crosser
	fix ret code if no servers

	Revision 1.8  1998/07/12 16:43:57  crosser
	Change protocol: responce now is terminated with empty line

	Revision 1.7  1998/07/05 00:26:18  crosser
	Change copyright

	Revision 1.6  1998/07/04 23:39:35  crosser
	wso_version

	Revision 1.4  1998/07/02 18:01:15  crosser
	change API

	Revision 1.3  1998/07/02 15:37:07  crosser
	persistent config

	Revision 1.2  1998/07/01 05:01:22  crosser
	Big reorganization

	Revision 1.1  1998/05/05 19:08:16  crosser
	Initial revision

*/

/*
	WHAT IS IT:
		Implementation of experimental "whoson" protocol
	AUTHOR:
		Eugene G. Crosser <crosser@average.org>
	COPYRIGHT:
		Public domain
*/

#include "config.h"

#include <sys/types.h>
#include <time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/un.h>
#include <netdb.h>
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <setjmp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#ifdef _REENTRANT
#include <pthread.h>
#endif

#include "whoson.h"
#include "rtconfig.h"
#include "report.h"

#define MAXREQL 1024

int wso_verbose=0;
static	struct _servdesc *servdesc=NULL;

static int wso_request(char *verb,char *addr,char *name,
					char *cbuf,int buflen) {
	char buf[MAXREQL],*p;
	int len=0;
	int rc=-1;
	char *configfile=DEFAULT_CONFIG;
	struct _servdesc *next_server;
#ifdef _REENTRANT
	static pthread_mutex_t mutex;
#endif

	len=strlen(verb);
	if (addr) len+=strlen(addr);
	if (name) len+=strlen(name);
	len+=7;
	if (len > sizeof(buf)) {
		ERRLOG((LOG_ERR,"[WHOSON] Request does not fit in %d bytes\n",
			sizeof(buf)))
		return -1;
	}
	sprintf(buf,"%s %s %s\r\n\r\n",
			verb,
			addr?addr:"",
			name?name:"");

/* Note that in MT-safe version, we first check if config is filled
   outside of the mutex, to avoid fiddling with the locks if we are
   not going to change anything anyway.  As a result, we need to check
   the same thing *again* within the mutex-locked portion.  Hope this
   is still cheaper than locking again each time... */

	if (!servdesc) {
#ifdef _REENTRANT
		pthread_mutex_init(&mutex,(pthread_mutexattr_t*)0);
		pthread_mutex_lock(&mutex);
		if (!servdesc)
#endif
		{
			if (getenv("WHOSON_VERBOSE")) wso_verbose=1;
			if ((configfile=getenv("WHOSON_CONFIG")) == NULL)
				configfile=DEFAULT_CONFIG;
			servdesc=wso_read_config(configfile,0);
		}
		if (!servdesc) {
			ERRLOG((LOG_ERR,"[WHOSON] No configured servers\n"))
			return -1;
		}

#ifdef _REENTRANT
		pthread_mutex_unlock(&mutex);
		pthread_mutex_destroy(&mutex);
#endif
	}

	for (next_server = servdesc;next_server;next_server=servdesc->next) {
		DPRINT(("trying next connector\n"))
		if ((rc=(next_server->root.connector)(next_server->priv,buf))
									>= 0)
			break;
	}

	if (rc >= 0) switch (buf[0]) {
	case '+': rc=0;  break;
	case '-': rc=+1; break;
	default:  rc=-1; break;
	}

	if (cbuf && buflen) {
		strncpy(cbuf,buf+1,buflen-1);
		cbuf[buflen-1]='\0';
	        if ((p=strchr(cbuf,'\n'))) *p='\0';
	        if ((p=strchr(cbuf,'\r'))) *p='\0';
	        DPRINT(("returning: \"%s\"\n",cbuf))
	}

	return rc;
}

char *wso_version(void)
{
	return "Version " VERSION " Build " __DATE__;
}

int wso_login(char *addr,char *name,char *buf,int buflen) {
	return wso_request("LOGIN",addr,name,buf,buflen);
}

int wso_logout(char *addr,char *buf,int buflen) {
	return wso_request("LOGOUT",addr,NULL,buf,buflen);
}

int wso_query(char *addr,char *buf,int buflen) {
	return wso_request("QUERY",addr,NULL,buf,buflen);
}


syntax highlighted by Code2HTML, v. 0.9.1