static char rcsid[] = "@(#)$Id: addr_util.c,v 1.50 2007/03/07 19:23:49 hurtta Exp $";

/******************************************************************************
 *  The Elm (ME+) Mail System  -  $Revision: 1.50 $   $State: Exp $
 *
 *  Modified by: Kari Hurtta <hurtta+elm@posti.FMI.FI> 
 *                           (was hurtta+elm@ozone.FMI.FI)
 ******************************************************************************
 *  The Elm Mail System 
 *
 * 			Copyright (c) 1988-1992 USENET Community Trust
 * 			Copyright (c) 1986,1987 Dave Taylor
 *****************************************************************************/

/** This file contains addressing utilities 

**/

#include "def_elm.h"
#include "s_elm.h"
#include "s_me.h"

DEBUG_VAR(Debug,__FILE__,"addr");

static unsigned char *s2us P_((char *str));
static unsigned char *s2us(str) 
     char *str;
{
    return (unsigned char *)str;
}
static char *us2s P_((unsigned char *str));
static char *us2s(str) 
     unsigned char *str;
{
    return (char *)str;
}


int aliases_to_expanded(x,aview)
     struct expanded_address *x;
     struct AliasView *aview;
{
    int i;
    int tagged = 0;
    int ac = get_alias_count(aview);

    CONST int NEWPOS = x->addrs_len;
    
    for (i=0; i < ac; i++) {
	struct alias_rec *a =  give_alias(aview,i);

	if (a &&
	    ison(a->status, TAGGED)) {
	    struct string *s = new_string2(display_charset,
					   s2us(a->alias));
	    add_textual_addr_(x,s,NEWPOS,0);
	    tagged++;
	    free_string(&s);
	}
    }
    
    if (tagged == 0) {
	int alias_current = get_alias_current(aview);
	struct alias_rec *a =  give_alias(aview,alias_current-1);

	if (a) {
	    struct string *s = new_string2(display_charset,
					   s2us(a->alias));
	    add_textual_addr_(x,s,NEWPOS,0);
	    free_string(&s);
	}
    }

    return tagged;
}

int argv_to_expanded(result,argv,mailer_info,aview)
     struct expanded_address *result;
     char *argv[];
     struct mailer_info      *mailer_info;
     struct AliasView *aview;
{
    int i,res;
    free_expanded_address(result);

    DPRINT(Debug,6,
	   (&Debug, "argv_to_expanded:"));
    for (i = 0;  argv[i]; i++) {
	DPRINT(Debug,6,
	       (&Debug, " [%d]=%s",i,argv[i]));
    }
    DPRINT(Debug,6,
	   (&Debug,"\n"));

    for (i = 0;  argv[i]; i++) {
	/* Because this comes from argument vector,
	   we use system charset instead of display_charset
	*/

	struct string * s = new_string2(system_charset,
					s2us(argv[i]));
	add_textual_addr_(result,s,0,0);

	free_string(&s);
    }

    dump_expanded_address(6,"argv_to_expanded: before build_address_l()",
			  *result);

    /* And make address structures */
    res = build_address_l(result,mailer_info,aview);

    dump_expanded_address(6,"argv_to_expanded: (result)",*result);

    DPRINT(Debug,6,
	   (&Debug, "argv_to_expanded=%d\n",res));
    return res;
}

void addr_to_expanded(result,addrs,mailer_info,aview)
     struct expanded_address *result;
     struct addr_item *addrs;
     struct mailer_info      *mailer_info;
     struct AliasView *aview;
{
    int i;
    free_expanded_address(result);

