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 = (struct name_list *)malloc(sizeof(struct name_list));
69	if (!new_name) return;
70
71	ZERO_STRUCTP(new_name);
72
73	new_name->name = strdup(name);
74	new_name->stype = stype;
75	new_name->comment = 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 = (struct cached_names *)
121				malloc(sizeof(struct cached_names));
122
123			ZERO_STRUCTP(new_names);
124			DLIST_ADD(cached_names, new_names);
125
126		} else {
127
128			/* Dispose of out of date name list */
129
130			free_name_list(names->name_list);
131			names->name_list = NULL;
132
133			new_names = names;
134		}
135
136		result = cli_NetServerEnum(cli, workgroup, stype,
137					   add_cached_names,
138					   &new_names->name_list);
139
140		new_names->cache_timeout = now;
141		new_names->result = result;
142		new_names->key = strdup(key);
143
144		names = new_names;
145	}
146
147	/* Return names by running callback function. */
148
149	for (tmp = names->name_list; tmp; tmp = tmp->next)
150		fn(tmp->name, stype, tmp->comment, state);
151
152	return names->result;
153}
154
155/* Wrapper for RNetShareEnum function */
156
157int smbw_RNetShareEnum(struct cli_state *cli,
158		       void (*fn)(const char *, uint32, const char *, void *),
159		       void *state)
160{
161	struct cached_names *names;
162	struct name_list *tmp;
163	time_t now = time(NULL);
164	char key[PATH_MAX];
165
166	slprintf(key, PATH_MAX - 1, "SHARE/%s", cli->desthost);
167
168	names = find_cached_names(key);
169
170	if (names == NULL || (now - names->cache_timeout) > CACHE_TIMEOUT) {
171		struct cached_names *new_names = NULL;
172
173		/* No names cached for this server */
174
175		if (names == NULL) {
176			new_names = (struct cached_names *)
177				malloc(sizeof(struct cached_names));
178
179			ZERO_STRUCTP(new_names);
180			DLIST_ADD(cached_names, new_names);
181
182		} else {
183
184			/* Dispose of out of date name list */
185
186			free_name_list(names->name_list);
187			names->name_list = NULL;
188
189			new_names = names;
190		}
191
192		new_names->result = cli_RNetShareEnum(cli, add_cached_names,
193						      &new_names->name_list);
194
195		new_names->cache_timeout = now;
196		new_names->key = strdup(key);
197
198		names = new_names;
199	}
200
201	/* Return names by running callback function. */
202
203	for (tmp = names->name_list; tmp; tmp = tmp->next)
204		fn(tmp->name, tmp->stype, tmp->comment, state);
205
206	return names->result;
207}
208