/*
 * ImapProxy - a caching IMAP proxy daemon
 * Copyright (C) 2002 Steven Van Acker
 * 
 * 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 <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <netdb.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <arpa/inet.h>
#include <stdarg.h>

#include <output.h>

/* socket_printf - sends something over a socket
 * arguments:
 * 	s - socket
 * 	fmt - format to use
 * 	... - args
 */
void socket_printf(int s, char *fmt,...)
{
    static char buf[8192];
    int i;
    va_list v;

    va_start(v, fmt);
    i = vsnprintf(buf, sizeof(buf), fmt, v);
    write(s, buf, i);
    va_end(v);
}

/* resolve a hostname to an IP in long notation
 */
unsigned long my_resolve(char *name)
{
    struct in_addr i;
    struct hostent *h;
    char *s;

    if (inet_aton(name, &i))
        return i.s_addr;

    h = gethostbyname(name);

    if (h)
        return *((unsigned long *) (h->h_addr));

    switch (h_errno)
    {
    case HOST_NOT_FOUND:
        s = "nonexistant host";
        break;
    case NO_ADDRESS:
        s = "no IP for hostname";
        break;
    case NO_RECOVERY:
        s = "fatal name server error";
        break;
    case TRY_AGAIN:
        s = "try again later";
        break;
    default:
        s = strerror(errno);
        break;
    }

    debug("my_resolve(\"%s\"): Unable to resolve %s: %s\n",name, name, s);

    return 0;
}


/*
 * setup_listener - sets a given socket to listen on a port, and returns that port
 * arguments:
 * 	ip - address to bind to
 * 	fd - socket fd
 * returns:
 * 	listening port on success
 * 	-1 on error
 */
int setup_listener(unsigned long ip,int fd,int port)
{
    struct sockaddr_in local;
    int size = 0;
    int on = 1;
    
    local.sin_family = PF_INET;
    local.sin_addr.s_addr = ip;
    local.sin_port = port;

    setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
    
    if (bind(fd, (struct sockaddr *) &local, sizeof(struct sockaddr_in)) < 0)
    {
        debug("setup_listener(): bind() error (%m)\n");
        return -1;
    }
    if (listen(fd, 1) < 0)
    {
        debug("setup_listener(): listen() error (%m)\n");
        return -1;
    }

    size = sizeof(struct sockaddr_in);
    if(getsockname(fd, (struct sockaddr *) &local, &size))
    {
	debug("setup_listener(): getsockname() error (%m)\n");
	return -1;
    }
    
    return htons(local.sin_port);
}

/* nonblock_socket - creates a new socket and sets it to NONBLOCKING
 * returns:
 * 	socket fd on success
 * 	-1 on error
 */
int nonblock_socket()
{
    int sockfd = 0;
    
    if((sockfd = socket(PF_INET,SOCK_STREAM,0))<0)
    {
        debug("nonblock_socket(): Couldn't create socket\n");
        return -1;
    }

    if(fcntl(sockfd,F_SETFL,O_NONBLOCK)<0)
    {
        debug("nonblock_socket(): Couldn't set O_NONBLOCK\n");
        return -1;
    }

    return sockfd;
}


syntax highlighted by Code2HTML, v. 0.9.1