static char rcsid[] = "@(#)$Id: shared.c,v 1.67 2006/06/29 17:26:41 hurtta Exp $";

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

/*
 * This file is compiled only if dlopen() is available, so
 * that file does not need to be guarded with #ifdef 
 */

#include "headers.h"

DEBUG_VAR(Debug,__FILE__,"dl");

#include "shared_imp.h"
#include "connection_imp.h"
#include "rc_imp.h"
#include "save_opts.h"
#include "s_me.h"
#include "cs_imp.h"
#include "ss_imp.h"

#include "s_elm.h"

#include <errno.h>
#ifndef ANSI_C
extern int errno;
#endif

#if ANSI_C
#define S_(x) static x;
#else
#define S_(x)
#endif


struct shared_FT * shared_folder_types           = NULL;
int shared_folder_type_count                     = 0;


/* FIXME -- is shared_SE_option_types really needed */
struct shared_SEOT  * shared_SE_option_types      = NULL;
int                   shared_SE_option_type_count = 0;

struct shared_CST * shared_CS_types             = NULL;
int    shared_CS_type_count                     = 0;

struct shared_MCF  * shared_MCF_types           = NULL;
int                  shared_MCF_type_count      = 0;

int use_sharedfunc P_((char **value, int enter,
		       int lineno, char *filename));

struct ImpInfo **library_list            = NULL;
int              library_list_count      = 0;


 

static char * give_shname P_((const char *tag));
 
static char * give_shname(tag)
     CONST char *tag;
{
    char * ret = elm_message(FRM("%s/%s%s%s"),
			     SHARED_DIR,
			     SHARED_LIBPREFIX,
			     tag,
			     SHARED_LIBSUFFIX);

    DPRINT(Debug,4,(&Debug,"use-*-library %s => %s\n",tag,ret));

    return ret;				 
}

S_(RC_post_init_f no_rc_post_init)
static void no_rc_post_init(errors)
     int *errors;
{
    /* Nothing */
}


static wants_rand_bits_f no_wants_rand_bits;
static void no_wants_rand_bits (buf,size,entropy_bits)
     CONST char *buf; 
     int size;
     int entropy_bits;
{
    /* Nothing */
}

struct ImpInfo * give_impinfo(tag)
     CONST char * tag;
{
    int i;

    for (i = 0; i < library_list_count; i++) {
	if (0 == strcmp(library_list[i]->tag,tag))
	    return library_list[i];
    }

    library_list = safe_realloc(library_list, 
				  (i+1) * sizeof(library_list[0]));

    library_list[i] = safe_malloc(sizeof (* library_list[i]) );

    bzero((void *)library_list[i], sizeof (* library_list[i]));

    library_list[i]->valid  = 0;
    library_list[i]->tag    = safe_strdup(tag);
    library_list[i]->shname = give_shname(tag);
    
    library_list[i]->handle = NULL;
    library_list[i]->base_lists_updated = 0;

    library_list[i]->regs       = NULL;
    library_list[i]->regs_count = 0;

    library_list[i]->rc_options      = NULL;
    library_list[i]->rc_option_count = 0;
    library_list[i]->rc_post_init    = no_rc_post_init;

    library_list[i]->wants_rand_bits = no_wants_rand_bits;

    library_list_count = i+1;
    return library_list[i];
}

int give_rnum(I,var)
     struct ImpInfo * I; 
     struct dt_shared_info *var;
{
    int i;
    int k;

    for (i = 0; i < I->regs_count; i++) 
	if (I->regs[i].var == var)
	    return i;

    DPRINT(Debug,7,(&Debug,
		    "give_rnum: Adding var %p to %s => rnum=%d\n",
		    var,I->shname,i));

    I->regs = safe_realloc(I->regs,
			   (I->regs_count+1) * sizeof (I->regs[0]));
    
    I->regs[i].var   = var;
    I->regs[i].valid   = 0;
    I->regs[i].updated = 0;
    I->regs[i].r.dummy = NULL;

    DPRINT(Debug,10,(&Debug,
		    "give_rnum: [%p]->regs[%d].valid=%d\n",
		     I,i,I->regs[i].valid));


    if (SHARED_LOADER_magic != var->loader->magic)
	panic("SHARED PANIC",__FILE__,__LINE__,
	      "give_rnum",
	      "Bad magic bumber",0);

