/*****************************************************************************
 *
 * $Id$
 * Purpose ...............: MBSE Deamon Client
 *
 *****************************************************************************
 * Copyright (C) 1993-2004
 *   
 * Michiel Broek		FIDO:	2:280/2802
 * Beekmansbos 10
 * 1971 BV IJmuiden
 * the Netherlands
 *
 * This file is part of MBSE BBS.
 *
 * This BBS 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, or (at your option) any
 * later version.
 *
 * MBSE BBS 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 MB BBS; see the file COPYING.  If not, write to the Free
 * Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
 *****************************************************************************/

#include "../config.h"
#include "mbselib.h"


static int		sock = -1;	/* Unix Datagram socket		*/
struct sockaddr_un      clntaddr;       /* Client socket address        */
struct sockaddr_un      servaddr;       /* Server socket address        */
struct sockaddr_un      from;           /* From socket address          */
int                     fromlen;
static char		*myname='\0';	/* my program name		*/
char			spath[108];     /* Server socket path           */
char			cpath[108];     /* Client socket path           */


/************************************************************************
 *
 * Connect to Unix Datagram socket, return -1 if error or socket no. 
 */

int socket_connect(char *user, char *prg, char *city)
{
    int 	s;
    static char	buf[SS_BUFSIZE], tty[18];

    myname = prg;

    /*
     * Create Unix Datagram socket for the client.
     */
    s = socket(AF_UNIX, SOCK_DGRAM, 0);
    if (s == -1) {
	perror(myname);
	printf("Unable to create Unix Datagram socket\n");
	return -1;
    }

    /*
     * Client will bind to an address so the server will get
     * an address in its recvfrom call and use it to send
     * data back to the client.
     */
    memset(&clntaddr, 0, sizeof(clntaddr));
    clntaddr.sun_family = AF_UNIX;
    strcpy(clntaddr.sun_path, cpath);

    if (bind(s, (struct sockaddr *)&clntaddr, sizeof(clntaddr)) < 0) {
	close(s);
	perror(myname);
	printf("Can't bind socket %s\n", cpath);
	return -1;
    }

    /*
     * If running seteuid as another user, chown to mbse.bbs
     */
    if (getuid() != geteuid()) {
	chown(cpath, getuid(), getgid());
    } else {
	chmod(cpath, 0775);
    }

    /*
     * Setup address structure for the server socket.
     */
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sun_family = AF_UNIX;
    strcpy(servaddr.sun_path, spath);
	
    /*
     * Now that we have an connection, we gather 
     * information to tell the server who we are.
     */
    if (isatty(1) && (ttyname(1) != NULL)) {
	strcpy(tty, ttyname(1));
	if (strchr(tty, 'p'))
	    memccpy(tty, index(tty, 'p'), '\0', strlen(tty));
	else if (strchr(tty, 't'))
	    memccpy(tty, index(tty, 't'), '\0', strlen(tty));
	else if (strchr(tty, 'c'))
	    memccpy(tty, index(tty, 'c'), '\0', strlen(tty));
    } else {
	strcpy(tty, "-");
    }
    sock = s;
	
    /*
     * Send the information to the server. 
     */
    sprintf(buf, "AINI:5,%d,%s,%s,%s,%s;", getpid(), tty, user, prg, city);
    if (socket_send(buf) != 0) {
	sock = -1;
	return -1;
    }

    strcpy(buf, socket_receive());
    if (strncmp(buf, "100:0;", 6) != 0) {
	printf("AINI not acknowledged by the server\n");
	sock = -1;
	return -1;
    }

    return s;
}



/*
 * Send data via internet domain socket
 */
int socket_send(char *buf)
{
    if (sock == -1)
	return -1;

    if (sendto(sock, buf, strlen(buf), 0, (struct sockaddr *)&servaddr, sizeof(servaddr)) != strlen(buf)) {
	printf("Socket send failed error %d\n", errno);
	return -1;
    }
    return 0;
}



/*
 * Return an empty buffer if somthing went wrong, else the complete
 * dataline is returned.
 */
char *socket_receive(void)
{
    static char	buf[SS_BUFSIZE];
    int		rlen;

    memset((char *)&buf, 0, SS_BUFSIZE);
    fromlen = sizeof(from);
    rlen = recvfrom(sock, buf, SS_BUFSIZE, 0, (struct sockaddr *)&from, &fromlen);
    if (rlen == -1) {
        perror("recv");
        printf("Error reading socket\n");
        memset((char *)&buf, 0, SS_BUFSIZE);
        return buf;
    }
    return buf;
}



/***************************************************************************
 *
 *  Shutdown the socket, first send the server the close command so this
 *  application will be removed from the servers active clients list.
 *  There must be a parameter with the pid so that client applications
 *  where the shutdown will be done by a child process is able to give
 *  the parent pid as an identifier.
 */

int socket_shutdown(pid_t pid)
{
    static char	buf[SS_BUFSIZE];

    if (sock == -1)
	return 0;

    sprintf(buf, "ACLO:1,%d;", pid);
    if (socket_send(buf) == 0) {
	strcpy(buf, socket_receive());
	if (strncmp(buf, "107:0;", 6) != 0) {
	    printf("Shutdown not acknowledged by the server\n");
	    printf("Got \"%s\"\n", buf);
	}
    }
	
    if (shutdown(sock, 1) == -1) {
	perror(myname);
	printf("Cannot shutdown socket\n");
	return -1;
    }

    sock = -1;
    return 0;
}