/*
	CVSNT Helper application API
    Copyright (C) 2004-5 Tony Hoyle and March-Hare Software Ltd

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License version 2.1 as published by the Free Software Foundation.

    This library 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
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/
#include <cvsapi.h>
#include "export.h"
#include "ServerInfo.h"

bool CServerInfo::getRemoteServerInfo(const char *server, remoteServerInfo& rsi)
{
	cvs::string current_rep;
	cvs::string remote = server;
	char *p = (char*)strchr(remote.c_str(),':');
	if(p)
		*p='\0';
	CSocketIO sock;
	if(!sock.create(remote.c_str(),p?p+1:"2401",false))
	{
		CServerIo::error("Couldn't create socket: %s",sock.error());
		return false;
	}
	if(p) *p=':';
	if(!sock.connect())
	{
		CServerIo::error("Couldn't connect to remote server: %s",sock.error());
		return false;
	}
	sock.send("BEGIN ENUM\n",11);
	cvs::string line;
	while(sock.getline(line))
	{
		CServerIo::trace(3,"From remote: %s",line.c_str());
		if(!strncmp(line.c_str(),"error ",6) || strstr(line.c_str(),"bad auth protocol start"))
		{
			CServerIo::error("Couldn't enumerate remote server.  Server does not support enum protocol.\n");
			return false;
		}
		if(!strcmp(line.c_str(),"END ENUM"))
			break;
		char *buf = (char*)line.c_str();
		char *p = strstr(buf,": ");
		if(!p)
			continue; // We don't know what this is
		*p='\0';
		p+=2;

		if(!strcmp(buf,"Version"))
			rsi.server_version = p;
		else if(!strcmp(buf,"ServerName"))
			rsi.server_name = p;
		else if(!strcmp(buf,"Repository"))
		{
			current_rep = p;
			rsi.repositories[current_rep]=p;
		}
		else if(!strcmp(buf,"RepositoryDescription"))
		{
			if(current_rep.size() && *p)
				rsi.repositories[current_rep]=p;
		}
		else if(!strcmp(buf,"RepositoryDefault"))
		{
			rsi.default_repository = current_rep;
		}
		else if(!strcmp(buf,"Protocol"))
			rsi.protocols[p]++;
		else if(!strcmp(buf,"AnonymousUsername"))
			rsi.anon_username=p;
		else if(!strcmp(buf,"AnonymousProtocol"))
			rsi.anon_protocol=p;
		else if(!strcmp(buf,"DefaultProtocol"))
			rsi.default_protocol=p;
		else
			continue; // Future or unknown responses
	}
	sock.close();

	// If there's only one repository it's default
	if(rsi.repositories.size()==1 && !rsi.default_repository.size())
		rsi.default_repository=rsi.repositories.begin()->first.c_str();

	// Sourceforge uses some kind of proxy and sends "-!- unable to open session"
	// instead of any standard error message.  In this case all entries will be empty
	if(!rsi.server_name.size() && !rsi.server_version.size() && rsi.protocols.empty() && rsi.repositories.empty())
	{
		CServerIo::error("Couldn't enumerate remote server.  Server does not support enum protocol.\n");
		return false;
	}

	if(!rsi.default_protocol.size())
	{
		cvs::string best_proto = "pserver";
		if(rsi.protocols.find("sspi")!=rsi.protocols.end())
			best_proto="sspi";
		else if(rsi.protocols.find("sserver")!=rsi.protocols.end())
			best_proto="sserver";
		rsi.default_protocol = best_proto;
	}

	if(!rsi.anon_protocol.size())
		rsi.anon_protocol = "pserver";

	return true;
}

const char *CServerInfo::getGlobalServerInfo(const char *server)
{
	CDnsApi dns;
	const char *p;
	cvs::string tmp,tmp2;
	cvs::string srv = server;

	while((p=strrchr(srv.c_str(),'/'))!=NULL)
	{
		cvs::sprintf(tmp2,80,"%s.%s",tmp.c_str(),p+1);
		tmp=tmp2;
		srv.resize(p-srv.c_str());
	}
	cvs::sprintf(tmp2,80,"%s.%s._cvspserver._tcp.cvsnt.org",tmp.substr(1).c_str(),srv.c_str());
	tmp=tmp2;

	// Straight anonymous connection
	if(dns.Lookup(tmp.c_str(), DNS_TYPE_TEXT))
	{
		m_root = dns.GetRRTxt();
		return m_root.c_str();
	}

	// cvsnt-style anonymous mapping
	if(dns.Lookup(tmp.c_str(), DNS_TYPE_SRV))
	{
		CDnsApi::SrvRR *rr = dns.GetRRSrv();
		cvs::sprintf(m_root,80,"::%s",rr->server);
		return m_root.c_str();
	}

	CServerIo::trace(3,"DNS lookup of %s failed",tmp.c_str());
	return NULL;
}


syntax highlighted by Code2HTML, v. 0.9.1