/*:ts=8*/
/*****************************************************************************
 * FIDOGATE --- Gateway UNIX Mail/News <-> FIDO NetMail/EchoMail
 *
 * $Id: rfcaddr.c,v 4.3 1997/10/14 17:59:31 mj Exp $
 *
 * RFCAddr struct handling
 *
 *****************************************************************************
 * Copyright (C) 1990-1997
 *  _____ _____
 * |     |___  |   Martin Junius             FIDO:      2:2452/110
 * | | | |   | |   Radiumstr. 18             Internet:  mj@fido.de
 * |_|_|_|@home|   D-51069 Koeln, Germany
 *
 * This file is part of FIDOGATE.
 *
 * FIDOGATE 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.
 *
 * FIDOGATE 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 FIDOGATE; see the file COPYING.  If not, write to the Free
 * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 *****************************************************************************/

#include "fidogate.h"

#include "shuffle.h"



/*
 * DotNames option from config file: User.Name instead of User_Name
 */
static int dot_names = FALSE;

void rfcaddr_dot_names(int f)
{
    dot_names = f;
}


/*
 * RfcAddrMode option from config file: () <> or none;
 */
static int addr_mode = 0;		/* 0 = user@do.main (Real Name)
					 * 1 = Real Name <user@do.main>
					 * 2 = user@do.main             */

void rfcaddr_mode(int m)
{
    addr_mode = m;
}



/*
 * rfcaddr_from_ftn() --- Generate RFCAddr struct from FTN name and node
 */
#define NOT_ALLOWED_ATOMS	"()<>@,;::\\\"[]"
#define NOT_ALLOWED_QTEXT	"\"\\"
/*#define NOT_ALLOWED_FULLNAME	"()<>"*/
#define NOT_ALLOWED_FULLNAME	"<>"

RFCAddr rfcaddr_from_ftn(char *name, Node *node)
{
    RFCAddr rfc;
    char buf[MAXUSERNAME];
    int i, c;
    char *p;
    int must_quote;

    rfc.flags = 0;
    
    /*
     * Internet address part
     */
#ifdef LOCAL_FTN_ADDRESSES
    if( ! hosts_lookup(node, NULL) )
	strncpy0(rfc.addr, cf_fqdn(), sizeof(rfc.addr));
    else
#endif
	if(node->zone == -1)
	    BUF_COPY(rfc.addr, FTN_INVALID_DOMAIN);
	else
	    BUF_COPY(rfc.addr, ftn_to_inet(node, FALSE));

    /*
     * Translate special chars >= 0x80 and removed ctrl chars
     */
    for(i=0; *name && i<MAXUSERNAME-1; )
    {
	c = (unsigned char)(*name++);
	if(c >= 0x80)			/* Must translate */
	{
	    p = charset_xlate(c, 0);
	    if(p)
		while(*p && i<MAXUSERNAME-1)
		    buf[i++] = *p++;
	}
	else if(c>=' ' && c<0x7f)
	    buf[i++] = c;
    }
    buf[i] = 0;

    /*
     * Check name for characters not allowed in RFC 822 atoms,
     * requiring that name must be quoted with "...". Copying name
     * to rfc.user[].
     */
    must_quote = FALSE;
    for(p=buf; *p; p++)
	if(strchr(NOT_ALLOWED_ATOMS, *p))
	    must_quote = TRUE;
    
    i = 0;
    if(must_quote)
	rfc.user[i++] = '\"';			/* " makes C-mode happy */
    for(p=buf; i<MAXUSERNAME-2 && *p; p++)
	if(!strchr(NOT_ALLOWED_QTEXT, *p))
	{
	    rfc.user[i] = *p;
	    if(rfc.user[i] == ' ')
		rfc.user[i] = dot_names ? '.' : '_';
	    i++;
	}
    if(must_quote)
	rfc.user[i++] = '\"';			/* " makes C-mode happy */
    rfc.user[i] = 0;

#ifdef LOCAL_FTN_ADDRESSES
    if( ! hosts_lookup(node, NULL) )
    {
	/* Add "%p.f.n.z" to user name */
	strncat0(rfc.user, "%"                      , sizeof(rfc.user));
	strncat0(rfc.user, node_to_pfnz(node, FALSE), sizeof(rfc.user));
    }
#endif
    
    /*
     * Copy name to real name field, removing addressing after `@' or `%'
     */
    i = 0;
    for(p=buf; i<MAXUSERNAME-1 && *p && *p!='@' && *p!='%'; p++)
	if(!strchr(NOT_ALLOWED_FULLNAME, *p))
	    rfc.real[i++] = *p;
    rfc.real[i] = 0;
    for(i=strlen(rfc.real)-1; i>=0; i++)	/* Remove trailing spaces */
	if(rfc.real[i] == ' ')
	    rfc.real[i] = 0;
	else
	    break;
    
    return rfc;
}