    var->loader->func_zero(var,& (I->regs[i]) );

    I->regs_count = i+1;


    for (k = 0; k < var->shared_list_len; k++)
	if (var->shared_list[k] == I)
	    goto found;

    DPRINT(Debug,7,(&Debug,
		    "give_rnum: Adding %s to var %p shared_list (index %d)\n",
		    I->shname,var,k));

    var->shared_list = safe_realloc(var->shared_list,
				    (k+1) * sizeof (var->shared_list[0]));

    var->shared_list[k] = I;
    var->shared_list_len = k+1;


 found:

    DPRINT(Debug,7,(&Debug,
		    "give_rnum=%d [var %p]\n",i,var));

    return i;


}

void load_code0(I)
     struct ImpInfo *I;
{
    if (! I->handle) {
	DPRINT(Debug,4,(&Debug," ... library loading %s\n",
			I->shname));
	
	I->handle = dlopen(I->shname,RTLD_NOW);
	
	if (! I->handle) {
	    lib_error(CATGETS(elm_msg_cat, MeSet,
			      MeDLopen0Error,
			      "library %s: %s: %s"),
		      I->tag, I->shname,
		      dlerror());
	    I->valid = 0;
	    return;
	}
    }

    if (! I->base_lists_updated) {

	/* union hack to avoid warnings about casting
         * between pointer-to-object and pointer-to-function
	 */
       
	union F8 {
	    void *                       ptr;
	    provides_RC_options_f      * f8;
	} f8;

	union F9 {
	    void *                       ptr;
	    RC_post_init_f             * f9;
	} f9;

	union F10 {
	    void *                       ptr;
	    wants_rand_bits_f          * f10;
	} f10;

	/* F11 reserved */

 

	f8.ptr = dlsym( I->handle,  "provides_RC_options");
	f9.ptr  = dlsym( I->handle,  "RC_post_init");
	f10.ptr = dlsym( I->handle,  "wants_rand_bits");



	if (!f8.f8) {
	    DPRINT(Debug,7,(&Debug, " ... NO provides_RC_options\n"));
	}
	if (!f9.f9) {
	   DPRINT(Debug,7,(&Debug, " ... NO RC_post_init\n"));
	}
	if (!f10.f10) {
	    DPRINT(Debug,7,(&Debug, " ... NO wants_rand_bits\n"));
	}





	if (f8.f8) {
	    int count;
	    size_t   s_res8;
	    struct rc_save_info_rec * res8 = f8.f8(&count, &s_res8);

	    if (s_res8 != sizeof (*res8)) {
		DPRINT(Debug,1,(&Debug,"... struct rc_save_info_rec mismatch: %d should be %d\n",
				s_res8,sizeof (*res8)));
	    } else {

		DPRINT(Debug,7,(&Debug," ... provides_RC_options: count %d\n",
				count));

		 I->rc_options      = res8;
		 I->rc_option_count = count;
	    }
	}

	if (f9.f9) {
	     I->rc_post_init  = f9.f9;

	    DPRINT(Debug,7,(&Debug," ... RC_post_init\n"));

	}

	if (f10.f10) {
	     I->wants_rand_bits = f10.f10;
		DPRINT(Debug,7,(&Debug," ... wants_rand_bits\n"));

	}

	 I->base_lists_updated = 1;
    }

    /* TODO: Other bookkeeping */


}

int reg_code1(I,r)
     struct ImpInfo *I; 
     int r;
{
    int res;

    if (SHARED_LOADER_magic != I->regs[r].var->loader->magic)
	panic("SHARED PANIC",__FILE__,__LINE__,
	      "reg_code1",
	      "Bad magic bumber",0);
    
    res = I->regs[r].valid;

    if ( I->regs[r].valid &&
	 ! I->regs[r].updated ) {

	DPRINT(Debug,7,(&Debug,"reg_code1: Checking library %s ... [%d var %p]\n",
			I->shname,r,I->regs[r].var));

	res = I->regs[r].var->loader->func_reg(I, r);
	I->regs[r].updated = 1;
	DPRINT(Debug,7,(&Debug,"reg_code1: ... %s result = %d   [%d var %p]  valid = %d\n",
			I->shname,res,r,I->regs[r].var,
			I->regs[r].valid));
    } else {
	DPRINT(Debug,7,(&Debug,
			"reg_code1: Skipping library %s ... [%d var %p] valid=%d updated=%d\n",
			I->shname,r,I->regs[r].var,
			I->regs[r].valid,
			I->regs[r].updated));
    }


    return res;
}