    DPRINT(Debug,6,
	   (&Debug ,"addr_to_expanded:"));
    if (!addrs) {
	DPRINT(Debug,6,
	       (&Debug ," -- NULL"));
    } else {
	for (i = 0;  
	     addrs[i].addr && addrs[i].fullname && addrs[i].comment; i++) {
	    CONST char *A, *B;

	    DPRINT(Debug,6,
		   (&Debug, 		    
		    " [%d]: {addr=%s, fullname=%S, comment=%S}",
		    i,
		    addrs[i].addr, addrs[i].fullname, 
		    addrs[i].comment));

	    A = get_string_MIME_name(addrs[i].fullname);
	    B = get_string_lang(addrs[i].fullname);	    
	    DPRINT(Debug,11,
		   (&Debug, " (fullname cs=%s lang=%s)",		    
		    A ? A : "<none>",
		    B ? B : "<none>"));
	    
	    A = get_string_MIME_name(addrs[i].comment);
	    B = get_string_lang(addrs[i].comment);	    
	    DPRINT(Debug,11,
		   (&Debug, " (comment cs=%s lang=%s)",		    
		    A ? A : "<none>",
		    B ? B : "<none>"));	    
	}
    }
    DPRINT(Debug,6,
	   (&Debug, "\n"));
    
    for (i = 0;  
	 addrs && addrs[i].addr && addrs[i].fullname && addrs[i].comment; 
	 i++) {
	int pos = add_expanded_addr_(result,addrs[i].addr, 
				     addrs[i].fullname, addrs[i].comment);
	add_textual_addr_(result,NULL,pos,1);
    }

    dump_expanded_address(7,"addr_to_expanded: before build_address_l()",
			  *result);

    /* And make address structures */
    build_address_l(result,mailer_info,aview);

    dump_expanded_address(6,"addr_to_expanded: (result)",*result);
}

void expanded_to_edit_buffer(buffer,expanded)
     struct string ** buffer;
     struct expanded_address expanded;
{
    struct textual *ptr;
    buffer[0] = '\0';

    if (*buffer)
	free_string(buffer);

    dump_expanded_address(6,"expanded_to_edit_buffer",expanded);
 
    for (ptr = expanded.surface; 
	 ptr < expanded.surface + expanded.surface_len; 
	 ptr++) {
	if (*buffer) {
	    struct string * temp;

	    add_ascii_to_string(*buffer,s2us(", "));

	    temp = cat_strings(*buffer,ptr->Textual,0);
	    free_string(buffer);
	    *buffer = temp;
	} else
	    *buffer = dup_string(ptr->Textual);
    }

    if (!*buffer)
	*buffer = new_string(display_charset);

    DPRINT(Debug,6,
	   (&Debug, "expanded_to_edit_buffer: (result) buffer=%S\n",
	    *buffer));
}

void update_expanded_from_edit_buffer(expanded,buffer,mailer_info,aview)
     struct expanded_address *expanded;
     CONST struct string     *buffer;
     struct mailer_info      *mailer_info;
     struct AliasView *aview;   /* NULL if aliases should be ignored */
{
    int i,next;
    struct expanded_address result;
    struct textual *ptr = expanded->surface;
   
    struct string_token * tokenized = string_tokenize(buffer, TOK_mail);

    zero_expanded_address(&result);

    DPRINT(Debug,6,
	   (&Debug, "update_expanded_from_edit_buffer: buffer=%S\n",
	    buffer));
    dump_expanded_address(6,"update_expanded_from_edit_buffer: (initial)",
			  *expanded);

