/* * Copyright (c) 2004, 2005 Sendmail, Inc. and its suppliers. * All rights reserved. * * By using this file, you agree to the terms and conditions set * forth in the LICENSE file which can be found at the top level of * the sendmail distribution. */ #include "sm/generic.h" SM_RCSID("@(#)$Id: sequence.c,v 1.16 2007/01/22 17:25:06 ca Exp $") #include "sm/assert.h" #include "sm/error.h" #include "sm/memops.h" #include "sm/heap.h" #include "map.h" #include "sm/map.h" #include "sm/maps.h" #include "sm/mapc.h" #include "sm/mapclasses.h" /* maximum number of maps in a sequence map */ #define SEQMAP_MAX 16 typedef struct sm_seqmap_S sm_seqmap_T, *sm_seqmap_P; struct sm_seqmap_S { char *seqmap_name; uint seqmap_nmaps; sm_map_P seqmap_maps[SEQMAP_MAX]; }; /* static sm_map_open_F sm_seq_open; */ /* static sm_map_close_F sm_seq_close; */ static sm_map_alloc_F sm_seq_alloc; static sm_map_free_F sm_seq_free; static sm_map_locate_F sm_seq_locate; static sm_map_first_F sm_seq_first; static sm_map_next_F sm_seq_next; /* ** SEQMAP_FREE -- free sequence map context ** ** Parameters: ** db -- pointer to sequence map ** ** Returns: ** usual sm_error code */ static sm_ret_T seqmap_free(sm_seqmap_P db) { if (db != NULL) sm_free_size(db, sizeof(*db)); return SM_SUCCESS; } /* ** SEQMAP_NEW -- allocate sequence map context ** ** Parameters: ** pdb -- pointer to pointer to sequence map (output) ** ** Returns: ** usual sm_error code */ static sm_ret_T seqmap_new(sm_seqmap_P *pdb) { sm_seqmap_P db; SM_REQUIRE(pdb != NULL); *pdb = NULL; db = sm_zalloc(sizeof(*db)); if (NULL == db) return sm_error_perm(SM_EM_MAP, ENOMEM); *pdb = db; return SM_SUCCESS; } /* ---------------------------------------- */ /* ** SM_SEQ_SETOPT -- set options for map ** ** Parameters: ** map -- map ** ap -- options ** ** Returns: ** usual sm_error code */ static sm_ret_T sm_seq_setopt(sm_map_P map, va_list ap) { sm_ret_T ret; int k; sm_map_P maph; sm_cstr_P map_name; sm_seqmap_P db; sm_mapc_P mapc; SM_IS_MAP(map); db = (sm_seqmap_P) map->sm_map_db; if (NULL == db) return sm_error_perm(SM_EM_MAP, ENOENT); ret = SM_SUCCESS; mapc = map->sm_map_class; SM_IS_MAPC(mapc); for (;;) { k = va_arg(ap, int); if (SMPO_END == k) break; switch (k) { case SMPO_MAP: if (db->seqmap_nmaps >= SM_ARRAY_SIZE(db->seqmap_maps)) { ret = sm_error_perm(SM_EM_MAP, E2BIG); goto error; } maph = va_arg(ap, sm_map_P); SM_IS_MAP(maph); db->seqmap_maps[db->seqmap_nmaps++] = maph; break; case SMPO_MAPNAME: if (db->seqmap_nmaps >= SM_ARRAY_SIZE(db->seqmap_maps)) { ret = sm_error_perm(SM_EM_MAP, E2BIG); goto error; } map_name = va_arg(ap, sm_cstr_P); ret = sm_mapname_find(mapc->sm_mapc_maps, map_name, &maph); if (sm_is_err(ret)) goto error; SM_IS_MAP(maph); db->seqmap_maps[db->seqmap_nmaps++] = maph; break; default: /* silently ignore bogus options? */ break; } } error: return ret; } /* ** SM_SEQ_GETOPT -- get options for map ** Does NOT do anything useful right now! ** ** Parameters: ** map -- map ** which -- which option? ** valp -- pointer to place where result should be stored ** ** Returns: ** usual sm_error code */ static sm_ret_T sm_seq_getopt(sm_map_P map, int which, void *valp) { sm_ret_T ret; sm_seqmap_P db; SM_IS_MAP(map); db = (sm_seqmap_P) map->sm_map_db; if (NULL == db) return sm_error_perm(SM_EM_MAP, ENOENT); /* ... */ ret = SM_SUCCESS; return ret; } /* ** SM_SEQ_CLOSE -- close map ** ** Parameters: ** map -- map ** flags -- flags for map ** ** Returns: ** usual sm_error code */ static sm_ret_T sm_seq_close(sm_map_P map, uint32_t flags) { sm_ret_T ret; sm_mapc_P mapc; sm_seqmap_P db; SM_IS_MAP(map); mapc = map->sm_map_class; SM_IS_MAPC(mapc); ret = SM_SUCCESS; db = (sm_seqmap_P) map->sm_map_db; if (NULL == db) return sm_error_perm(SM_EM_MAP, ENOENT); /* close SEQ map */ seqmap_free(db); map->sm_map_db = NULL; return ret; } /* ** SM_SEQ_DESTROY -- destroy map ** XXX more parameters... ** ** Parameters: ** map -- map ** flags -- flags for map ** ** Returns: ** usual sm_error code */ static sm_ret_T sm_seq_destroy(sm_map_P map, uint32_t flags) { sm_ret_T ret; sm_mapc_P mapc; sm_seqmap_P db; SM_IS_MAP(map); mapc = map->sm_map_class; SM_IS_MAPC(mapc); ret = SM_SUCCESS; db = (sm_seqmap_P) map->sm_map_db; if (NULL == db) return sm_error_perm(SM_EM_MAP, ENOENT); /* destroy? */ seqmap_free(db); map->sm_map_db = NULL; return ret; } /* ** SM_SEQ_CREATE -- create map ** ** Parameters: ** mapc -- map context ** type -- type of map ** flags -- flags for map ** map -- map ** ** Returns: ** usual sm_error code */ static sm_ret_T sm_seq_create(sm_mapc_P mapc, const sm_cstr_P type, uint32_t flags, sm_map_P map) { sm_ret_T ret; sm_seqmap_P db; SM_IS_MAPC(mapc); SM_REQUIRE(map != NULL); db = NULL; ret = SM_SUCCESS; /* create SEQ map ... */ ret = seqmap_new(&db); if (sm_is_err(ret)) return ret; map->sm_map_db = db; map->sm_map_caps = SMMAP_CAPS_LTALL; return ret; } /* ** SM_SEQ_OPEN -- open map ** Note: this currently requires that all maps are already open! ** ** Parameters: ** mapc -- map context ** type -- type of map (currently ignored) ** flags -- flags for map (currently ignored) ** path -- path of map (currently ignored) ** mode -- open mode (currently ignored) ** map -- map ** ap -- additional argument ** ** Returns: ** usual sm_error code */ static sm_ret_T sm_seq_open(sm_mapc_P mapc, const sm_cstr_P type, uint32_t flags, const char *path, int mode, sm_map_P map, va_list ap) { sm_ret_T ret; sm_seqmap_P db; uint i; SM_IS_MAPC(mapc); SM_REQUIRE(map != NULL); ret = SM_SUCCESS; db = map->sm_map_db; if (NULL == db) return sm_error_perm(SM_EM_MAP, ENOENT); if (db->seqmap_nmaps <= 0) return sm_error_perm(SM_EM_MAP, EINVAL); /* open SEQ map ... */ for (i = 0; i < db->seqmap_nmaps; i++) { if (db->seqmap_maps[i] == NULL) return sm_error_perm(SM_EM_MAP, EINVAL); /* other checks? */ #if 0 ret = sm_map_open(maps, NULL, NULL, 0, NULL, mode, &db->seqmap_maps[i]); #endif /* 0 */ } return ret; #if 0 error: if (db != NULL) { (void) db->close(db, 0); db = NULL; } return ret; #endif /* 0 */ } /* ** SM_SEQ_LOOKUP -- lookup a key in SEQ, return data if found ** ** Parameters: ** map -- map context ** flags -- flags ** key -- key ** data -- data (output) ** ** Returns: ** usual sm_error code */ static sm_ret_T sm_seq_lookup(sm_map_P map, uint32_t flags, sm_map_key_P key, sm_map_data_P data) { sm_ret_T ret, tempfail; uint i; sm_map_P maph; sm_seqmap_P db; SM_IS_MAP(map); SM_IS_KEY(key); SM_IS_DATA(data); tempfail = ret = SM_SUCCESS; db = (sm_seqmap_P) map->sm_map_db; if (NULL == db) return sm_error_perm(SM_EM_MAP, ENOENT); /* XXX */ if (db->seqmap_nmaps <= 0) return sm_error_perm(SM_EM_MAP, EINVAL); /* XXX WARNING: changes key inplace! */ if (SM_IS_FLAG(flags, SMMAP_FL_LWR_KEY)) { SM_CLR_FLAG(flags, SMMAP_FL_LWR_KEY); sm_str2lower(key); } for (i = 0; i < db->seqmap_nmaps; i++) { maph = db->seqmap_maps[i]; if (NULL == maph) return sm_error_perm(SM_EM_MAP, EINVAL); ret = sm_map_lookup(maph, flags, key, data); if (SM_SUCCESS == ret) break; if (sm_is_err(ret) && sm_is_temp_err(ret)) tempfail = ret; } if (sm_is_err(ret) && tempfail != SM_SUCCESS) ret = tempfail; return ret; } #if 0 /* ** SM_SEQ_ADD -- add key/data to SEQ ** Not correctly implemented. ** ** Parameters: ** map -- map context ** key -- key ** data -- data ** flags -- flags ** ** Returns: ** usual sm_error code */ static sm_ret_T sm_seq_add(sm_map_P map, sm_map_key_P key, sm_map_data_P data, uint flags) { sm_ret_T ret; sm_mapc_P mapc; sm_seqmap_P db; SM_IS_MAP(map); SM_REQUIRE(key != NULL); SM_REQUIRE(data != NULL); mapc = map->sm_map_class; SM_IS_MAPC(mapc); ret = SM_SUCCESS; db = (sm_seqmap_P) map->sm_map_db; if (NULL == db) return sm_error_perm(SM_EM_MAP, ENOENT); /* XXX */ /* XXX add to which map? one? first writable? all? */ return ret; } /* ** SM_SEQ_RM -- remove key/data from SEQ ** Not correctly implemented. ** ** Parameters: ** map -- map context ** key -- key ** ** Returns: ** usual sm_error code */ static sm_ret_T sm_seq_rm(sm_map_P map, sm_map_key_P key) { sm_ret_T ret; sm_mapc_P mapc; sm_seqmap_P db; SM_IS_MAP(map); SM_REQUIRE(key != NULL); mapc = map->sm_map_class; SM_IS_MAPC(mapc); ret = SM_SUCCESS; db = (sm_seqmap_P) map->sm_map_db; if (NULL == db) return sm_error_perm(SM_EM_MAP, ENOENT); /* XXX */ /* XXX add to which map? one? first writable? all? */ return ret; } #endif /* 0 */ /* ** SM_SEQ_CLASS_CREATE -- create SEQ map class ** ** Parameters: ** maps -- map system context ** ** Returns: ** usual sm_error code */ sm_ret_T sm_seq_class_create(sm_maps_P maps) { sm_ret_T ret; sm_mapc_P mapc; sm_cstr_P type; #define SEQ_MAP "sequence" ret = SM_SUCCESS; mapc = NULL; type = sm_cstr_scpyn0((const uchar *)SEQ_MAP, strlen(SEQ_MAP)); if (NULL == type) goto error; ret = sm_mapc_create(maps, type, /* locking flags??? */ SMMAPC_FL_ALLOC_K|SMMAPC_FL_ALLOC_D| SMMAPC_FL_FREE_K| SMMAPC_FL_FREE_D| SMMAPC_FL_GEN_REOPEN, sm_seq_create, sm_seq_open, sm_seq_close, NULL, sm_seq_destroy, NULL /*sm_seq_add*/, NULL /*sm_seq_rm*/, sm_seq_alloc, sm_seq_free, sm_seq_lookup, sm_seq_locate, sm_seq_first, sm_seq_next, sm_seq_setopt, sm_seq_getopt, &mapc); SM_CSTR_FREE(type); return ret; error: if (SM_SUCCESS == ret) ret = sm_error_temp(SM_EM_MAP, ENOMEM); /* cleanup mapc? */ return ret; }