/*
 * rfcaddr_from_rfc() --- Generate RFCAddr struct from RFC address
 *
 * Supported formats:
 *     user@domain
 *     user@domain (Full Name)
 *     Full Name <user@domain>
 */
RFCAddr rfcaddr_from_rfc(char *addr)
{
    RFCAddr rfc;
    char bufn[MAXUSERNAME];
    char bufa[MAXINETADDR];
    char *p, *s, *r;
    int i;

    rfc.flags = 0;
    
    /*
     * Full name <user@domain>
     */
    if( (p = strchr(addr, '<')) && (r = strrchr(p+1, '>')) )
    {
	/* Full name */
	for(s=addr; is_space(*s); s++) ;
	for(i=0; i<MAXUSERNAME-1 && *s && *s!='<'; i++, s++)
	    bufn[i] = *s;
	bufn[i] = 0;
	/* Address */
	for(i=0, s=p+1; i<MAXINETADDR-1 && *s && s<r; i++, s++)
	    bufa[i] = *s;
	bufa[i] = 0;
    }
    /*
     * user@domain (Full Name)
     */
    else if( (p = strchr(addr, '(')) && (r = strrchr(p+1, ')')) )
    {
	/* Full name */
	for(i=0, s=p+1; i<MAXUSERNAME-1 && *s && s<r; i++, s++)
	    bufn[i] = *s;
	bufn[i] = 0;
	/* Address */
	for(s=addr; is_space(*s); s++) ;
	for(i=0; i<MAXINETADDR-1 && *s && *s!='('; i++, s++)
	    bufa[i] = *s;
	bufa[i] = 0;
    }
    /*
     * user@domain
     */
    else 
    {
	/* No full name */
	bufn[0] = 0;
	/* Address */
	for(s=addr; is_space(*s); s++) ;
	for(i=0; i<MAXINETADDR-1 && *s; i++, s++)
	    bufa[i] = *s;
	bufa[i] = 0;
    }

    /*
     * Copy full name to RFCAddr struct, remove surrounding "..."
     * and leading/trailing spaces
     */
    p = bufn;
    if(*p == '\"')				/* " makes C-mode happy */
	p++;
    while(is_space(*p))
	p++;
    i = strlen(p) -1;
    while(i>=0 && p[i]==' ')
	p[i--] = 0;
    if(i>=0 && p[i]=='\"')			/* " makes C-mode happy */
	p[i--] = 0;
    while(i>=0 && p[i]==' ')
	p[i--] = 0;
    strncpy0(rfc.real, p, sizeof(rfc.real));

    /*
     * Removed leading/trailing spaces from address
     */
    for(p=bufa; is_space(*p); p++) ;
    for(i=strlen(p)-1; i>=0 && is_space(p[i]); p[i--]=0) ;
    
    /*
     * Address type  user@domain
     */
    if( (r = strrchr(p, '@')) )
    {
	/* User name */
	for(i=0, s=p; i<MAXUSERNAME-1 && *s && s<r; i++, s++)
	    rfc.user[i] = *s;
	rfc.user[i] = 0;
	/* Internet address */
	for(i=0, s=r+1; i<MAXINETADDR-1 && *s; i++, s++)
	    rfc.addr[i] = *s;
	rfc.addr[i] = 0;
    }
    /*
     * Address type  host!user
     */
    else if( (r = strchr(p, '!')) )
    {
	/* User name */
	for(i=0, s=r+1; i<MAXUSERNAME-1 && *s; i++, s++)
	    rfc.user[i] = *s;
	rfc.user[i] = 0;
	/* Internet address */
	for(i=0, s=p; i<MAXINETADDR-1 && *s && s<r; i++, s++)
	    rfc.addr[i] = *s;
	rfc.addr[i] = 0;
    }
    /*
     * Address type  user%domain
     */
    else if( (r = strrchr(p, '%')) )
    {
	/* User name */
	for(i=0, s=p; i<MAXUSERNAME-1 && *s && s<r; i++, s++)
	    rfc.user[i] = *s;
	rfc.user[i] = 0;
	/* Internet address */
	for(i=0, s=r+1; i<MAXINETADDR-1 && *s; i++, s++)
	    rfc.addr[i] = *s;
	rfc.addr[i] = 0;
    }
    /*
     * Adress type  user
     */
    else
    {
	/* User name */
	strncpy0(rfc.user, p, sizeof(rfc.user));
	/* Internet address */
	rfc.addr[0] = 0;
    }
    
    
    return rfc;
}