    for (i = 0; tokenized[i].token; i = next) {
	CONST int NEWPOS = result.addrs_len;
	struct string * surface = NULL;
	int q= 0, spacecount =  0, q_seen = 0;

	int Tlen = string_len(tokenized[i].token);

	DPRINT(Debug,9,
	       (&Debug, 
		"update_expanded_from_edit_buffer: [%d]=\"%S\" %04x\n",
		i,
		tokenized[i].token,
		tokenized[i].special));

	if (0x0020 /* SPACE  */ == tokenized[i].special ||
	    0x002C    /* ',' */ == tokenized[i].special) {
	    next = i+1;
	    continue;
	}
	for (next = i; tokenized[next].token; next++) {
	    if (0x003C    /* '<' */  == tokenized[next].special) {
		q++;
		q_seen = 1;
	    } else if (0x003E    /* '>' */ == tokenized[next].special)
		q--;
	    else if (!q && 0x002C    /* ',' */ == tokenized[next].special)
		break;
	    else if (!q && q_seen && 
		     0x0020 /* SPACE  */ != tokenized[next].special &&
		     0x0028 /* '(' */ != tokenized[next].special)
		break;
	    else if (!q && 0x0020 /* SPACE  */  == tokenized[next].special &&
		     tokenized[next+1].token && 
		     0x0028    /* '(' */ == tokenized[next+1].special)
		/* Don't count whitespaces before comments */  ;
	    else if (!q && q_seen &&
		     0x0020 /* SPACE  */ == tokenized[i].special)
		break;
	    else if (!q && 0x0020 /* SPACE  */ == tokenized[next].special)
		spacecount ++;

	    DPRINT(Debug,9,
		   (&Debug, 
		    "update_expanded_from_edit_buffer+ [%d]=\"%S\" %04x  q=%d\n",
		    next,
		    tokenized[next].token,
		    tokenized[next].special,
		    q));
	    
	    if (surface) {
		struct string * tmp1 = cat_strings(surface,
						   tokenized[next].token,0);
		free_string(&surface);
		surface = tmp1;
	    } else {
		surface = dup_string(tokenized[next].token);
	    }
	}

	DPRINT(Debug,9,
	       (&Debug, 
		"update_expanded_from_edit_buffer- spacecount=%d, q=seen=%d\n",
		spacecount,q_seen));

  
	if (surface && 
	    ptr < expanded->surface + expanded->surface_len &&
	    0 == string_cmp(ptr->Textual,
			    surface,
			    -999 /* Unknow values are not equal */
			    )) {
	    int r;
	    int pos = NEWPOS;
	    int count = 0;
	    int j;
	    /* no change -- copy original */
      
	    for (j = 0; j < ptr->len; j++) {
		CONST struct addr_item *ptr1 = & (expanded->addrs[ptr->pos+j]);
		int p = ADD_EXPANDED(result,ptr1->addr,ptr1->fullname,
				     ptr1->comment);
		if (0 == count)
		    pos = p;
		count++;
	    }
	    r=ADD_TEXTUAL(result,ptr->Textual,pos,count);
	    DPRINT(Debug,9,
		   (&Debug, 
		    "update_expanded_from_edit_buffer-> [%d] = %S (keep %d addresses)\n",
		    r,surface,count));
	    
	}

	/* Starting with - is alias expansion removing syntax */
	else if (aview &&
		 Tlen > 0 &&
		 give_unicode_from_string(tokenized[i].token,
					  0) == 0x002D /* '-' */ 
		 ) {
	    int r;
	    struct string * surface1 = NULL;
      
	    DPRINT(Debug,9,
		   (&Debug, 
		    "update_expanded_from_edit_buffer= resscan from %d\n",i));
			   
	    for (next = i; tokenized[next].token; next++) {
		if (0x003C /* '<' */ == tokenized[next].special ||
		    0x003E /* '>' */ == tokenized[next].special ||
		    0x002C /* ',' */ == tokenized[next].special ||
		    0x0020 /* SPACE */ == tokenized[next].special)
		    break;

		DPRINT(Debug,9,
		       (&Debug, 
			"expanded_to_edit_buffer+ [%d]=\"%S\" %04x\n",
			next,tokenized[next].token,tokenized[next].special));
		
		if (surface1) {
		    struct string * tmp1 = cat_strings(surface1,
						       tokenized[next].token,
						       0);
		    free_string(&surface1);
		    surface1 = tmp1;
		} else {
		    surface1 = dup_string(tokenized[next].token);
		}
	    }
	    
	    r=ADD_TEXTUAL(result,surface1,NEWPOS,0);
	    DPRINT(Debug,9,
		   (&Debug, 
		    "update_expanded_from_edit_buffer-> [%d] = %S\n",
		    r,surface1));
	    
	    if (surface1)
		free_string(&surface1);
	    
	    /* word <address> */
	} else if (spacecount <= 1 && q_seen) {
	    int r = ADD_TEXTUAL(result,surface,NEWPOS,0);
	    DPRINT(Debug,9,
		   (&Debug, "update_expanded_from_edit_buffer-> [%d] = %S\n",
		    r,surface));
	} else {
	    struct string * surface1 = NULL;
	    int r;

	    DPRINT(Debug,9,
		   (&Debug, 
		    "update_expanded_from_edit_buffer= resscan from %d\n",i));
	    
	    for (next = i; tokenized[next].token; next++) {
		if (!q && 
		    0x0020 /* SPACE */ == tokenized[next].special &&
		    tokenized[next+1].token && 
		    0x0028 /* '(' */ == tokenized[next+1].special)
		    /* Don't break on whitespaces before comments */  ;
		else if (0x003C /* '<' */ == tokenized[next].special ||
			 0x003E /* '>' */ == tokenized[next].special ||
			 0x002C /* ',' */ == tokenized[next].special ||
			 0x0020 /* SPACE */ == tokenized[next].special)
		    break;

		DPRINT(Debug,9,
		       (&Debug, 
			"update_expanded_from_edit_buffer+ [%d]=\"%S\" %04x\n",
			next,
			tokenized[next].token,
			tokenized[next].special));

		if (surface1) {
		    struct string * tmp1 = cat_strings(surface1,
						       tokenized[next].token,
						       0);
		    free_string(&surface1);
		    surface1 = tmp1;
		} else {
		    surface1 = dup_string(tokenized[next].token);
		}
	    }

	    if (!surface1) {
		DPRINT(Debug,9,
		       (&Debug, "update_expanded_from_edit_buffer-> parse failure\n"));

		lib_error(CATGETS(elm_msg_cat, ElmSet, ElmUnparseable,
				  "Unparseable (%S): %S"),
			  tokenized[next].token,buffer);
		break;
	    }

	    r=ADD_TEXTUAL(result,surface1,NEWPOS,0);
	    DPRINT(Debug,9,
		   (&Debug, "update_expanded_from_edit_buffer-> [%d] = %S\n",
		    r,surface1));
	    
	    if (surface1)
		free_string(&surface1);
	}

	if (ptr < expanded->surface + expanded->surface_len)
	    ptr++;

	if (i == next) {
	    lib_error(CATGETS(elm_msg_cat, ElmSet, ElmUnparseable,
			      "Unparseable (%S): %S"),
		      tokenized[next].token,buffer);
	    next++;
	}

	if (surface)
	    free_string(&surface);
    }

