/* Utilities for VFS modules.
   This has nothing to do with cryptography.

   Currently includes login and tcp open socket routines.
   
   Copyright (C) 1995, 1996 Miguel de Icaza
   
   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., 675 Mass Ave, Cambridge, MA 02139, USA.  */

#include <config.h>
#include "net-includes.h"
#include "diffie/diffie-socket.h"
#include "diffie/z-socket.h"

#ifndef test_get_host_and_username
#include "tcputil.h"
/* #include "../src/dialog.h" */	/* for message () */
#include "mem.h"		/* for bcopy */
#include "util.h"	/* for unix_error_string */
#include "diffie/compat.h"
#include "mad.h"

int open_tcp_link  (char *host, int *port, int *version, char *caller)
{
    struct   sockaddr_in server_address;
    unsigned long inaddr;
    struct   hostent *hp;
    int      my_socket;

    if (!*host)
	return 0;
    
    bzero ((char *) &server_address, sizeof (server_address));
    server_address.sin_family = AF_INET;
    
    /*  Try to use the dotted decimal number */
    if ((inaddr = inet_addr (host)) != -1)
	bcopy ((char *) &inaddr, (char *) &server_address.sin_addr,
	       sizeof (inaddr));
    else {
	if ((hp = gethostbyname (host)) == NULL){
	    message_2s (1, caller, " Can't locate hostname: %s ", host);
	    return 0;
	}
	bcopy ((char *) hp->h_addr, (char *) &server_address.sin_addr,
	       hp->h_length);
    }

    /* Try to contact a remote portmapper to obtain the listening port */
    if (*port == 0){
	*port = get_remote_port (&server_address, version);
	if (*port < 1)
	    return 0;
    } else
	*version = 3;	/* FIXED: default to version 3 */
    
    server_address.sin_port = htons (*port);
    
    if ((my_socket = socket (AF_INET, SOCK_STREAM, 0)) < 0){
	message_2s (1, caller, " Can't create socket: %s ",
		 unix_error_string(errno));
	return 0;
    }
    diffie_errno = 0;
    if (connect (my_socket, (struct sockaddr *) &server_address,
	     sizeof (server_address)) < 0){
	message_2s (1, caller, " Can't connect to server: %s ",
		 unix_error_string (errno));
	if (diffie_errno)
	    message_2s (1, caller, " Security says: %s ",
		arc_socket_error_string (diffie_errno));
	close (my_socket);
	return 0;
    }
    return my_socket;
}
#endif

/* Extract the hostname and username from the path */
/* path is in the form: [user@]hostname:port/remote-dir, e.g.:
 *
 * ftp://sunsite.unc.edu/pub/linux
 * ftp://miguel@sphinx.nuclecu.unam.mx/c/nc
 * ftp://tsx-11.mit.edu:8192/
 * ftp://joe@foo.edu:11321/private
 * ftp://joe:password@foo.se
 *
 * If the user is empty, e.g. ftp://@roxanne/private, then your login name
 * is supplied.
 *
 * returns malloced host, user.
 * returns a malloced strings with the pathname relative to the host.
 * */

struct passwd *cached_getpwuid (pid_t pid);
struct group *cached_getgrgid (gid_t gid);

#ifdef HAVE_MAD
char *mad_get_host_and_username (char *path, char **host, char **user, int *port,
			     int default_port, int default_is_anon, char **pass, char *file, int line)
#else
char *get_host_and_username (char *path, char **host, char **user, int *port,
			     int default_port, int default_is_anon, char **pass)
#endif
{
    struct passwd *passwd_info;
    char *dir, *colon, *inner_colon, *at, *rest;
    char *retval = 0;
    char *pcopy = (char *) strdup (path);
    char *pend   = pcopy + strlen (pcopy);
    
    *pass = NULL;
    *port = default_port;
    *user = NULL;
    
    /* locate path component */
    for (dir = pcopy; *dir != PATH_SEP && *dir; dir++)
	;
    if (*dir){
#ifdef HAVE_MAD
	retval = mad_strdup (dir, file, line);
#else
	retval = (char *) strdup (dir);
#endif
	*dir = 0;
    } else {
#ifdef HAVE_MAD
	retval = mad_strdup (PATH_SEP_STR, file, line);
#else
	retval = (char *) strdup (PATH_SEP_STR);
#endif
    }
    
    /* search for any possible user */
    at    = strchr (pcopy, '@');

    /* We have a username */
    if (at){
	*at = 0;
	inner_colon = strchr (pcopy, ':');
	if (inner_colon){
	    *inner_colon = 0;
	    inner_colon++;
	    if (*inner_colon == '@')
		*pass = NULL;
	    else
		*pass = (char *) strdup (inner_colon);
	}
	if (*pcopy != 0)
	    *user = (char *) strdup (pcopy);
	else
	    default_is_anon = 0;
	
	if (pend == at+1)
	    rest = at;
	else
	    rest = at + 1;
    } else
	rest = pcopy;

    if (!*user){
	if (default_is_anon)
	    *user = (char *) strdup ("anonymous");
	else {
	    if ((passwd_info = cached_getpwuid (geteuid ())) == NULL)
		*user = (char *) strdup ("anonymous");
	    else {
#ifdef HAVE_MAD
		*user = (char *) mad_strdup (passwd_info->pw_name, file, line);
#else
		*user = (char *) strdup (passwd_info->pw_name);
#endif
	    }
	    endpwent ();
	}
    }
    /* Check if the host comes with a port spec, if so, chop it */
    colon = strchr (rest, ':');
    if (colon){
	*port = atoi (colon+1);

	if (*port <= 0 || *port >= 65536)
	    *port = 21;
	*colon = 0;
    }
    *host = (char *) strdup (rest);

    free (pcopy);
    return retval;
}


