/*
elmo - ELectronic Mail Operator
Copyright (C) 2003 rzyjontko
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; version 2.
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.
----------------------------------------------------------------------
this module defines operations on current configuration
*/
/****************************************************************************
* IMPLEMENTATION HEADERS
****************************************************************************/
#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
#include "confhold.h"
#include "confread.h"
#include "hash.h"
#include "rstring.h"
#include "memblock.h"
#include "xmalloc.h"
#include "file.h"
/****************************************************************************
* IMPLEMENTATION PRIVATE DEFINITIONS / ENUMERATIONS / SIMPLE TYPEDEFS
****************************************************************************/
#define CONF_SIZE 3
/****************************************************************************
* IMPLEMENTATION PRIVATE CLASS PROTOTYPES / EXTERNAL CLASS REFERENCES
****************************************************************************/
/****************************************************************************
* IMPLEMENTATION PRIVATE STRUCTURES / UTILITY CLASSES
****************************************************************************/
/**
* this is how I store information about available options
* example:
* name - pop_acc
* fields - server, username, password, port
* fields == NULL iff variable is simple (no fields)
*/
typedef struct citem {
char *name;
rstring_t *fields;
} citem_t;
/**
* this is how I store values for options
* the hashing table stores a list of values associated with an option
*
* m_value is not a usual rstring. It may have some NULLs inside.
*/
typedef struct vitem {
char *s_value;
rstring_t *m_value;
struct vitem *next;
} vitem_t;
typedef struct conf {
int unused;
citem_t *citem;
vitem_t *vitem;
vitem_t *selected;
} conf_t;
/****************************************************************************
* IMPLEMENTATION REQUIRED EXTERNAL REFERENCES (AVOID)
****************************************************************************/
/****************************************************************************
* IMPLEMENTATION PRIVATE DATA
****************************************************************************/
static conf_t conf_table[CONF_SIZE];
static htable_t *variable_table = NULL;
static htable_t *values_table = NULL;
static memblock_t *fields_block = NULL;
static memblock_t *values_block = NULL;
static citem_t *prepare_citem = NULL;
static vitem_t *prepare_vitem = NULL;
/****************************************************************************
* INTERFACE DATA
****************************************************************************/
/****************************************************************************
* IMPLEMENTATION PRIVATE FUNCTION PROTOTYPES
****************************************************************************/
/****************************************************************************
* IMPLEMENTATION PRIVATE FUNCTIONS
****************************************************************************/
static int
field_index (citem_t *item, const char *field)
{
int i;
for (i = 0; i < item->fields->count; i++){
if (strcmp (field, item->fields->array[i]) == 0)
break;
}
return i;
}
static void
destroy_val (void *ptr)
{
vitem_t *item = (vitem_t *) ptr;
for (item = (vitem_t *) ptr; item; item = item->next)
if (item->m_value)
rstring_delete (item->m_value);
}
static void
destroy_def (void *ptr)
{
citem_t *item = (citem_t *) ptr;
if (item->fields)
rstring_delete (item->fields);
}
/****************************************************************************
* INTERFACE FUNCTIONS
****************************************************************************/
void
confhold_init (void)
{
int i;
if (variable_table){
htable_destroy (variable_table, NULL);
}
if (values_table){
htable_destroy (values_table, NULL);
}
if (fields_block){
memblock_destroy (fields_block);
}
if (values_block){
memblock_destroy (values_block);
}
variable_table = htable_create (5);
values_table = htable_create (6);
fields_block = memblock_create (100);
values_block = memblock_create (200);
for (i = 0; i < CONF_SIZE; i++){
conf_table[i].unused = 1;
}
}
void
confhold_free_resources (void)
{
if (variable_table){
htable_destroy (variable_table, destroy_def);
variable_table = NULL;
}
if (values_table){
htable_destroy (values_table, destroy_val);
values_table = NULL;
}
if (fields_block){
memblock_destroy (fields_block);
fields_block = NULL;
}
if (values_block){
memblock_destroy (values_block);
values_block = NULL;
}
}
void
confhold_register (const char *name, int fieldcount, ...)
{
citem_t *item;
char *field;
va_list ap;
item = memblock_malloc (&fields_block, sizeof (citem_t));
item->name = memblock_strdup (&fields_block, name);
if (fieldcount){
item->fields = rstring_create_size (fieldcount + 1);
}
else {
item->fields = NULL;
}
va_start (ap, fieldcount);
while (fieldcount--){
field = memblock_strdup (&fields_block, va_arg (ap, char *));
rstring_add (item->fields, field);
}
va_end (ap);
htable_insert (variable_table, name, item);
}
int
confhold_open (const char *name)
{
int i;
entry_t *c_entry;
entry_t *v_entry;
for (i = 0; i < CONF_SIZE; i++){
if (conf_table[i].unused)
break;
}
if (i == CONF_SIZE)
return -1;
c_entry = htable_lookup (variable_table, name);
if (c_entry == NULL || c_entry->content == NULL)
return -1;
v_entry = htable_lookup (values_table, name);
if (v_entry == NULL || v_entry->content == NULL)
return -1;
conf_table[i].citem = (citem_t *) c_entry->content;
conf_table[i].vitem = (vitem_t *) v_entry->content;
conf_table[i].unused = 0;
return i;
}
void
confhold_close (int cd)
{
conf_table[cd].unused = 1;
}
rstring_t *
confhold_get_fields (int cd, const char *field)
{
int index;
vitem_t *vitem;
rstring_t *result;
if (conf_table[cd].unused)
return NULL;
index = field_index (conf_table[cd].citem, field);
result = rstring_create_size (2);
for (vitem = conf_table[cd].vitem; vitem; vitem = vitem->next){
if (vitem->m_value && vitem->m_value->array[index])
rstring_add (result, vitem->m_value->array[index]);
}
return result;
}
void
confhold_select (int cd, int index)
{
if (conf_table[cd].unused)
return;
for (conf_table[cd].selected = conf_table[cd].vitem;
index && conf_table[cd].selected; index--){
conf_table[cd].selected = conf_table[cd].selected->next;
}
}
void
confhold_select_where (int cd, const char *field, const char *desired)
{
int index;
vitem_t *old_selected;
if (conf_table[cd].unused)
return;
old_selected = conf_table[cd].selected;
index = field_index (conf_table[cd].citem, field);
for (conf_table[cd].selected = conf_table[cd].vitem;
conf_table[cd].selected;
conf_table[cd].selected = conf_table[cd].selected->next){
if (! strcmp (conf_table[cd].selected->m_value->array[index],
desired))
break;
}
if (conf_table[cd].selected == NULL)
conf_table[cd].selected = old_selected;
}
char *
confhold_field_from_selected (int cd, const char *field)
{
int index;
if (conf_table[cd].unused)
return NULL;
if (conf_table[cd].vitem == NULL || conf_table[cd].citem == NULL)
return NULL;
if (conf_table[cd].selected == NULL)
return NULL;
index = field_index (conf_table[cd].citem, field);
return conf_table[cd].selected->m_value->array[index];
}
char *
confhold_get_first (const char *name, const char *field)
{
int i;
entry_t *d_entry = htable_lookup (variable_table, name);
entry_t *v_entry;
citem_t *def;
vitem_t *val;
if (d_entry == NULL && field)
return NULL;
v_entry = htable_lookup (values_table, name);
if (v_entry == NULL)
return NULL;
def = (d_entry) ? (citem_t *) d_entry->content : NULL;
val = (vitem_t *) v_entry->content;
if (field == NULL)
return val->s_value;
if (def == NULL)
return NULL;
i = field_index (def, field);
return val->m_value->array[i];
}
rstring_t *
confhold_get_all (const char *name)
{
entry_t *v_entry;
vitem_t *vitem;
rstring_t *result;
v_entry = htable_lookup (values_table, name);
if (v_entry == NULL || v_entry->content == NULL)
return NULL;
result = rstring_create_size (2);
for (vitem = (vitem_t *) v_entry->content;
vitem;
vitem = vitem->next){
if (vitem->s_value)
rstring_add (result, vitem->s_value);
}
return result;
}
int
confhold_prepare_to_insert (const char *name)
{
entry_t *c_entry;
entry_t *v_entry;
c_entry = htable_lookup (variable_table, name);
if (c_entry == NULL){
prepare_citem = NULL;
return 1;
}
else
prepare_citem = c_entry->content;
v_entry = htable_insert (values_table, name, NULL);
prepare_vitem = memblock_malloc (&values_block, sizeof (vitem_t));
prepare_vitem->next = (vitem_t *) v_entry->content;
prepare_vitem->s_value = NULL;
prepare_vitem->m_value = NULL;
if (prepare_citem && prepare_citem->fields)
prepare_vitem->m_value =
rstring_create_size (prepare_citem->fields->count + 1);
v_entry->content = prepare_vitem;
return 0;
}
int
confhold_insert_value (const char *field, const char *val)
{
int index;
if (prepare_vitem == NULL)
return 0;
if (prepare_citem && prepare_citem->fields && field){
index = field_index (prepare_citem, field);
if (index == prepare_citem->fields->count)
return 1;
prepare_vitem->m_value->array[index] =
memblock_strdup (&values_block, val);
}
else if ((prepare_citem == NULL || prepare_citem->fields == NULL)
&& field == NULL){
prepare_vitem->s_value = memblock_strdup (&values_block, val);
}
return 0;
}
/****************************************************************************
* INTERFACE CLASS BODIES
****************************************************************************/
/****************************************************************************
*
* END MODULE confhold.c
*
****************************************************************************/
syntax highlighted by Code2HTML, v. 0.9.1