static void load_code P_((int idx));
static void load_code(idx)
     int idx;
{

    DPRINT(Debug,4,(&Debug,"library [%d] - processing %s ... \n",
		    idx, library_list[idx]->shname));

    load_code0(library_list[idx]);

}


static void unreg1 P_((struct ImpInfo * I, int r));
static void unreg1(I,r)
     struct ImpInfo * I; 
     int r;
{

    if (SHARED_LOADER_magic != I->regs[r].var->loader->magic)
	panic("SHARED PANIC",__FILE__,__LINE__,
	      "unreg1",
	      "Bad magic bumber",0);

    I->regs[r].var->loader->
	func_unreg(I, r);

    I->regs[r].valid   = 0;
    I->regs[r].updated = 0;

    DPRINT(Debug,10,(&Debug,
		     "unreg1: [%p]->regs[%d].valid=%d\n",
		     I,r,I->regs[r].valid));


}

static void unload_code P_((int idx));
static void unload_code(idx)
     int idx;
{
    if (library_list[idx]->regs_count > 0) {
	int i;

	for (i = 0; i < library_list[idx]->regs_count; i++) {
	    	    
	    if (library_list[idx]->regs[i].valid &&
		library_list[idx]->regs[i].updated) {

		unreg1(library_list[idx],i);

	    }	    
	}
    }

    /* TODO: Other bookkeeping */

    if (library_list[idx]->handle) {

	DPRINT(Debug,4,(&Debug,"library  [%d] - unloading %s\n",
			idx,library_list[idx]->shname));


	dlclose(library_list[idx]->handle);
	library_list[idx]->handle = NULL;
    }
}

int tag_ok(name)
     CONST char *name;
{
    if ('\0' == *name)
	return 0;

    if (strspn(name,"abcdefghijklmnopqrstuvwxyz") < 3)
	return 0;

    return strlen(name) == 
	strspn(name,
	       "abcdefghijklmnopqrstuvwxyz0123456789-");
}

static int libraries_loaded = 0;


static int locate_and_load_library P_((const char *prefix));
static int locate_and_load_library(prefix)
     CONST char *prefix;
{
    int i;

    for (i = 0; i < library_list_count; i++) {
	if (0 == strcmp(library_list[i]->tag,prefix)) {
	    
	    /* Do not update libraries_loaded
	       because this loads only one library 
	    */
	    if (library_list[i]->valid &&
		!libraries_loaded)
		load_code(i);

	    if (library_list[i]->valid) {
		int r;

		for (r = 0; r < library_list[i]->regs_count; r++) 
		    reg_code1(library_list[i],r);
	    }

	    return i;
	}
    }
    return -1;
}

void load_shared_libs() 
{
    int i;

    if (libraries_loaded)
	return;

    for (i = 0; i < library_list_count; i++) {
	if (library_list[i]->valid)
	    load_code(i);

	/* NOTE: This do not load variable specific
	         code ...
	*/
    }
    libraries_loaded = 1;
}

void load_shared_libs1(var)
     struct dt_shared_info *var;
{
    int i;
    
    if (var->libraries_loaded)
	return;

    DPRINT(Debug,7,(&Debug,"Loading [var %p] ...\n",var));

    for (i = 0; i < var->shared_list_len; i++) {

	if (var->shared_list[i]->valid)
	    load_code0(var->shared_list[i]);

	if (var->shared_list[i]->valid) {
	    int r = give_rnum(var->shared_list[i],var);

	    DPRINT(Debug,7,(&Debug,
			    "Prosessing [var %p] %d, %s : valid=%d => r=%d\n",
			    var, i, 
			    var->shared_list[i]->shname,
			    var->shared_list[i]->valid,
			    r));

	    reg_code1(var->shared_list[i],r);

	} else {
	    
	    DPRINT(Debug,7,(&Debug,
			    "Skipping [var %p] %d, %s : valid=%d\n",
			    var, i, 
			    var->shared_list[i]->shname,
			    var->shared_list[i]->valid));
    

	}
    }

