1/*
2   Unix SMB/CIFS implementation.
3   SMB wrapper directory functions
4   Copyright (C) Tim Potter 2000
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2 of the License, or
9   (at your option) any later version.
10
11   This program is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15
16   You should have received a copy of the GNU General Public License
17   along with this program; if not, write to the Free Software
18   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19*/
20
21#include "includes.h"
22
23/* We cache lists of workgroups, lists of servers in workgroups, and lists
24   of shares exported by servers. */
25
26#define CACHE_TIMEOUT 30
27
28struct name_list {
29	struct name_list *prev, *next;
30	char *name;
31	uint32 stype;
32	char *comment;
33};
34
35struct cached_names {
36	struct cached_names *prev, *next;
37	char *key;
38	struct name_list *name_list;
39	time_t cache_timeout;
40	int result;
41};
42
43static struct cached_names *cached_names = NULL;
44
45/* Find a list of cached name for a workgroup, server or share list */
46
47static struct cached_names *find_cached_names(char *key)
48{
49	struct cached_names *tmp;
50
51	for (tmp = cached_names; tmp; tmp = tmp->next) {
52		if (strequal(tmp->key, key)) {
53			return tmp;
54		}
55	}
56
57	return NULL;
58}
59
60/* Add a name to a list stored in the state variable */
61
62static void add_cached_names(const char *name, uint32 stype,
63			     const char *comment, void *state)
64{
65	struct name_list **name_list = (struct name_list **)state;
66	struct name_list *new_name;
67
68	new_name = SMB_MALLOC_P(struct name_list);
69	if (!new_name) return;
70
71	ZERO_STRUCTP(new_name);
72
73	new_name->name = SMB_STRDUP(name);
74	new_name->stype = stype;
75	new_name->comment = SMB_STRDUP(comment);
76
77	DLIST_ADD(*name_list, new_name);
78}
79
80static void free_name_list(struct name_list *name_list)
81{
82	struct name_list *tmp = name_list;
83
84	while(tmp) {
85		struct name_list *next;
86
87		next = tmp->next;
88
89		SAFE_FREE(tmp->name);
90		SAFE_FREE(tmp->comment);
91		SAFE_FREE(tmp);
92
93		tmp = next;
94	}
95}
96
97/* Wrapper for NetServerEnum function */
98
99BOOL smbw_NetServerEnum(struct cli_state *cli, char *workgroup, uint32 stype,
100			void (*fn)(const char *, uint32, const char *, void *),
101			void *state)
102{
103	struct cached_names *names;
104	struct name_list *tmp;
105	time_t now = time(NULL);
106	char key[PATH_MAX];
107	BOOL result = True;
108
109	slprintf(key, PATH_MAX - 1, "%s/%s#%s", cli->desthost,
110		 workgroup, (stype == SV_TYPE_DOMAIN_ENUM ? "DOM" : "SRV"));
111
112	names = find_cached_names(key);
113
114	if (names == NULL || (now - names->cache_timeout) > CACHE_TIMEOUT) {
115		struct cached_names *new_names = NULL;
116
117		/* No names cached for this workgroup */
118
119		if (names == NULL) {
120			new_names = SMB_MALLOC_P(struct cached_names);
121
122			ZERO_STRUCTP(new_names);
123			DLIST_ADD(cached_names, new_names);
124
125		} else {
126
127			/* Dispose of out of date name list */
128
129			free_name_list(names->name_list);
130			names->name_list = NULL;
131
132			new_names = names;
133		}
134
135		result = cli_NetServerEnum(cli, workgroup, stype,
136					   add_cached_names,
137					   &new_names->name_list);
138
139		new_names->cache_timeout = now;
140		new_names->result = result;
141		new_names->key = SMB_STRDUP(key);
142
143		names = new_names;
144	}
145
146	/* Return names by running callback function. */
147
148	for (tmp = names->name_list; tmp; tmp = tmp->next)
149		fn(tmp->name, stype, tmp->comment, state);
150
151	return names->result;
152}
153
154/* Wrapper for RNetShareEnum function */
155
156int smbw_RNetShareEnum(struct cli_state *cli,
157		       void (*fn)(const char *, uint32, const char *, void *),
158		       void *state)
159{
160	struct cached_names *names;
161	struct name_list *tmp;
162	time_t now = time(NULL);
163	char key[PATH_MAX];
164
165	slprintf(key, PATH_MAX - 1, "SHARE/%s", cli->desthost);
166
167	names = find_cached_names(key);
168
169	if (names == NULL || (now - names->cache_timeout) > CACHE_TIMEOUT) {
170		struct cached_names *new_names = NULL;
171
172		/* No names cached for this server */
173
174		if (names == NULL) {
175			new_names = SMB_MALLOC_P(struct cached_names);
176
177			ZERO_STRUCTP(new_names);
178			DLIST_ADD(cached_names, new_names);
179
180		} else {
181
182			/* Dispose of out of date name list */
183
184			free_name_list(names->name_list);
185			names->name_list = NULL;
186
187			new_names = names;
188		}
189
190		new_names->result = cli_RNetShareEnum(cli, add_cached_names,
191						      &new_names->name_list);
192
193		new_names->cache_timeout = now;
194		new_names->key = SMB_STRDUP(key);
195
196		names = new_names;
197	}
198
199	/* Return names by running callback function. */
200
201	for (tmp = names->name_list; tmp; tmp = tmp->next)
202		fn(tmp->name, tmp->stype, tmp->comment, state);
203
204	return names->result;
205}
206