static char rcsid[] = "@(#)$Id: aliases.c,v 1.8.40.1 2007/08/25 07:45:27 hurtta Exp $";

/******************************************************************************
 *  The Elm (ME+) Mail System  -  $Revision: 1.8.40.1 $   $State: Exp $
 *
 *  Author: Kari Hurtta <hurtta+elm@posti.FMI.FI> (was hurtta+elm@ozone.FMI.FI)
 *****************************************************************************/

#include "def_aliases.h"

DEBUG_VAR(Debug,__FILE__,"alias");

struct alias_view {
    int classnum;
    int index;
};

static struct AliasView    ** aliasview_list = NULL;
static int                    aliasview_list_len = 0;

struct AliasView * new_aliasview() 
{
    int idx;
    struct AliasView **X;
    struct AliasView *r = safe_malloc(sizeof (*r));

    /* bzero is defined hdrs/defs.h */
    bzero((void *)r,sizeof (*r));

    r->magic                = ALIASVIEW_magic;
    r->aliasclasscount      = 0;
    r->aliasclass           = NULL;

    r->view                 = NULL;
    r->view_len             = 0;

    r->normal_alias_len     = 0;

    for (idx = 0; idx < aliasview_list_len; idx++)
	if (!aliasview_list[idx]) {
	    DPRINT(Debug,7,(&Debug,
			       "malloc_view: Re-using aliasview index %d\n",
			       idx));
	    goto found;
	}

    X = safe_realloc(aliasview_list,(aliasview_list_len+1)* sizeof (*X));
    X[aliasview_list_len] = NULL;
    aliasview_list = X;
    idx = aliasview_list_len++;

    DPRINT(Debug,7,(&Debug,
		       "malloc_view: Allocing new aliasview index %d\n",
		       idx));


 found:
    aliasview_list[idx] = r;

    return r;
}

static void reset_aliasview P_((struct AliasView *aview));
static void reset_aliasview(aview)
     struct AliasView *aview;
{

    if (aview->view) {
	free(aview->view);
	aview->view = NULL;
    }
    aview->view_len = 0;
    aview->normal_alias_len = 0;

}

static void free_aliasview1 P_((struct AliasView **x));
static void free_aliasview1(x)
     struct AliasView **x;
{
    struct AliasView *r = *x;
    if (r->aliasclass) {
	int i;

	for (i = 0; i < r->aliasclasscount; i++) {
	    if (r->aliasclass[i].atype->magic != ALIASTYPE_magic)
		panic("ALIAS VIEW PANIC",__FILE__,__LINE__,"free_aliasview",
		      "bad aliastype magic",0);
		
	    r->aliasclass[i].atype->at_free_it(& (r->aliasclass[i]) );

	    r->aliasclass[i].atype = NULL;    /* Invalidate */
	}

	free(r->aliasclass); r->aliasclass = NULL;
    }
    r->aliasclasscount = 0;

    reset_aliasview(r);

    r->magic = 0;           /* Invalidate */
    free(r); r = NULL;

    *x = r;
}

void free_aliasview(x)
     struct AliasView **x;
{
    int i;
    struct AliasView *r = *x;

    if (r->magic != ALIASVIEW_magic) 
	panic("ALIAS VIEW PANIC",__FILE__,__LINE__,"free_aliasview",
	      "bad aliasview magic",0);

    for ( i = 0; i < aliasview_list_len; i++) {
	if (aliasview_list[i] == r) {
	    
	    SIGDPRINT(Debug,7,(&Debug,
			       "free_aliasview: Aliasview index %d goes free\n",
			       i));
	    
	    aliasview_list[i] = NULL;
	    goto okei;
	}
    }

    panic("MBX VIEW PANIC",__FILE__,__LINE__,"free_aliasview",
	  "aliasview not found from list",0);
	
 okei:
    free_aliasview1(&r);

    *x = r;
}

void free_all_aliasviews()
{
    if (aliasview_list) {
	int i;
	
	for ( i = 0; i < aliasview_list_len; i++) {
	    if (aliasview_list[i]) {
		
		SIGDPRINT(Debug,7,(&Debug,"free_all_aliasviews: [%d]\n",
				   i));
		
		if (aliasview_list[i]->magic    != ALIASVIEW_magic)
		    panic("MBX VIEW PANIC",__FILE__,__LINE__,"free_all_aliasviews",
			  "Bad magic number",0);
		
		free_aliasview1(& (aliasview_list[i]));
	    }
	}
	
	free(aliasview_list);
	aliasview_list = NULL;
    }
    aliasview_list_len = 0;
}