    DPRINT(Debug,7,(&Debug,"Loading [var %p] done.\n",var));
    var->libraries_loaded = 1;
}

void register_hidden_library(parent,lib)
     struct dt_shared_info *parent;
     struct dt_shared_info *lib;
{
    if (lib->hidden_var)
	panic("SHARED PANIC",__FILE__,__LINE__,
	      "process_lib_reg",
	      "register_hidden_library have children or already registered",0);

    lib->hidden_var = parent->hidden_var;

    parent->hidden_var = lib;
}

static int process_lib_reg P_((struct rc_save_info_rec *r,
			       char *value, int lineno,
			       char *filename));
static int process_lib_reg(r,value,lineno,filename)
     struct rc_save_info_rec *r;
     char *value; 
     int lineno;
     char *filename;
{
    int ret = 1;
    struct dt_shared_info *S = r->val.shared;
    char * temp = safe_strdup(value);
    char *p;


    if (S->loader->magic != SHARED_LOADER_magic)
	panic("SHARED PANIC",__FILE__,__LINE__,
	      "process_lib_reg",
	      "Bad magic bumber (1)",0);

    for (p = strtok(temp," "); p; p = strtok(NULL," ")) {
	if (!tag_ok(p)) {
	    lib_error(CATGETS(elm_msg_cat, MeSet,
			      MeInvalidUseXLib,
			      "%s: %s: Invalid name"),
		      r->name,p);
	    ret = 0;
	    
	} else {
	    
	    struct ImpInfo * I = give_impinfo(p);
	    
	    int rnum = give_rnum(I,S);

	    /* We do not load code here with dlopen, because we
	       cant load code only when it is needed.
	    */
	    if (0 == access(I->shname,ACCESS_EXISTS)) {

		struct dt_shared_info *S1;

		I->valid = 1;
		libraries_loaded = 0;     /* Rescan... */

		I->regs[rnum].valid = 1;
		S->libraries_loaded = 0;

		DPRINT(Debug,10,(&Debug,
				 "process_lib_reg: [%p]->regs[%d].valid=%d\n",
				 I,rnum,I->regs[rnum].valid));

		for (S1 = S->hidden_var; S1;  S1 = S1->hidden_var) {
		    int rnum = give_rnum(I,S1);

		    I->regs[rnum].valid = 1;
		    S->libraries_loaded = 0;

		    DPRINT(Debug,10,(&Debug,
				     "process_lib_reg: [%p]->regs[%d].valid=%d (hidden)\n",
				     I,rnum,I->regs[rnum].valid));
		}
		

	    } else {
		int err = errno;
		
		lib_error(CATGETS(elm_msg_cat, MeSet,
				  MeNonExistUseXLib,
				  "%s: %s: %s: %s"),
			  r->name,I->tag,I->shname,
			  error_description(err));
		ret = 0;
	    }   
	}
    
    }
    
    free(temp);
    return ret;
}

S_(rc_parse_line dt_SHARED_parse_line)
static int dt_SHARED_parse_line(r,lcl,value,lineno,filename, negate)
     struct rc_save_info_rec *r;
     int lcl;
     char *value; 
     int lineno; 
     char *filename;
     int negate;
{   
    int i;

    if (negate) {
	lib_error(CATGETS(elm_msg_cat, ElmSet, ElmBadNegate,
			  "!%s is not supported in line %d in \"%s\" file"),
		  r->name,lineno,filename);
	return 0;
    }

    if (r->val.shared->loader->magic != SHARED_LOADER_magic)
	panic("SHARED PANIC",__FILE__,__LINE__,
	      "dt_SHARED_parse_line",
	      "Bad magic bumber (1)",0);

    for (i = 0; i < r->val.shared->shared_list_len; i++) {
	int j;

	for (j = 0; j < r->val.shared->shared_list[i]->regs_count; j++) {
	    if (r->val.shared->shared_list[i]->regs[j].var->loader->magic !=
		SHARED_LOADER_magic)
		panic("SHARED PANIC",__FILE__,__LINE__,
		      "dt_SHARED_parse_line",
		      "Bad magic bumber (2)",0);

	    if (r->val.shared == r->val.shared->shared_list[i]->regs[j].var) {
		r->val.shared->shared_list[i]->regs[j].valid = 0;


		DPRINT(Debug,10,(&Debug,
				 "dt_SHARED_parse_line: [%p]->regs[%d].valid=%d\n",
				 r->val.shared->shared_list[i],
				 j,
				 r->val.shared->shared_list[i]->regs[j].valid));


		goto found1;
	    }

	}

	panic("SHARED PANIC",__FILE__,__LINE__,
	      "dt_SHARED_parse_line",
	      "No info on list",0);


    found1:;

    }
    
    return process_lib_reg(r,value,lineno,filename);
}

