/*
 * $Id: dotqmail2valias.c,v 1.8 2007/05/22 03:58:58 rwidmer Exp $
 * Copyright (C) 2003-2004 Tom Collins
 * Initial version of this program sponsored by ACIS Pty Ltd.
 *
 * Based on "vconvert.c,v 1.2 2003/10/20 18:59:57" in vpopmail 5.4.
 * Copyright (C) 1999-2002 Inter7 Internet Technologies, Inc.
 *
 * 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 <sys/types.h>
#include <dirent.h>
#include "config.h"
#include "vpopmail.h"
#include "vauth.h"

/* Default behavior is to do nothing if there are already valias table 
 * entries for a dotqmail file to be processed.  Define one of the 
 * following settings to do something instead of nothing.
 */

/* To delete the existing valias table entries and replace them
 * with contents of current .qmail files, define
 * DELETE_OLD_VALIAS_ENTRIES.
 */
/* #define DELETE_OLD_VALIAS_ENTRIES */

/* To delete .qmail files that have matching valias table
 * entries (instead of attempting to convert them),
 * define DELETE_OLD_DOTQMAIL_FILES.
 */
/* #define DELETE_OLD_DOTQMAIL_FILES */

int Debug = 0;
int AllDomains = 0;

int do_all_domains();
int conv_domain( char *); 
void usage();
void get_options(int argc, char **argv);

/* replace all occurrences of c1 in s with c2 */
void strreplace (char *s, char c1, char c2)
{
	char *p;
	
	for (p = s; *p != '\0'; p++) if (*p == c1) *p = c2;
}

int main(int argc, char *argv[])
{
#ifndef VALIAS
	fprintf (stderr, "You must enable valiases (./configure --enable-valias) to use this program.\n");
	return -1;
#endif

	if( vauth_open( 1 )) {
		vexiterror( stderr, "Initial open." );
	}

	get_options(argc,argv);

	if ( optind == argc ) {
		if (AllDomains)
			do_all_domains();
		else {
			usage();
			return -1;
		}
	} else {
		for(;optind<argc;++optind){
			lowerit(argv[optind]);
			printf("converting %s\n", argv[optind]);
			if ( conv_domain( argv[optind] ) != 0 ) {
				fprintf(stderr, "conversion of %s failed\n", argv[optind]);
				/* should exit -1 here? */
			}
		}
	}
	return(vexit(0));
}

int do_all_domains()
{
 FILE *fs;
 char assign_file[MAX_BUFF];
 static char tmpbuf[MAX_BUFF];
 int i;

    snprintf(assign_file, sizeof(assign_file), "%s/users/assign",  QMAILDIR); 
    if ( (fs=fopen(assign_file, "r"))==NULL ) {
       snprintf(tmpbuf, sizeof(tmpbuf), "could not open qmail assign file at %s\n", assign_file);
       perror(tmpbuf);
       vexit(-1);
    }
    while ( fgets(tmpbuf, sizeof(tmpbuf),fs) != NULL ) {
        if (*tmpbuf != '+') continue;  /* ignore non-domain entries */
        for(i=1;tmpbuf[i]!=':';++i);
        tmpbuf[i-1] = 0;
        /* ignore non-domain entries */
        if (strchr (tmpbuf, '.') == NULL) continue;
	if ( tmpbuf[1] != '\n' ) {
            printf("converting %s\n", &tmpbuf[1] );
            if ( conv_domain( &tmpbuf[1] ) != 0 ) {
                printf("conversion of %s failed\n", &tmpbuf[1]);
                /* should vexit -1 here? */
            }
        }
    }
    fclose(fs);
    return(0);
}