/*
 * rfcaddr_to_asc() --- Text representation of RFCAddr
 */
char *rfcaddr_to_asc(RFCAddr *rfc, int real_flag)
                 
                  			/* TRUE=with real name, FALSE=without*/
{
    SHUFFLEBUFFERS;
    
    if(real_flag && rfc->real[0])
    {
	if(addr_mode == 0) 
	{
	    /* user@do.main (Real Name) */
	    sprintf(tcharp, "%s%s%s (%s)",
		    rfc->user, rfc->addr[0] ? "@" : "", rfc->addr, rfc->real );
	    return tcharp;
	}
	if(addr_mode == 1) 
	{
	    /* Real Name <user@do.main> */
	    sprintf(tcharp, "%s <%s%s%s>",
		    rfc->real, rfc->user, rfc->addr[0] ? "@" : "", rfc->addr );
	    return tcharp;
	}
    }
    
    /* Default, no real name:
     * user@do.main           */
    sprintf(tcharp, "%s%s%s",
	    rfc->user, rfc->addr[0] ? "@" : "", rfc->addr );

    return tcharp;
}



#ifdef TEST /****************************************************************/

int main(int argc, char *argv[])
{
#if 0
    Node node;
    char *name;
    RFCAddr rfc;

    cf_initialize();
    cf_read_config_file(CONFIG_GATE);
    hosts_init();
    maus_init();
    
    if(argc != 3)
    {
	fprintf(stderr, "usage: testrfc name Z:N/F.P\n");
	exit(1);
    }
    
    name = argv[1];
    if(asc_to_node(argv[2], &node, FALSE) == ERROR)
    {
	fprintf(stderr, "testrfc: invalid FTN address\n");
	exit(1);
    }
    
    rfc = rfcaddr_from_ftn(name, &node);
    
    printf("RFCAddr: %s@%s (%s)\n", rfc.user, rfc.addr, rfc.real);
#endif

#if 1
    char *addr;
    RFCAddr rfc;

    cf_initialize();
    cf_read_config_file(CONFIG_GATE);
    hosts_init();
    maus_init();
    
    if(argc != 2)
    {
	fprintf(stderr, "usage: testrfc addr");
	exit(1);
    }
    
    addr = argv[1];

    rfc = rfcaddr_from_rfc(addr);
    printf("RFCAddr: %s@%s (%s)\n", rfc.user, rfc.addr, rfc.real);
#endif
    
    exit(0);
}

#endif /**TEST***************************************************************/