S_(rc_parse_cline dt_SHARED_parse_cline)
static int dt_SHARED_parse_cline(r,lcl,value,lineno,filename)
     struct rc_save_info_rec *r;
     int lcl;
     char *value; 
     int lineno; 
     char *filename;
{
    return process_lib_reg(r,value,lineno,filename);
}


S_(rc_print_value dt_SHARED_print_value)
static void dt_SHARED_print_value(F,r,comment)
     FILE *F;
     struct rc_save_info_rec *r;
     int comment;
{
    int i;
    int len=0;

    if (r->val.shared->loader->magic != SHARED_LOADER_magic)
	panic("SHARED PANIC",__FILE__,__LINE__,
	      "dt_SHARED_print_value",
	      "Bad magic bumber (1)",0);

    if (comment)
	fprintf(F, "### ");
    fprintf(F, "%s =", r->name);


    for (i = 0; i < r->val.shared->shared_list_len; i++) {
	int j;

	for (j = 0; j < r->val.shared->shared_list[i]->regs_count; j++) {
	    if (r->val.shared->shared_list[i]->regs[j].var->loader->magic !=
		SHARED_LOADER_magic)
		panic("SHARED PANIC",__FILE__,__LINE__,
		      "dt_SHARED_print_value",
		      "Bad magic bumber (2)",0);

	    if (r->val.shared == r->val.shared->shared_list[i]->regs[j].var) {
		goto found1;
	    }

	}

	panic("SHARED PANIC",__FILE__,__LINE__,
	      "dt_SHARED_print_value",
	      "No info on list",0);


    found1:

	if (r->val.shared->shared_list[i]->regs[j].valid) {
	    char * s = r->val.shared->shared_list[i]->tag;
	

	    if (strlen(s) + len > 72) {
		if (!comment)
		    fprintf(F, "\n\t");
		else
		    fprintf(F, "\n###\t");
		len = 8;
	    }
	    else {
		fprintf(F, " ");
		++len;
	    }
	    fprintf(F, "%s", s);
	    len += strlen(s);
	}
    }
    fprintf(F,"\n");
}

S_(rc_get_value dt_SHARED_get_value)
static char * dt_SHARED_get_value(r)
     struct rc_save_info_rec *r;
{
    /* static pointer to buffer accross invocations */
    static char * return_buffer = NULL;
    int i;
    int len=0;

    return_buffer = strmcpy(return_buffer,"");    /* Reset result */

    if (r->val.shared->loader->magic != SHARED_LOADER_magic)
	panic("SHARED PANIC",__FILE__,__LINE__,
	      "dt_SHARED_get_value",
	      "Bad magic bumber (1)",0);



    for (i = 0; i < r->val.shared->shared_list_len; i++) {
	int j;

	for (j = 0; j < r->val.shared->shared_list[i]->regs_count; j++) {
	    if (r->val.shared->shared_list[i]->regs[j].var->loader->magic !=
		SHARED_LOADER_magic)
		panic("SHARED PANIC",__FILE__,__LINE__,
		      "dt_SHARED_get_value",
		      "Bad magic bumber (2)",0);

	    if (r->val.shared == r->val.shared->shared_list[i]->regs[j].var) {
		goto found1;
	    }

	}

	panic("SHARED PANIC",__FILE__,__LINE__,
	      "dt_SHARED_get_value",
	      "No info on list",0);


    found1:

	if (r->val.shared->shared_list[i]->regs[j].valid) {
	    char * s = r->val.shared->shared_list[i]->tag;

	    if (return_buffer[0])
		return_buffer = strmcat(return_buffer," ");
	    
	    return_buffer = strmcat(return_buffer,s);
	}
    }

    return return_buffer;
}