struct aliasclass * add_aliasclass(x,t)
     struct AliasView *x; 
     struct alias_type *t;
{
    if (t->magic != ALIASTYPE_magic)
	panic("ALIAS VIEW PANIC",__FILE__,__LINE__,"add_aliasclass",
	      "bad aliastype magic",0);

    x->aliasclass = safe_realloc(x->aliasclass,
				 ( x->aliasclasscount +1) *
				 sizeof (x->aliasclass[0]));

    x->aliasclass[x->aliasclasscount].atype = t;
    x->aliasclass[x->aliasclasscount].p.dummy = NULL;

    t->at_init_it(& (x->aliasclass[x->aliasclasscount]));

    return (& (x->aliasclass[x->aliasclasscount++]));
}

struct alias_rec * give_alias(aview,index)
     struct AliasView *aview;
     int index;
{
    int cx;
    int cindex;

    if (aview->magic != ALIASVIEW_magic)
	panic("ALIAS VIEW PANIC",__FILE__,__LINE__,"give_alias",
	      "bad aliasview magic",0);
    
    if (index < 0 || index >= aview->view_len)
	panic("ALIAS VIEW PANIC",__FILE__,__LINE__,"give_alias",
	      "bad index",0);
    
    cx     = aview->view[index].classnum;
    cindex = aview->view[index].index;

    if (cx < 0 || cx >= aview->aliasclasscount)
	panic("ALIAS VIEW PANIC",__FILE__,__LINE__,"give_alias",
	      "bad class number",0);

    if (aview->aliasclass[cx].atype->magic != ALIASTYPE_magic)
	panic("ALIAS VIEW PANIC",__FILE__,__LINE__,"give_alias",
	      "bad aliastype magic",0);

    return aview->aliasclass[cx].atype->
	at_it_give_alias( & (aview->aliasclass[cx] ),
			  cindex);
    
}



int get_alias_count(aview)
     struct AliasView *aview;
{
    return aview->normal_alias_len;
}


int get_total_alias_count(aview)
     struct AliasView *aview;
{
    return aview->view_len;
}

/*  current == index+1     value is used only by caller */
int get_alias_current(aview) 
     struct AliasView *aview;
{
    return aview->current;
}

void set_alias_current(aview,cur)
     struct AliasView *aview; 
     int cur;
{
    if (aview->magic != ALIASVIEW_magic)
	panic("ALIAS VIEW PANIC",__FILE__,__LINE__,"set_alias_current",
	      "bad aliasview magic",0);

    aview->current = cur;
}

int get_alias_selected(aview)
     struct AliasView *aview;
{
    return aview->selected;
}

void set_alias_selected(aview,sel)
     struct AliasView *aview; 
     int sel;
{
    if (aview->magic != ALIASVIEW_magic)
	panic("ALIAS VIEW PANIC",__FILE__,__LINE__,"set_alias_selected",
	      "bad aliasview magic",0);

    aview->selected = sel;
}


static void rebuild_aliasview P_((struct AliasView *aview));
static void rebuild_aliasview(aview)
     struct AliasView *aview;
{
    int len = 0;
    int i;
    int dup = 0;
    int x;

    reset_aliasview(aview);

    for (i = 0; i < aview->aliasclasscount; i++) {
	len += aview->aliasclass[i].atype->
	    at_get_count_it(& (aview->aliasclass[i]));
    }

    DPRINT(Debug,4, (&Debug,
		     "rebuild_aliasview: len=%d\n",len));

    if (len < 1)
	return;

    aview->view = safe_malloc(len * sizeof (aview->view[0]));

    x = 0;
    
    for (i = 0; i < aview->aliasclasscount && x < len; i++) {
	int y;

	int count = aview->aliasclass[i].atype->
	    at_get_count_it(& (aview->aliasclass[i]));
	
	for (y = 0; y < count && x < len; y++) {
	    struct alias_rec *a;
	    int D;

	    aview->view[x].classnum = i;
	    aview->view[x].index    = y;

	    a = aview->aliasclass[i].atype->
		at_it_give_alias( & (aview->aliasclass[i] ),
				  y);


	    if (a) {
		int isdup = 0;
		/* Check for duplicates ... */
		
		for (D = 0; D < x; D++) {
		    int cx     = aview->view[D].classnum;
		    int cindex = aview->view[D].index;
		    
		    struct alias_rec *b = 
			aview->aliasclass[cx].atype->
			at_it_give_alias( & (aview->aliasclass[cx] ),
					  cindex);
		    
		    if (b &&
			0 == strcmp(b->alias,a->alias)) {

			DPRINT(Debug,14, (&Debug,
					  "rebuild_aliasview: %d [%d/%d] is previous same alias than [%d/%d]  \"%s\"\n",
					  D,cx,cindex,
					  i,y,
					  b->alias));
			       
			isdup++;
			break;
		    }
		    
		    if (cx >= i)
			break;

		}
	    
		if (isdup) {
		    dup++;

		    if (!(a->type & DUPLICATE)) {
			
			a->type |= DUPLICATE;
			
			DPRINT(Debug,14, (&Debug,
					  "rebuild_aliasview: Marking [%d/%d] \"%s\" as duplicate (not added as %d)\n",
					  i,y,
					  a->name,x));
		    }

		} else {		   
		    if (a->type & DUPLICATE) {
			
			DPRINT(Debug,14, (&Debug,
					  "rebuild_aliasview: Clearing [%d/%d] duplicate mark\n",
					  i,y));
			a->type &= ~DUPLICATE;
		    }

		    x++;
		}
	    }
	}
    }