    dump_expanded_address(6,"update_expanded_from_edit_buffer: before build_address_l",
			  result);

    build_address_l(&result,mailer_info,aview);

    free_expanded_address(expanded);
    *expanded = result;   /* put new (same?) result to place */

    if (tokenized)
	free_string_tokenized(&tokenized);

    dump_expanded_address(6,"update_expanded_from_edit_buffer: (result)",
			  *expanded);
}


#ifdef I_NETDB
static int verify_mail_domain P_((char *domain));
static int verify_mail_domain(domain)
     char *domain;
{
    static char * last_verify_domain    = NULL;
    static int    last_verify_result  = -1;
    time_t        last_verify_time    = 0;
    
    int result  = -1;
    
    time_t now;
    
    time(&now);
    
    if (last_verify_time + 1000 > now &&
	last_verify_domain &&
	0 == istrcmp(last_verify_domain,domain))
	result = last_verify_result;
    
    if (-1 == result) {
	struct hostent *he = NULL;
	
	lib_transient(CATGETS(elm_msg_cat, MeSet,
			      MeLookingUp,
			      "Looking up %s ..."),
		      domain);
				
	he = gethostbyname(domain);
	
	if (!he) {
	    DPRINT(Debug,9,(&Debug, 
			    "verify_mail_domain: %s: h_errno=%d\n",
			    domain,h_errno));
	    
	    switch(h_errno) {
	    case HOST_NOT_FOUND:
		result = 0;
		break;
		
	    case NO_ADDRESS:
		result = 1;
		
	    }
	} else
	    result = 1;
	
	
	if (result >= 0) {
	    last_verify_domain = strmcpy(last_verify_domain,domain);
	    last_verify_result = result;
	    last_verify_time   = now;

	    if (result) 
		lib_transient(CATGETS(elm_msg_cat, MeSet,MeLookingUpOK,
				      "Looking up %s ... OK"),
			      domain);
	    else
		lib_transient(CATGETS(elm_msg_cat, MeSet,MeLookingUpNotExists,
				      "Looking up %s ... Not exists"),
			      domain);
	} else
	    lib_transient(CATGETS(elm_msg_cat, MeSet,
				  MeLookingUpFailed,
				  "Looking up %s ... Failed"),
			  domain);
	
    }

    return result;
}

