1/*++
2/* NAME
3/*	dict_debug 3
4/* SUMMARY
5/*	dictionary manager, logging proxy
6/* SYNOPSIS
7/*	#include <dict.h>
8/*
9/*	DICT	*dict_debug(dict_handle)
10/*	DICT	*dict_handle;
11/*
12/*	DICT	*DICT_DEBUG(dict_handle)
13/*	DICT	*dict_handle;
14/* DESCRIPTION
15/*	dict_debug() encapsulates the given dictionary object and returns
16/*	a proxy object that logs all access to the encapsulated object.
17/*	This is more convenient than having to add logging capability
18/*	to each individual dictionary access method.
19/*
20/*	DICT_DEBUG() is an unsafe macro that returns the original object if
21/*	the object's debugging flag is not set, and that otherwise encapsulates
22/*	the object with dict_debug(). This macro simplifies usage by avoiding
23/*	clumsy expressions. The macro evaluates its argument multiple times.
24/* DIAGNOSTICS
25/*	Fatal errors: out of memory.
26/* LICENSE
27/* .ad
28/* .fi
29/*	The Secure Mailer license must be distributed with this software.
30/* AUTHOR(S)
31/*	Wietse Venema
32/*	IBM T.J. Watson Research
33/*	P.O. Box 704
34/*	Yorktown Heights, NY 10598, USA
35/*--*/
36
37/* System libraries. */
38
39#include <sys_defs.h>
40
41/* Utility library. */
42
43#include <msg.h>
44#include <mymalloc.h>
45#include <dict.h>
46
47/* Application-specific. */
48
49typedef struct {
50    DICT    dict;			/* the proxy service */
51    DICT   *real_dict;			/* encapsulated object */
52} DICT_DEBUG;
53
54/* dict_debug_lookup - log lookup operation */
55
56static const char *dict_debug_lookup(DICT *dict, const char *key)
57{
58    DICT_DEBUG *dict_debug = (DICT_DEBUG *) dict;
59    DICT   *real_dict = dict_debug->real_dict;
60    const char *result;
61
62    result = dict_get(real_dict, key);
63    msg_info("%s:%s lookup: \"%s\" = \"%s\"", dict->type, dict->name, key,
64	     result ? result : real_dict->error ? "error" : "not_found");
65    DICT_ERR_VAL_RETURN(dict, real_dict->error, result);
66}
67
68/* dict_debug_update - log update operation */
69
70static int dict_debug_update(DICT *dict, const char *key, const char *value)
71{
72    DICT_DEBUG *dict_debug = (DICT_DEBUG *) dict;
73    DICT   *real_dict = dict_debug->real_dict;
74    int     result;
75
76    result = dict_put(real_dict, key, value);
77    msg_info("%s:%s update: \"%s\" = \"%s\": %s", dict->type, dict->name,
78	     key, value, result == 0 ? "success" : real_dict->error ?
79	     "error" : "failed");
80    DICT_ERR_VAL_RETURN(dict, real_dict->error, result);
81}
82
83/* dict_debug_delete - log delete operation */
84
85static int dict_debug_delete(DICT *dict, const char *key)
86{
87    DICT_DEBUG *dict_debug = (DICT_DEBUG *) dict;
88    DICT   *real_dict = dict_debug->real_dict;
89    int     result;
90
91    result = dict_del(real_dict, key);
92    msg_info("%s:%s delete: \"%s\": %s", dict->type, dict->name, key,
93	     result == 0 ? "success" : real_dict->error ?
94	     "error" : "failed");
95    DICT_ERR_VAL_RETURN(dict, real_dict->error, result);
96}
97
98/* dict_debug_sequence - log sequence operation */
99
100static int dict_debug_sequence(DICT *dict, int function,
101			               const char **key, const char **value)
102{
103    DICT_DEBUG *dict_debug = (DICT_DEBUG *) dict;
104    DICT   *real_dict = dict_debug->real_dict;
105    int     result;
106
107    result = dict_seq(real_dict, function, key, value);
108    if (result == 0)
109	msg_info("%s:%s sequence: \"%s\" = \"%s\"", dict->type, dict->name,
110		 *key, *value);
111    else
112	msg_info("%s:%s sequence: found EOF", dict->type, dict->name);
113    DICT_ERR_VAL_RETURN(dict, real_dict->error, result);
114}
115
116/* dict_debug_close - log operation */
117
118static void dict_debug_close(DICT *dict)
119{
120    DICT_DEBUG *dict_debug = (DICT_DEBUG *) dict;
121
122    dict_close(dict_debug->real_dict);
123    dict_free(dict);
124}
125
126/* dict_debug - encapsulate dictionary object and install proxies */
127
128DICT   *dict_debug(DICT *real_dict)
129{
130    DICT_DEBUG *dict_debug;
131
132    dict_debug = (DICT_DEBUG *) dict_alloc(real_dict->type,
133				      real_dict->name, sizeof(*dict_debug));
134    dict_debug->dict.flags = real_dict->flags;	/* XXX not synchronized */
135    dict_debug->dict.lookup = dict_debug_lookup;
136    dict_debug->dict.update = dict_debug_update;
137    dict_debug->dict.delete = dict_debug_delete;
138    dict_debug->dict.sequence = dict_debug_sequence;
139    dict_debug->dict.close = dict_debug_close;
140    dict_debug->real_dict = real_dict;
141    return (&dict_debug->dict);
142}
143