int conv_domain( char *domain )
{
	char domcopy[MAX_BUFF];
	char domainpath[MAX_BUFF];
	char username[MAX_BUFF];
	char alias_line[MAX_ALIAS_LINE];
	char *p;
	
	DIR *domaindir;
	struct dirent *direntry;
	char dotqmail_fn[MAX_BUFF];
	FILE *dotqmail_fs;
	
	int notlist;
	int linecount;
	
	snprintf (domcopy, sizeof(domcopy), "%s", domain);
	if (vget_assign (domcopy, domainpath, sizeof(domainpath), NULL, NULL) == NULL) {
		fprintf (stderr, "Error, domain %s not found in users/cdb.\n", domain);
		return -1;
	}
	if (strcmp (domain, domcopy) != 0) {
		fprintf (stderr, "Skipping %s (alias of %s).\n", domain, domcopy);
		return -1;
	}
	
	if ((domaindir = opendir (domainpath)) == NULL) {
		fprintf (stderr, "Error, couldn't open %s.\n", domainpath);
		return -1;
	}
	
	while ((direntry = readdir(domaindir)) != NULL) {
		/* don't process .qmail-default */
		if (strcmp (".qmail-default", direntry->d_name) == 0) continue;

		/* process all other files starting with ".qmail-" */
		if (strncmp (".qmail-", direntry->d_name, 7) == 0) {
			snprintf (username, sizeof(username), "%s", &direntry->d_name[7]);
			snprintf (dotqmail_fn, sizeof(dotqmail_fn), "%s/%s", domainpath, direntry->d_name);

			/* convert to email address (change ':' to '.') */
			strreplace (username, ':', '.');
			printf ("  checking %s@%s...", username, domain);
			
			/* Does a VALIAS already exist for the file?  If so, throw an error. */
			if (valias_select (username, domain) != NULL) {
				#ifdef DELETE_OLD_VALIAS_ENTRIES
					valias_delete (username, domain);
				#else
					#ifdef DELETE_OLD_DOTQMAIL_FILES
						printf ("valias already exists, deleting %s.\n", direntry->d_name);
						unlink (dotqmail_fn);
						continue;
					#else
						printf ("valias already exists, skipping.\n");
						continue;
					#endif
				#endif
			}
			
			/* Open the .qmail-alias file */
			if ((dotqmail_fs = fopen (dotqmail_fn, "r")) == NULL ) {
				printf ("Error opening %s, skipping.\n", dotqmail_fn);
				continue;
			}
			
			/* if first line matches "|[^ ]+/ezmlm-", then it's a list and shouldn't get converted */
			/* ! note that .qmail-list-owner has ezmlm-warn on second line ! */
			notlist = 1;
			linecount = 0;
			while (notlist && (fgets (alias_line, sizeof(alias_line), dotqmail_fs) != NULL)) {
				linecount++;
				/* Determine if this is an ezmlm list (which shouldn't be converted to valias) */
				/* if line is program delivery, and contains string "/ezmlm-" before the first " ",
				   then it is a list. */
				if (alias_line[0] == '|') {
					char *p1, *p2;
					p1 = strstr (alias_line, "/ezmlm-");
					p2 = strchr (alias_line, ' ');
					if ( (p1 != NULL) && (p2 == NULL || p1 < p2) ) {
						printf ("mailing list, skipping.\n");
						notlist = 0;
					}
				}
				
				/* strip trailing newline (if present) */
				p = strchr (alias_line, '\n');
				if (p) *p = '\0';
				valias_insert (username, domain, alias_line);
			}
			fclose (dotqmail_fs);
			if (notlist) {
				printf (" converted %u entries.\n", linecount);
				unlink (dotqmail_fn);
			} else {
				/* it's a list, so remove the valias entries we created */
				valias_delete (username, domain);
			}
		}
	}
	
	closedir (domaindir);
	return 0;
}


void usage()
{
	fprintf(stdout, "usage: dotqmail2valias [options] [domainlist]\n");
	fprintf(stdout, "  Converts .qmail-alias files for listed domains to valias format.\n");
	fprintf(stdout, "  Options:\n");
	fprintf(stdout, "    -a = convert all domains\n");
	fprintf(stdout, "    -v = version\n");
	fprintf(stdout, "    -d = debug info\n");
}

void get_options(int argc, char **argv)
{
 int c;
 int errflag;
 extern char *optarg;
 extern int optind;

	errflag = 0;
	Debug = 0;

	while( !errflag && (c=getopt(argc,argv,":avd")) != -1 ) {
		switch(c) {
			case 'a':
				AllDomains = 1;
				break;
			case 'd':
				Debug = 1;
				break;
			case 'v':
				printf("version: %s\n", VERSION);
				break;
			default:
				errflag = 1;
				break;
		}
	}
	if (errflag > 0) {
		usage();
		vexit(-1);
	}
}



syntax highlighted by Code2HTML, v. 0.9.1