struct rc_type rc_DT_SHARED = { RCTYPE_magic,
				dt_SHARED_parse_line, dt_SHARED_parse_cline,
				dt_SHARED_print_value, dt_SHARED_get_value };


int verify_shared_index(i)
     struct ImpInfo *i;
{
    if (i->handle &&
	i->valid)
	return 1;

    return 0;
}

struct SE_option_type * get_option_type(prefix)
     CONST char *prefix;
{
    int i;
    int idx1 = locate_and_load_library(prefix);

    for (i = 0; i < shared_SE_option_type_count; i++) {
	struct ImpInfo *I = shared_SE_option_types[i].imp_idx;

	if (library_list[idx1] == I) {

	    if (! I->handle) {
		lib_error(CATGETS(elm_msg_cat, MeSet,
                                  MeInvalidOptionTag,
				  "Options %s:* ignored -- code not loaded"),
			  prefix);
		return NULL;
	    }
	    return shared_SE_option_types[i].T;
	}
    }
    lib_error(CATGETS(elm_msg_cat, MeSet,
		      MeInvalidOptionTag,
		      "Options %s:* ignored -- code not loaded"),
	      prefix);
    return NULL;
}

void mark_shared_changed(A)
     void *A;
{
    int i;

    for (i = 0; i < library_list_count; i++) {
	int x;

	if (!library_list[i]->handle) 
	    continue;

	for (x = 0; x < library_list[i]->rc_option_count; x++) {
	
	    if (library_list[i]->rc_options[x].val.dummy == A) {
		mark_XX(& (library_list[i]->rc_options[x]));
	    }

	}
    }
}


void mark_fshared_changed(A)
     option_func *A;
{
    int i;

    for (i = 0; i < library_list_count; i++) {
	int x;

	if (!library_list[i]->handle) 
	    continue;

	for (x = 0; x < library_list[i]->rc_option_count; x++) {
	
	    if (library_list[i]->rc_options[x].func_val == A) {
		mark_XX(& (library_list[i]->rc_options[x]));
	    }

	}
    }
}



int give_options(tag,rc_options,rc_option_count)
     char *tag;
     struct rc_save_info_rec ** rc_options;
     int                      * rc_option_count;
{
    int idx1 = locate_and_load_library(tag);
    
    *rc_options           = NULL;
    *rc_option_count      = 0;

    if (idx1 < 0 ||
	!library_list[idx1]->handle) 
	return 0;

    *rc_options       = library_list[idx1]->rc_options;
    *rc_option_count  = library_list[idx1]->rc_option_count;

    return 1;
}

static void seed_rand_bits1(const char *buf, int size,
			    int entropy_bits);

static void seed_rand_bits1(buf,size,entropy_bits)
     CONST char *buf; 
     int size;
     int entropy_bits;
{
    int i;

    DPRINT(Debug,10,(&Debug, 
		    "Seeding random generator %d bytes (%d entropy bits)\n",
		    size,entropy_bits));

    if (entropy_bits > size*8)
	panic("SHARED PANIC",__FILE__,__LINE__,"seed_rand_bits1",
	      "Impossible entropy",0);


    /* Only seed libraries which are loaded */

    for (i = 0; i < library_list_count; i++) {
	if (library_list[i]->handle) {
	    /* We should perhaps mangle data so same bits are
	       not given to different modules
	    */
	    library_list[i]->wants_rand_bits(buf,size,entropy_bits);	    
	}
    }
}

void seed_rand_bits(buf,size,entropy_bits)
     CONST char *buf; 
     int size;
     int entropy_bits;
{
    
    static char buffer[1024];
    static int  byte_count    = 0;
    static int  entropy_count  = 0;
    

    DPRINT(Debug,10,(&Debug, 
		    "Got random generator %d bytes (%d entropy bits)\n",
		    size,entropy_bits));

    if (entropy_bits > size*8)
	panic("SHARED PANIC",__FILE__,__LINE__,"seed_rand_bits",
	      "Impossible entropy",0);

    if (size > sizeof buffer)
	seed_rand_bits1(buf,size,entropy_bits);
    else {

	int i;

	if (size + byte_count > sizeof buffer) {
	    seed_rand_bits1(buffer,byte_count,entropy_count);
	    byte_count = 0;
	    entropy_count = 0;
	}

	/* We can just XOR bits ... */
	for (i = 0; i < size; i++) 
	    buffer[byte_count++] ^= buf[i];

	if (byte_count > sizeof buffer)
	    panic("SHARED PANIC",__FILE__,__LINE__,"seed_rand_bits",
		  "Overflow",0);
	entropy_count += entropy_bits;

	if (entropy_count > 16 && library_list_count) {
	    seed_rand_bits1(buffer,byte_count,entropy_count);
	    byte_count = 0;
	    entropy_count = 0;
	}
    }
}