    DPRINT(Debug,4, (&Debug,
		     "rebuild_aliasview: %d normal aliases\n",x));
    aview->normal_alias_len = x;

    if (dup) {
	/* Add duplicates */

	for (i = 0; i < aview->aliasclasscount && x < len; i++) {
	    int y;
	    
	    int count = aview->aliasclass[i].atype->
		at_get_count_it(& (aview->aliasclass[i]));
	    
	    for (y = 0; y < count && x < len; y++) {

		struct alias_rec *a = aview->aliasclass[i].atype->
		    at_it_give_alias( & (aview->aliasclass[i] ),
				      y);

		if (a) {
		    if (a->type & DUPLICATE) {

			aview->view[x].classnum = i;
			aview->view[x].index    = y;
			x++;
		    }
		}
	    }
	}
    }


    aview->view_len = x;
    
    DPRINT(Debug,4, (&Debug,
		     "rebuild_aliasview: len=%d duplicates=%d\n",
		     x,dup));

}

/* Return 1 if changes */
int update_aview(aview)
     struct AliasView *aview;
{
    int r = 0;
  
    if (aview->magic != ALIASVIEW_magic)
	panic("ALIAS VIEW PANIC",__FILE__,__LINE__,"update_aview",
	      "bad aliasview magic",0);

    if (aview->aliasclass) {
	int i;

	for (i = 0; i < aview->aliasclasscount; i++) {
	    if (aview->aliasclass[i].atype->magic != ALIASTYPE_magic)
		panic("ALIAS VIEW PANIC",__FILE__,__LINE__,"update_aview",
		      "bad aliastype magic",0);
		
	    if (aview->aliasclass[i].atype->
		at_update_it(& (aview->aliasclass[i]))) {

		int j,z;

		r = 1;		
	    }
	}


	if (r) 
	    rebuild_aliasview(aview);
       
    }

    DPRINT(Debug,4, (&Debug, "update_aview=%d\n",r));

    return r;
}


struct sort_data2 {
    struct aliasclass *c;
    struct alias_view   w;
};

struct alias_rec *  give_alias_s(s)
     struct sort_data2 *s;
{
    if (s->c->atype->magic != ALIASTYPE_magic)
	panic("ALIAS VIEW PANIC",__FILE__,__LINE__,"give_alias_s",
	      "bad aliastype magic",0);

    return s->c->atype->at_it_give_alias(s->c, s->w.index);
}

void sort_aview (aview,func)
     struct AliasView     *aview;
     alias_compare_func   *func;
{
    int i;
    struct sort_data2 * array;

    /* Little dirty ... */
    typedef int (*compar) P_((const void *, const void *));
    compar X = (compar) func;

    int len = aview->view_len;
    
    if (aview->magic != ALIASVIEW_magic)
	panic("ALIAS VIEW PANIC",__FILE__,__LINE__,"sort_aview",
	      "bad aliasview magic",0);

    if (len < 2)
	return;

    array = safe_malloc(len * sizeof (array[0]));

    for (i = 0; i < len; i++) {
	int cx     = aview->view[i].classnum;
	int cindex = aview->view[i].index;

	if (cx < 0 || cx >= aview->aliasclasscount)
	    panic("ALIAS VIEW PANIC",__FILE__,__LINE__,"sort_aview",
		  "bad class number",0);

	
	array[i].c           = & (aview->aliasclass[cx] );
	array[i].w           = aview->view[i];	
    }

    qsort(array,len,sizeof (array[0]), X);
   

    for (i = 0; i < len; i++) {
	aview->view[i] = array[i].w;
    }

    free(array);
}

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


syntax highlighted by Code2HTML, v. 0.9.1