#endif

int build_address_l(expanded,mailer_info,aview)
    struct expanded_address *expanded;
    struct mailer_info      *mailer_info;
    struct AliasView *aview;   /* NULL id aliases should NOT be expanded */
{
    struct textual *ptr;
    int expands = 0;
    struct expanded_address result;
    int too_long = FALSE;

    dump_expanded_address(9,"build_address_l",*expanded);

    zero_expanded_address(&result);

    for (ptr = expanded->surface; 
	 ptr < expanded->surface + expanded->surface_len; 
	 ptr++) {
	CONST int NEWPOS = result.addrs_len;
	struct addr_item * aliases;

	struct addr_item verify_result;
	enum mailer_errcode errcode = MAILER_NOT_AVAIL;

	if (!ptr->Textual) {

	    if (ptr->len == 1) {
		/* If we have no textual presentation we are converting
		 * from struct addrs
		 */
		struct string * temp = 
		    make_surface_addr(expanded->addrs[ptr->pos]);

		int pos = ADD_EXPANDED(result,
				       expanded->addrs[ptr->pos].addr,
				       expanded->addrs[ptr->pos].fullname,
				       expanded->addrs[ptr->pos].comment);
		ADD_TEXTUAL(result,temp,pos,1);
	
		free_string(&temp);
	    } else {
		DPRINT(Debug,1,
		       (&Debug, 
			"build_address_l: SOFWARE ERROR: [%d]: textual=NULL, len=%d\n",
			ptr - expanded->surface, ptr->len));
	    }
	}

	else {
	    charset_t utf8 = MIME_name_to_charset("UTF-8",0);

	    struct string * utf8_temp;
	    unsigned char * utf8_textual;

	    DPRINT(Debug,10,(&Debug,"build_address_l: processing %S\n",
			     ptr->Textual));

	    /* HACK: We use UTF-8 version of Textual .... */

	    if (!utf8) 
		panic("CHARSET PANIC",__FILE__,__LINE__,"build_address_l",
		      "UTF-8 not found",0);

	    utf8_temp    = convert_string(utf8,ptr->Textual,0);
	    utf8_textual = stream_from_string(utf8_temp,0,NULL);

	    if (utf8_textual[0] == '-') {
		/* Is also on result's remove list */
		ADD_TEXTUAL(result,ptr->Textual,NEWPOS,0);
	    }

	    else if (qstrpbrk(us2s(utf8_textual),"!@: <>,()") != NULL) {
		struct string * temp = NULL;
		if (ptr->len == 1) 
		    temp = make_surface_addr(expanded->addrs[ptr->pos]);

		if (temp && 0 == string_cmp(temp,ptr->Textual,999)) {
		    /* no change -- preserve original address */
		    
		    int pos;

		    DPRINT(Debug,10,(&Debug,"build_address_l: ... no change\n"));
		    
		    pos = ADD_EXPANDED(result,
					   expanded->addrs[ptr->pos].addr,
					   expanded->addrs[ptr->pos].fullname,
					   expanded->addrs[ptr->pos].comment);
		    ADD_TEXTUAL(result,temp,pos,1);

		} else {
		    /* generate addresses from textual 'surface' 
		       presentation */
		    int pos = NEWPOS;
		    int count = 0;

		    struct addr_item * address =
			break_down_address(us2s(utf8_textual), 
					   /* If user pastes encoded words 
					      from somewhere decode them also.
					   */
					   is_rfc1522(us2s(utf8_textual)),
					   utf8);
				 
		    struct addr_item *ptr1;

		    for (ptr1 = address; 
			 ptr1 && ptr1 -> addr && 
			     ptr1->fullname && ptr1->comment; 
			 ptr1++) {
			charset_t utf7;

			int p;
			char * sep;

			DPRINT(Debug,10,(&Debug,"build_address_l: ... got %s\n",
					 ptr1->addr));			

			sep = qstrpbrk(ptr1->addr,"!:@");
			
			if (sep) {
			    DPRINT(Debug,9,
				   (&Debug, 
				    "build_address_l: addr %s separator %c\n",
				    ptr1->addr,
				    *sep));
			}

			if (sep && '@' == *sep &&
			    sep > ptr1->addr) {

			    if (0 == istrcmp(sep+1,hostfullname) ||
				0 == istrcmp(sep+1,hostname)) {

			    local_address_verify:

				if (verify_local_address) {

				    DPRINT(Debug,9,(&Debug,
						     "build_address_l: verifying local address %s\n",
						     ptr1->addr));

				    if (mailer_info &&
					verify_mailer_domaddr(mailer_info,
							      ptr1->addr,
							   &verify_result,
							   &errcode)) {
					
					
					DPRINT(Debug,5,
					       (&Debug, 
						"Address %s verified -- really %s\n",
						ptr1->addr,
						verify_result.addr));



		    		    
					ptr1->addr = strmcpy(ptr1->addr,
							     verify_result.addr);

					if (!ptr1->fullname) {
					    ptr1->fullname = verify_result.fullname;
					    verify_result.fullname = NULL;
					} else if (verify_result.fullname)
					    free_string(&verify_result.fullname);

					if (!ptr1->comment) {
					    ptr1->comment = verify_result.comment;
					    verify_result.comment = NULL;
					} else if (verify_result.comment)
					    free_string(&verify_result.comment);
					free(verify_result.addr); 
					verify_result.addr = NULL;

				    } else {

					switch (errcode) {
					    
					case MAILER_NOT_AVAIL:
					    lib_error(CATGETS(elm_msg_cat, 
							      ElmSet, 
							      ElmVerifyNot1,
							      "Unable to verify mail address %s"),
						      ptr1->addr);
					    break;

					case MAILER_NOT_EXIST:
					    lib_error(CATGETS(elm_msg_cat, 
							      ElmSet, ElmVerifyBad1,
							      "Address %s is not e-mail address"),
						      ptr1->addr);
					    break;
					}
				    }



				}


			    } else {
#ifdef I_NETDB
				if (verify_domain) {
				
				    int r;
				    
				    DPRINT(Debug,9,
					   (&Debug, 
					    "build_address_l:  verifying domain %s\n",
					    sep+1));
				
				    r = verify_mail_domain(sep+1);
				    
				    if (0 == r) {
					lib_error(CATGETS(elm_msg_cat, ElmSet, ElmDomainUnknown,
							  "Domain %s of address %S is unknown"),
						  
						  sep+1,
						  ptr->Textual);
				    }
				}
#endif			    
			    }
			    
			} else {   /* Local address */


			    if (sep == NULL &&
				mailer_info &&
				query_mailer_info(mailer_info,MI_USE_DOMAIN)) {
				
				
				DPRINT(Debug,10,(&Debug,
						 "build_address_l: Adding domain %s to address %s\n",
						 hostfullname, ptr1->addr));
				
				ptr1->addr = strmcat(ptr1->addr,"@");
				ptr1->addr = strmcat(ptr1->addr, hostfullname);  
			    }


			    goto local_address_verify;   /* HACK */
			}



			if (text_charset != utf8 &&
			    0 != (CS_mapping 
				  & charset_properties(text_charset))) {
			    struct string * A, *B;

			    /* Convert strings to text_charset
			       so that utf-8 is not show on
			       MIME encoded words
			    */
			    A = convert_string(text_charset,ptr1->fullname,1);
			    B = convert_string(text_charset,ptr1->comment,1);
			    
			    p = ADD_EXPANDED(result,ptr1->addr,A, B);
			    free_string(&A);
			    free_string(&B);
			} else if (convert_utf_header && 
				   (utf7 =  MIME_name_to_charset("UTF-7",0)) &&
				   0 != (CS_mapping & charset_properties(utf7))) {
			    struct string * A, *B;

			    /* If we are using utf-8 as text charset convert it to utf-7 */

			    A = convert_string(utf7,ptr1->fullname,1);
			    B = convert_string(utf7,ptr1->comment,1);
			    
			    p = ADD_EXPANDED(result,ptr1->addr,A, B);
			    free_string(&A);
			    free_string(&B);
			    
			} else
			    p = ADD_EXPANDED(result,ptr1->addr,
					     ptr1->fullname, ptr1->comment);
			if (0 == count)
			    pos = p;
			count++;
		    }
		    ADD_TEXTUAL(result,ptr->Textual,pos,count);
		    if (address)
			free_addr_items(address);
		}

		if (temp)
		    free_string(&temp);
	    } 
	    
	    else if (aview &&
		     NULL != (aliases = 
			      get_alias_address_l(us2s(utf8_textual), TRUE, 
						  &too_long,mailer_info,
						  aview))) {
		struct addr_item *ptr1;
		int pos = NEWPOS;
		int count = 0;

		expands = 1;

		for (ptr1 = aliases; 
		     ptr1 && ptr1 -> addr && ptr1->fullname && ptr1->comment; 
		     ptr1++) {
		    struct textual *ptr2;
		    int p;

		    /* scan words to be eleminated */
		    for (ptr2 = expanded->surface; 
			 ptr2 < expanded->surface + expanded->surface_len; 
			 ptr2++) {
			if (ptr2 -> Textual) {

			    /* FIXME: This is very ineffective */

			    struct string * utf8_temp2    = 
				convert_string(utf8,ptr2->Textual,0);
			    unsigned char * utf8_textual2 = 
				stream_from_string(utf8_temp2,0,NULL);

			    if (utf8_textual2[0] == '-') {
				if (0 == strcmp(ptr1->addr,
						&(us2s(utf8_textual2)[1])))
				    break;
			    }
			    free_string(&utf8_temp2);
			    free(utf8_textual2);
			} 
		    }
		    
		    if (ptr2 && 
			ptr2 < expanded->surface + expanded->surface_len)
			/* Is on eliminating list -- don't add */
			continue;
		    
		    p = ADD_EXPANDED(result,ptr1->addr,ptr1->fullname,
				     ptr1->comment);
		    if (0 == count)
			pos = p;
		    count++;
		}
		ADD_TEXTUAL(result,ptr->Textual,pos,count);

		if (aliases)
		    free_addr_items(aliases);
	    } 

	    else if (too_long) {
		DPRINT(Debug,2,
		       (&Debug, "Overflowed alias expansion for %S\n", 
			ptr->Textual));
		continue;             /* Don't process */
	    }
	    
	    else if (mailer_info &&
		     verify_mailer_addr(mailer_info,us2s(utf8_textual),
					&verify_result,
					&errcode)) {
		int pos;
		
		DPRINT(Debug,5,
		       (&Debug, 
			"Address %S verified -- really %s\n",
			ptr->Textual,verify_result.addr));
		    		    
		/* Preserve possible comment and fullname
		 *
		 * Use dup_string() to avoid shared pointer so
		 * there no need to make spacial case for free_string()
		 */

		if (ptr->len == 1 && ! verify_result.fullname)
		    verify_result.fullname = 
			dup_string(expanded->addrs[ptr->pos].fullname);
		if (ptr->len == 1 && ! verify_result.comment)
		    verify_result.comment = 
			dup_string(expanded->addrs[ptr->pos].comment);

		if (!verify_result.fullname)
		    verify_result.fullname = new_string(display_charset);
		if (!verify_result.comment)
		    verify_result.comment = new_string(display_charset);
	       
		pos = ADD_EXPANDED(result,verify_result.addr,
				   verify_result.fullname,
				   verify_result.comment);
		ADD_TEXTUAL(result,ptr->Textual,pos,1);

		/* ADD_EXPANDED makes copy, so original need to be free'ed 
		 * on above there is make duplicate from 
		 *   expanded->addrs[ptr->pos].{fullname,comment) so 
		 * this can be free'ed safely	     	    
		 */
		free_string(&verify_result.fullname);
		free_string(&verify_result.comment);
		free(verify_result.addr); verify_result.addr = NULL;
	    }

	    else { 
		struct string * gecos  = NULL; 
		struct string * comment = NULL;
		int pos; 

		DPRINT(Debug,10,(&Debug,
				 "build_address_l: local address %S verify failed\n",
				 ptr->Textual));

		if (verify_local_address) {
		    switch (errcode) {
		    case MAILER_NOT_AVAIL:
			lib_error(CATGETS(elm_msg_cat, ElmSet, ElmVerifyNot,
					  "Unable to verify mail address %S"),
				  ptr->Textual);
			break;
		    case MAILER_NOT_EXIST:
			lib_error(CATGETS(elm_msg_cat, ElmSet, ElmVerifyBad,
					  "Address %S is not e-mail address or Elm's alias"),
				  ptr->Textual);
			break;
		    }
		}

		/* Preserve possible comment 
		 *
		 * Use dup_string() to avoid shared pointer so
		 * there no need to make spacial case for free_string()
		 */
		if (ptr->len == 1)
		    gecos = dup_string(expanded->addrs[ptr->pos].fullname);
		if (ptr->len == 1)
		    comment = dup_string(expanded->addrs[ptr->pos].comment);
		
		if (!gecos)
		    gecos = new_string(display_charset);
		if (!comment)
		    comment = new_string(display_charset);

		pos = ADD_EXPANDED(result,us2s(utf8_textual),gecos,comment);
		if (mailer_info &&
		    query_mailer_info(mailer_info,MI_USE_DOMAIN)) {
		    result.addrs[pos].addr = 
			strmcat(result.addrs[pos].addr,"@");
		    result.addrs[pos].addr = strmcat(result.addrs[pos].addr, 
						     hostfullname);
		}
		ADD_TEXTUAL(result,ptr->Textual,pos,1);
	    
		if (check_only) 
		    lib_error(CATGETS(elm_msg_cat, ElmSet, ElmAliasUnknown,
				      "(alias \"%S\" is unknown)"), 
			      ptr->Textual);

		/* ADD_EXPANDED makes copy, so original need to be free'ed
		 * on above there is make duplicate from 
		 *   expanded->addrs[ptr->pos].{fullname,comment) so 
		 * this can be free'ed safely
		 */
		free_string(&gecos);
		free_string(&comment);
	    }

	    free_string(&utf8_temp);
	    free(utf8_textual);
	}
    }
    free_expanded_address(expanded);
    *expanded = result;   /* put new (same?) result to place */

    dump_expanded_address(9,"build_address_l: (result)",*expanded);
    DPRINT(Debug,9,
	   (&Debug,"build_address_l=%d\n",expands));
    
    return expands;
}

int check_8bit_addr(addr)
     struct addr_item * addr;
{
    struct addr_item *p;
    for (p = addr; p && p->fullname && p->addr && p->comment; p++) {
	if (!can_ascii_string(p->fullname))
	    return TRUE;
	if (!can_ascii_string(p->comment))
	    return TRUE;
    }
    return FALSE;
}

/*
 * Local Variables:
 *  mode:c
 *  c-basic-offset:4
 *  buffer-file-coding-system: iso-8859-1
 * End:
 */


syntax highlighted by Code2HTML, v. 0.9.1