void post_init_shared_options(errors)
     int *errors;
{
    int i;

    /* Automatically move libraries out from
       use-library ... 
    */

    /* load generic ... */
    load_shared_libs1(&use_shared_all);

    

    /* unreg possible registered but no longer valid... */

    for (i = 0; i < library_list_count; i++) {
	int j;
	for (j = 0; j < library_list[i]->regs_count; j++) {
	    
	    if (! library_list[i]->regs[j].valid &&
		library_list[i]->regs[j].updated) {

		unreg1(library_list[i],j);

	    }

	}
    }

    /* Unload possible loaded but no longer valid... */
    for (i = 0; i < library_list_count; i++) {
	if (!library_list[i]->valid) {
	    DPRINT(Debug,4,(&Debug,"Unloading no longer valid library %s\n",
			    library_list[i]->tag));

	    unload_code(i);
	}
    }

    /* Only post_init libraries which are loaded
       (other do not have options)
    */

    for (i = 0; i < library_list_count; i++) {
	if (library_list[i]->handle &&
	    library_list[i]->rc_option_count > 0) {

	    library_list[i]->rc_post_init(errors);
	}
    }
}


void print_local_shared_options(F,global)
     FILE *F;
     int global;
{
    int i;

    /* We want print options of all shared libs */
    load_shared_libs();

    for (i = 0; i < library_list_count; i++) {
	if (library_list[i]->handle &&
	    library_list[i]->rc_option_count > 0) {
	    int x;
	    
	    fprintf(F,"\n");

	    elm_fprintf(F, 
			CATGETS(elm_msg_cat, MeSet, MeElmrcSection,
				"# Options for %s section (shared library)\n#\n\n"), 
			library_list[i]->tag);
	    fprintf(F,"%s:\n",
		    library_list[i]->tag);

	    DPRINT(Debug,8,(&Debug, " -- library %s  -- %d options\n",
			    library_list[i]->tag,
			    library_list[i]->rc_option_count));

	    for (x = 0; x < library_list[i]->rc_option_count; x++) {
		int local_value;

		/** skip system-only options **/
		if (!global & 
		    (library_list[i]->rc_options[x].flags & FL_SYS) ) {
		    DPRINT(Debug,8,(&Debug,
				    "shlib/option %d -- \"%s\" system-only, flags=%0x\n",
				    x,library_list[i]->rc_options[x].name, 
				    save_info[x].flags ));
		    continue;
		}

		if (global &
		    !(library_list[i]->rc_options[x].flags & FL_SYS) &&
		    !(library_list[i]->rc_options[x].flags & FL_CHANGED)) {
		    DPRINT(Debug,8,(&Debug,
				    "shlib/option %d -- \"%s\" user option, flags=%0x\n",
				    x,library_list[i]->rc_options[x].name, 
				    save_info[x].flags ));
		    continue;
		}

		if (global)
		    local_value = 
			library_list[i]->rc_options[x].flags & FL_CHANGED;
		else
		    local_value = 
			library_list[i]->rc_options[x].flags & FL_LOCAL;
       
		if (RCTYPE_magic != library_list[i]->rc_options[x].dt_type->magic) {
		    DPRINT(Debug,1,(&Debug,
				    "shlib/option %d -- \"%s\" BAD, flags=%0x (library=%s)\n",
				    x,library_list[i]->rc_options[x].name, 
				    save_info[x].flags,
				    library_list[i]->tag));

		    panic("RC PANIC",__FILE__,__LINE__,
			  "print_local_shared_options",
			  "Bad config item type",0);
		}
		library_list[i]->
		    rc_options[x].dt_type->
		    print_value(F,
				& library_list[i]->rc_options[x],
				!local_value);

	    }
	}	   	
    }
}

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


syntax highlighted by Code2HTML, v. 0.9.1