/*
 * 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 <ctype.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <signal.h>

#include <output.h>
#include <defines.h>

int option_version = 0;
char *option_config_file = DEFAULT_CONFIG_FILE;
int option_print_config=0;
int option_help = 0;
int rehash_flag = 0;

/* function called when a child terminates */
void sigchldhandler(int x)
{
    int r;
    
    debug("SIGCHLD generated !\n");
    while((r = waitpid(-1,NULL,WNOHANG)) > 0);

    if(r < 0)
    {
	debug("sigchldhandler(): waitpid returned error (%s)\n",strerror(errno));
    }

    /* some old unices seem to remove the signal handler after it was called.
     * so we replace it.
     */
    signal(SIGCHLD,sigchldhandler);
}

/* function to call on SIGHUP
 */
void sighup(int x)
{
    debug("sighup(): Got SIGHUP signal.\n");
    rehash_flag = 1;
}

/*
 * This function checks whether the given word is 
 * in the form {123}
 * 
 * returns 1 on success
 * 0 on failure
 */
int word_is_literal_start(char *buf)
{
    char *p,*q,*i;

    p = buf;
    
    /* check if next letter is '{' */
    
    if(*p != '{') 
	return 0;

    /* check if the string ends with "}\r\n" */
    q = buf + strlen(buf) - 1;
    
    if(*q-- != '}') return 0;
   
    p++;
    i = p;

    while(i <= q)
    {
	if(!isdigit(*i))
	    return 0;
	i++;
    }
   
    return 1;
}

/*
 * This function checks whether the given string ends with the start of a literal
 * and returns the length of the literal on success, or -1 if none found.
 *
 * The string should not be crlf stripped
 */
int check_for_literal_count(char *buf)
{
    char *p,*q,*i;

    if(!(p = strrchr(buf,'{')))
	return -1;

    /* check if the string ends with "}\r\n" */
    q = buf + strlen(buf) - 1;
    
    if(*q-- != '\n') return -1;
    if(*q-- != '\r') return -1;
    if(*q-- != '}') return -1;
   
    p++;
    i = p;

    while(i <= q)
    {
	if(!isdigit(*i))
	    return -1;
	i++;
    }
   
    return (int)strtol(p,NULL,10);
}

/* parse the options given to the program, and handle them */
int parse_options(int argc,char **argv)
{
    int c = 0;

    while((c = getopt(argc,argv,"hvcf:")) != EOF)
    {
        switch((char)c)
        {
            case 'v':
                option_version = 1;
                break;
            case 'f':
                option_config_file = optarg;
                break;
            case 'c':
                option_print_config = 1;
                break;
            case 'h':
            case ':':
            case '?':
            default:
                option_help = 1;
                break;
        }
    }

    return optind;
}

int version()
{
    fprintf(stderr,PROGNAME " " VERSION " by " AUTHOR ".\n\n");

    return 0;
}

int usage(char *prog)
{
    fprintf( stderr,
	    "Usage:\n"
	    "\t%s\t-v -h -c -f <file>\n\n"
	    "\t-v\tPrint version information and exit.\n"
	    "\t-h\tPrint this help screen and exit.\n"
	    "\t-c\tPrint parsed configfile and exit.\n"
	    "\t-f file\tRead \"file\" as the config file.\n\n",prog);
    
    return 0;
}


int my_daemon()
{
    int i = 0,n = 0;
    
    if((n = fork()) < 0)
    {
	debug("my_daemon(): Could not fork !! (%m)\n");
	return -1;
    }

    if(n)
    {
	/* exit parent */
	exit(0);
    }
    
    /* create a new session to get rid of the controlling tty */
    if (setsid() < 0)
    {
	debug("my_daemon(): Can't setsid() !\n");
	return -1;
    }

    if((n = fork())<0)
    {
	debug("my_daemon(): Could not fork !! (%m)\n");
        return -1;
    }

    if(n)
    {
	exit(0);
    }

    n = sysconf(_SC_OPEN_MAX);

    for(i = 0;i < n;i++)
	close(i);
    
    /* open fd 0 to /dev/null */
    open("/dev/null",O_RDWR);
    /* fd 1 */
    dup(0); 
    /* fd 2 */
    dup(0);

    return 0;
}

char *my_strndup(char *s,int n)
{
    char *out = NULL;

    if(!(out = malloc(n+1)))
    {
	debug("my_strndup(): Out of memory\n");
	return NULL;
    }

    strncpy(out,s,n);
    out[n] = '\0';
    
    return out;
}




syntax highlighted by Code2HTML, v. 0.9.1