/*
**    nspasm - The spasm anti-spam milter
**    Copyright (C) 2002 Sean Hanson <aradia@theasylum.org>
**
**    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 <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <ctype.h>
#include <db2/db.h>
#include <pwd.h>
#include <sys/types.h>

#include "spasm.h"

void showhelp(char *command) {
    printf("spasmwl v%s\n", SPASM_VERSION);
    printf("syntax: %s [-h] [-a|-d|-l] [-u [username@]domain.com] [-e entry]\n", command);
    printf("where:\n");
    printf("-h				Ummmm...\n");
    printf("-a				Add a whitelist entry\n");
    printf("-d				Delete a whitelist entry\n");
    printf("-l				List whitelist entries\n");
    printf("-u [username@]domain.com	Username and domain (superuser only)\n");
    printf("-e entry			Whitelist entry to add/delete\n");
    printf("				(envelope sender address: user@domain.com)\n");
    printf("				(host/domain: mail.domain.com, domain.com\n");
    printf("				(IP address: 10.3.2.1, 10.3.2, 10.3, 10\n");
    printf("See man page for more details.\n");
}

int main(int argc, char **argv)
{
    char data[256];
    DB *db;
    DB_ENV dbenv;
    DB_INFO dbinfo;
    DBT dbk, dbv;
    DBC *dbcp;
    int dbfd;
    struct flock lfd;
    char *entry = NULL;
    char *file = NULL;
    int c;
    const char *args = "adle:u:h";
    int ADD = 0;
    int DELETE = 0;
    int LIST = 0;
    uid_t uid;
    struct passwd *pw;
    
    /* Who am I? */
    uid = getuid();
    pw = getpwuid(uid);
    if(pw == NULL) {
	printf("Error looking up userid: %m\n");
	exit(1);
    }

    /* Get options */
    while((c = getopt(argc, argv, args)) != -1) {
	switch(c) {
	    case 'a':
		ADD = 1;
		break;
	    case 'd':
		DELETE = 1;
		break;
	    case 'l':
		LIST = 1;
		break;
	    case 'e':
		entry = strdup(optarg);
		if(entry == NULL) {
		    printf("Error allocating memory for entry: %m\n");
		    if(file != NULL) free(file);
		    exit(1);
		}
		break;
	    case 'u':
		if(uid == 0) {
		    file = strdup(optarg);
		    if(file == NULL) {
		        printf("Error allocating memory for username: %m\n");
		        if(entry != NULL) free(entry);
		        exit(1);
		    }
		} else {
		    printf("You don't have permission to specify a username\n");
		    if(entry != NULL) free(entry);
		    exit(1);
		}
		break;
	    case 'h':
	    case '?':
	    default:
		showhelp(argv[0]);
		exit(0);
	}
    }

    if((ADD + DELETE + LIST) != 1) {
	showhelp(argv[0]);
	if(file != NULL) free(file);
	if(entry != NULL) free(entry);
	exit(0);
    }

    if(uid != 0) {
	sprintf(data, "%s@%s", pw->pw_name, DEFAULT_DOMAIN);
	file = strdup(data);
	if(file == NULL) {
	    printf("Error allocating memory for username: %m\n");
	    if(entry != NULL) free(entry);
	    exit(1);
	}
    }

    if(file == NULL) {
	printf("Username (user@domain.com): ");
/*	fgets(data, sizeof(data), stdin); */
	scanf("%s", data);
	file = strdup(data);
	if(file == NULL) {
	    printf("Error allocating memory for username: %m\n");
	    if(entry != NULL) free(entry);
	    exit(1);
	}
    }
    if(entry == NULL && (ADD || DELETE)) {
	printf("Whitelist entry: ");
	scanf("%s", data);
	entry = strdup(data);
	if(entry == NULL) {
	    printf("Error allocating memory for entry: %m\n");
	    if(file != NULL) free(file);
	    exit(1);
	}
    }

    if(chdir(WHITELIST_DIR) != 0) {
	printf("Error changing directory: %m\n");
	free(file);
	if(entry != NULL) free(entry);
	exit(1);
    }

    memset(&dbenv, 0, sizeof(DB_ENV));
    memset(&dbinfo, 0, sizeof(DB_INFO));
    memset(&dbk, 0, sizeof(DBT));
    memset(&dbv, 0, sizeof(DBT));
    memset(&lfd, 0, sizeof(lfd));
    dbinfo.db_pagesize = 512;
    lfd.l_type = F_WRLCK;

    if(db_open(file, DB_HASH, DB_CREATE, 0644, &dbenv, &dbinfo, &db) != 0) {
	printf("Error opening database file: %m\n");
	free(file);
	if(entry != NULL) free(entry);
	exit(1);
    }
    if(db->fd(db, &dbfd) != 0) {
	printf("Error reading file descriptor for database: %m\n");
	db->close(db, 0);
	free(file);
	if(entry != NULL) free(entry);
	exit(1);
    }
    if(fcntl(dbfd, F_SETLKW, &lfd) == -1) {
	printf("Error setting write lock on database: %m\n");
	db->close(db, 0);
	free(file);
	if(entry != NULL) free(entry);
	exit(1);
    }

    if(ADD || DELETE) {
        dbk.data = entry;
        dbk.size = strlen(entry);
        dbv.data = "1";
        dbv.size = strlen(dbv.data);
        if(ADD) db->put(db, NULL, &dbk, &dbv, 0);
        else if(DELETE) db->del(db, NULL, &dbk, 0);
        if(db->sync(db, 0) != 0) {
            printf("Error syncing database: %m\n");
        }
    } else if(LIST) {
	if(db->cursor(db, NULL, &dbcp) != 0) {
	    printf("Error obtaining database cursor: %m\n");
	    db->close(db, 0);
	    free(file);
	    if(entry != NULL) free(entry);
	    exit(1);
	}
	while(dbcp->c_get(dbcp, &dbk, &dbv, DB_NEXT) == 0) {
	    char *buf;
	    if((buf = calloc(dbk.size+1, 1)) == NULL) {
		printf("Error allocating memory for buf: %m\n");
	    } else {
		strncpy(buf, dbk.data, dbk.size);
		printf("%s\n", buf);
		free(buf);
	    }
	}
	dbcp->c_close(dbcp);
    }

    db->close(db, 0);
    free(file);
    if(entry != NULL) free(entry);
    exit(0);
}
