1/*
2 *  Unix SMB/CIFS implementation.
3 *  RPC Pipe client / server routines
4 *  Copyright (C) Gerald Carter                     2002.
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/* Implementation of registry virtual views for printing information */
22
23#include "includes.h"
24
25#undef DBGC_CLASS
26#define DBGC_CLASS DBGC_RPC_SRV
27
28#define MAX_TOP_LEVEL_KEYS	3
29
30/* some symbolic indexes into the top_level_keys */
31
32#define KEY_INDEX_ENVIR		0
33#define KEY_INDEX_FORMS		1
34#define KEY_INDEX_PRINTER	2
35
36static const char *top_level_keys[MAX_TOP_LEVEL_KEYS] = {
37	"Environments",
38	"Forms",
39	"Printers"
40};
41
42
43/**********************************************************************
44 It is safe to assume that every registry path passed into on of
45 the exported functions here begins with KEY_PRINTING else
46 these functions would have never been called.  This is a small utility
47 function to strip the beginning of the path and make a copy that the
48 caller can modify.  Note that the caller is responsible for releasing
49 the memory allocated here.
50 **********************************************************************/
51
52static char* trim_reg_path( char *path )
53{
54	char *p;
55	uint16 key_len = strlen(KEY_PRINTING);
56
57	/*
58	 * sanity check...this really should never be True.
59	 * It is only here to prevent us from accessing outside
60	 * the path buffer in the extreme case.
61	 */
62
63	if ( strlen(path) < key_len ) {
64		DEBUG(0,("trim_reg_path: Registry path too short! [%s]\n", path));
65		DEBUG(0,("trim_reg_path: KEY_PRINTING => [%s]!\n", KEY_PRINTING));
66		return NULL;
67	}
68
69
70	p = path + strlen( KEY_PRINTING );
71
72	if ( *p == '\\' )
73		p++;
74
75	if ( *p )
76		return SMB_STRDUP(p);
77	else
78		return NULL;
79}
80
81/**********************************************************************
82 handle enumeration of subkeys below KEY_PRINTING\Environments
83 *********************************************************************/
84
85static int print_subpath_environments( char *key, REGSUBKEY_CTR *subkeys )
86{
87	const char *environments[] = {
88		"Windows 4.0",
89		"Windows NT x86",
90		"Windows NT R4000",
91		"Windows NT Alpha_AXP",
92		"Windows NT PowerPC",
93		"Windows IA64",
94		"Windows x64",
95		NULL };
96	fstring *drivers = NULL;
97	int i, env_index, num_drivers;
98	BOOL valid_env = False;
99	char *base, *new_path;
100	char *keystr;
101	char *key2 = NULL;
102	int num_subkeys = -1;
103
104	DEBUG(10,("print_subpath_environments: key=>[%s]\n", key ? key : "NULL" ));
105
106	/* listed architectures of installed drivers */
107
108	if ( !key )
109	{
110		/* Windows 9x drivers */
111
112		if ( get_ntdrivers( &drivers, environments[0], 0 ) )
113			regsubkey_ctr_addkey( subkeys, 	environments[0] );
114		SAFE_FREE( drivers );
115
116		/* Windows NT/2k intel drivers */
117
118		if ( get_ntdrivers( &drivers, environments[1], 2 )
119			|| get_ntdrivers( &drivers, environments[1], 3 ) )
120		{
121			regsubkey_ctr_addkey( subkeys, 	environments[1] );
122		}
123		SAFE_FREE( drivers );
124
125		/* Windows NT 4.0; non-intel drivers */
126		for ( i=2; environments[i]; i++ ) {
127			if ( get_ntdrivers( &drivers, environments[i], 2 ) )
128				regsubkey_ctr_addkey( subkeys, 	environments[i] );
129
130		}
131		SAFE_FREE( drivers );
132
133		num_subkeys = regsubkey_ctr_numkeys( subkeys );
134		goto done;
135	}
136
137	/* we are dealing with a subkey of "Environments */
138
139	key2 = SMB_STRDUP( key );
140	keystr = key2;
141	reg_split_path( keystr, &base, &new_path );
142
143	/* sanity check */
144
145	for ( env_index=0; environments[env_index]; env_index++ ) {
146		if ( StrCaseCmp( environments[env_index], base ) == 0 ) {
147			valid_env = True;
148			break;
149		}
150	}
151
152	if ( !valid_env )
153		return -1;
154
155	/* enumerate driver versions; environment is environments[env_index] */
156
157	if ( !new_path ) {
158		switch ( env_index ) {
159			case 0:	/* Win9x */
160				if ( get_ntdrivers( &drivers, environments[0], 0 ) ) {
161					regsubkey_ctr_addkey( subkeys, "0" );
162					SAFE_FREE( drivers );
163				}
164				break;
165			case 1: /* Windows NT/2k - intel */
166				if ( get_ntdrivers( &drivers, environments[1], 2 ) ) {
167					regsubkey_ctr_addkey( subkeys, "2" );
168					SAFE_FREE( drivers );
169				}
170				if ( get_ntdrivers( &drivers, environments[1], 3 ) ) {
171					regsubkey_ctr_addkey( subkeys, "3" );
172					SAFE_FREE( drivers );
173				}
174				break;
175			default: /* Windows NT - nonintel */
176				if ( get_ntdrivers( &drivers, environments[env_index], 2 ) ) {
177					regsubkey_ctr_addkey( subkeys, "2" );
178					SAFE_FREE( drivers );
179				}
180
181		}
182
183		num_subkeys = regsubkey_ctr_numkeys( subkeys );
184		goto done;
185	}
186
187	/* we finally get to enumerate the drivers */
188
189	keystr = new_path;
190	reg_split_path( keystr, &base, &new_path );
191
192	if ( !new_path ) {
193		num_drivers = get_ntdrivers( &drivers, environments[env_index], atoi(base) );
194		for ( i=0; i<num_drivers; i++ )
195			regsubkey_ctr_addkey( subkeys, drivers[i] );
196
197		num_subkeys = regsubkey_ctr_numkeys( subkeys );
198		goto done;
199	}
200
201done:
202	SAFE_FREE( key2 );
203
204	return num_subkeys;
205}
206
207/***********************************************************************
208 simple function to prune a pathname down to the basename of a file
209 **********************************************************************/
210
211static char* dos_basename ( char *path )
212{
213	char *p;
214
215	p = strrchr( path, '\\' );
216	if ( p )
217		p++;
218	else
219		p = path;
220
221	return p;
222}
223
224/**********************************************************************
225 handle enumeration of values below
226 KEY_PRINTING\Environments\<arch>\<version>\<drivername>
227 *********************************************************************/
228
229static int print_subpath_values_environments( char *key, REGVAL_CTR *val )
230{
231	char 		*keystr;
232	char		*key2 = NULL;
233	char 		*base, *new_path;
234	fstring		env;
235	fstring		driver;
236	int		version;
237	NT_PRINTER_DRIVER_INFO_LEVEL	driver_ctr;
238	NT_PRINTER_DRIVER_INFO_LEVEL_3	*info3;
239	WERROR		w_result;
240	char 		*buffer = NULL;
241	char		*buffer2 = NULL;
242	int		buffer_size = 0;
243	int 		i, length;
244	char 		*filename;
245	UNISTR2		data;;
246
247	DEBUG(8,("print_subpath_values_environments: Enter key => [%s]\n", key ? key : "NULL"));
248
249	if ( !key )
250		return 0;
251
252	/*
253	 * The only key below KEY_PRINTING\Environments that
254	 * posseses values is each specific printer driver
255	 * First get the arch, version, & driver name
256	 */
257
258	/* env */
259
260	key2 = SMB_STRDUP( key );
261	keystr = key2;
262	reg_split_path( keystr, &base, &new_path );
263	if ( !base || !new_path )
264		return 0;
265	fstrcpy( env, base );
266
267	/* version */
268
269	keystr = new_path;
270	reg_split_path( keystr, &base, &new_path );
271	if ( !base || !new_path )
272		return 0;
273	version = atoi( base );
274
275	/* printer driver name */
276
277	keystr = new_path;
278	reg_split_path( keystr, &base, &new_path );
279	/* new_path should be NULL here since this must be the last key */
280	if ( !base || new_path )
281		return 0;
282	fstrcpy( driver, base );
283
284	w_result = get_a_printer_driver( &driver_ctr, 3, driver, env, version );
285
286	if ( !W_ERROR_IS_OK(w_result) )
287		return -1;
288
289	/* build the values out of the driver information */
290	info3 = driver_ctr.info_3;
291
292	filename = dos_basename( info3->driverpath );
293	init_unistr2( &data, filename, UNI_STR_TERMINATE);
294	regval_ctr_addvalue( val, "Driver",             REG_SZ,       (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
295
296	filename = dos_basename( info3->configfile );
297	init_unistr2( &data, filename, UNI_STR_TERMINATE);
298	regval_ctr_addvalue( val, "Configuration File", REG_SZ,       (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
299
300	filename = dos_basename( info3->datafile );
301	init_unistr2( &data, filename, UNI_STR_TERMINATE);
302	regval_ctr_addvalue( val, "Data File",          REG_SZ,       (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
303
304	filename = dos_basename( info3->helpfile );
305	init_unistr2( &data, filename, UNI_STR_TERMINATE);
306	regval_ctr_addvalue( val, "Help File",          REG_SZ,       (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
307
308	init_unistr2( &data, info3->defaultdatatype, UNI_STR_TERMINATE);
309	regval_ctr_addvalue( val, "Data Type",          REG_SZ,       (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
310
311	regval_ctr_addvalue( val, "Version",            REG_DWORD,    (char*)&info3->cversion, sizeof(info3->cversion) );
312
313	if ( info3->dependentfiles ) {
314		/* place the list of dependent files in a single
315		   character buffer, separating each file name by
316		   a NULL */
317
318		for ( i=0; strcmp(info3->dependentfiles[i], ""); i++ ) {
319			/* strip the path to only the file's base name */
320
321			filename = dos_basename( info3->dependentfiles[i] );
322
323			length = strlen(filename);
324
325			buffer2 = SMB_REALLOC( buffer, buffer_size + (length + 1)*sizeof(uint16) );
326			if ( !buffer2 )
327				break;
328			buffer = buffer2;
329
330			init_unistr2( &data, filename, UNI_STR_TERMINATE);
331			memcpy( buffer+buffer_size, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
332
333			buffer_size += (length + 1)*sizeof(uint16);
334		}
335
336		/* terminated by double NULL.  Add the final one here */
337
338		buffer2 = SMB_REALLOC( buffer, buffer_size + 2 );
339		if ( !buffer2 ) {
340			SAFE_FREE( buffer );
341			buffer_size = 0;
342		} else {
343			buffer = buffer2;
344			buffer[buffer_size++] = '\0';
345			buffer[buffer_size++] = '\0';
346		}
347	}
348
349	regval_ctr_addvalue( val, "Dependent Files",    REG_MULTI_SZ, buffer, buffer_size );
350
351	free_a_printer_driver( driver_ctr, 3 );
352
353	SAFE_FREE( key2 );
354	SAFE_FREE( buffer );
355
356	DEBUG(8,("print_subpath_values_environments: Exit\n"));
357
358	return regval_ctr_numvals( val );
359}
360
361
362/**********************************************************************
363 handle enumeration of subkeys below KEY_PRINTING\Forms
364 Really just a stub function, but left here in case it needs to
365 be expanded later on
366 *********************************************************************/
367
368static int print_subpath_forms( char *key, REGSUBKEY_CTR *subkeys )
369{
370	DEBUG(10,("print_subpath_forms: key=>[%s]\n", key ? key : "NULL" ));
371
372	/* there are no subkeys */
373
374	if ( key )
375		return -1;
376
377	return 0;
378}
379
380/**********************************************************************
381 handle enumeration of values below KEY_PRINTING\Forms
382 *********************************************************************/
383
384static int print_subpath_values_forms( char *key, REGVAL_CTR *val )
385{
386	int 		num_values = 0;
387	uint32 		data[8];
388	int		form_index = 1;
389
390	DEBUG(10,("print_values_forms: key=>[%s]\n", key ? key : "NULL" ));
391
392	/* handle ..\Forms\ */
393
394	if ( !key )
395	{
396		nt_forms_struct *forms_list = NULL;
397		nt_forms_struct *form = NULL;
398		int i;
399
400		if ( (num_values = get_ntforms( &forms_list )) == 0 )
401			return 0;
402
403		DEBUG(10,("print_subpath_values_forms: [%d] user defined forms returned\n",
404			num_values));
405
406		/* handle user defined forms */
407
408		for ( i=0; i<num_values; i++ )
409		{
410			form = &forms_list[i];
411
412			data[0] = form->width;
413			data[1] = form->length;
414			data[2] = form->left;
415			data[3] = form->top;
416			data[4] = form->right;
417			data[5] = form->bottom;
418			data[6] = form_index++;
419			data[7] = form->flag;
420
421			regval_ctr_addvalue( val, form->name, REG_BINARY, (char*)data, sizeof(data) );
422
423		}
424
425		SAFE_FREE( forms_list );
426		forms_list = NULL;
427
428		/* handle built-on forms */
429
430		if ( (num_values = get_builtin_ntforms( &forms_list )) == 0 )
431			return 0;
432
433		DEBUG(10,("print_subpath_values_forms: [%d] built-in forms returned\n",
434			num_values));
435
436		for ( i=0; i<num_values; i++ )
437		{
438			form = &forms_list[i];
439
440			data[0] = form->width;
441			data[1] = form->length;
442			data[2] = form->left;
443			data[3] = form->top;
444			data[4] = form->right;
445			data[5] = form->bottom;
446			data[6] = form_index++;
447			data[7] = form->flag;
448
449			regval_ctr_addvalue( val, form->name, REG_BINARY, (char*)data, sizeof(data) );
450		}
451
452		SAFE_FREE( forms_list );
453	}
454
455	return num_values;
456}
457
458/**********************************************************************
459 handle enumeration of subkeys below KEY_PRINTING\Printers
460 *********************************************************************/
461
462static int print_subpath_printers( char *key, REGSUBKEY_CTR *subkeys )
463{
464	int n_services = lp_numservices();
465	int snum;
466	fstring sname;
467	int i;
468	int num_subkeys = 0;
469	char *keystr, *key2 = NULL;
470	char *base, *new_path;
471	NT_PRINTER_INFO_LEVEL *printer = NULL;
472	fstring *subkey_names = NULL;
473
474	DEBUG(10,("print_subpath_printers: key=>[%s]\n", key ? key : "NULL" ));
475
476	if ( !key )
477	{
478		/* enumerate all printers */
479
480		for (snum=0; snum<n_services; snum++) {
481			if ( !(lp_snum_ok(snum) && lp_print_ok(snum) ) )
482				continue;
483
484			fstrcpy( sname, lp_servicename(snum) );
485
486			regsubkey_ctr_addkey( subkeys, sname );
487		}
488
489		num_subkeys = regsubkey_ctr_numkeys( subkeys );
490		goto done;
491	}
492
493	/* get information for a specific printer */
494
495	key2 = SMB_STRDUP( key );
496	keystr = key2;
497	reg_split_path( keystr, &base, &new_path );
498
499		if ( !W_ERROR_IS_OK( get_a_printer(NULL, &printer, 2, base) ) )
500		goto done;
501
502	num_subkeys = get_printer_subkeys( &printer->info_2->data, new_path?new_path:"", &subkey_names );
503
504	for ( i=0; i<num_subkeys; i++ )
505		regsubkey_ctr_addkey( subkeys, subkey_names[i] );
506
507	free_a_printer( &printer, 2 );
508
509	/* no other subkeys below here */
510
511done:
512	SAFE_FREE( key2 );
513	SAFE_FREE( subkey_names );
514
515	return num_subkeys;
516}
517
518/**********************************************************************
519 handle enumeration of values below KEY_PRINTING\Printers
520 *********************************************************************/
521
522static int print_subpath_values_printers( char *key, REGVAL_CTR *val )
523{
524	int 		num_values = 0;
525	char		*keystr, *key2 = NULL;
526	char		*base, *new_path;
527	NT_PRINTER_INFO_LEVEL 	*printer = NULL;
528	NT_PRINTER_INFO_LEVEL_2 *info2;
529	DEVICEMODE	*devmode;
530	prs_struct	prs;
531	uint32		offset;
532	int		snum;
533	fstring		printername;
534	NT_PRINTER_DATA	*p_data;
535	int		i, key_index;
536	UNISTR2		data;
537
538	/*
539	 * Theres are tw cases to deal with here
540	 * (1) enumeration of printer_info_2 values
541	 * (2) enumeration of the PrinterDriverData subney
542	 */
543
544	if ( !key ) {
545		/* top level key has no values */
546		goto done;
547	}
548
549	key2 = SMB_STRDUP( key );
550	keystr = key2;
551	reg_split_path( keystr, &base, &new_path );
552
553	fstrcpy( printername, base );
554
555	if ( !new_path )
556	{
557		/* we are dealing with the printer itself */
558
559		if ( !W_ERROR_IS_OK( get_a_printer(NULL, &printer, 2, printername) ) )
560			goto done;
561
562		info2 = printer->info_2;
563
564
565		regval_ctr_addvalue( val, "Attributes",       REG_DWORD, (char*)&info2->attributes,       sizeof(info2->attributes) );
566		regval_ctr_addvalue( val, "Priority",         REG_DWORD, (char*)&info2->priority,         sizeof(info2->attributes) );
567		regval_ctr_addvalue( val, "ChangeID",         REG_DWORD, (char*)&info2->changeid,         sizeof(info2->changeid) );
568		regval_ctr_addvalue( val, "Default Priority", REG_DWORD, (char*)&info2->default_priority, sizeof(info2->default_priority) );
569		regval_ctr_addvalue( val, "Status",           REG_DWORD, (char*)&info2->status,           sizeof(info2->status) );
570		regval_ctr_addvalue( val, "StartTime",        REG_DWORD, (char*)&info2->starttime,        sizeof(info2->starttime) );
571		regval_ctr_addvalue( val, "UntilTime",        REG_DWORD, (char*)&info2->untiltime,        sizeof(info2->untiltime) );
572		regval_ctr_addvalue( val, "cjobs",            REG_DWORD, (char*)&info2->cjobs,            sizeof(info2->cjobs) );
573		regval_ctr_addvalue( val, "AveragePPM",       REG_DWORD, (char*)&info2->averageppm,       sizeof(info2->averageppm) );
574
575		init_unistr2( &data, info2->printername, UNI_STR_TERMINATE);
576		regval_ctr_addvalue( val, "Name",             REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
577		init_unistr2( &data, info2->location, UNI_STR_TERMINATE);
578		regval_ctr_addvalue( val, "Location",         REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
579		init_unistr2( &data, info2->comment, UNI_STR_TERMINATE);
580		regval_ctr_addvalue( val, "Comment",          REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
581		init_unistr2( &data, info2->parameters, UNI_STR_TERMINATE);
582		regval_ctr_addvalue( val, "Parameters",       REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
583		init_unistr2( &data, info2->portname, UNI_STR_TERMINATE);
584		regval_ctr_addvalue( val, "Port",             REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
585		init_unistr2( &data, info2->servername, UNI_STR_TERMINATE);
586		regval_ctr_addvalue( val, "Server",           REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
587		init_unistr2( &data, info2->sharename, UNI_STR_TERMINATE);
588		regval_ctr_addvalue( val, "Share",            REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
589		init_unistr2( &data, info2->drivername, UNI_STR_TERMINATE);
590		regval_ctr_addvalue( val, "Driver",           REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
591		init_unistr2( &data, info2->sepfile, UNI_STR_TERMINATE);
592		regval_ctr_addvalue( val, "Separator File",   REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
593		init_unistr2( &data, "winprint", UNI_STR_TERMINATE);
594		regval_ctr_addvalue( val, "Print Processor",  REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
595
596
597		/* use a prs_struct for converting the devmode and security
598		   descriptor to REG_BIARY */
599
600		prs_init( &prs, MAX_PDU_FRAG_LEN, regval_ctr_getctx(val), MARSHALL);
601
602		/* stream the device mode */
603
604		snum = lp_servicenumber(info2->sharename);
605		if ( (devmode = construct_dev_mode( snum )) != NULL )
606		{
607			if ( spoolss_io_devmode( "devmode", &prs, 0, devmode ) ) {
608
609				offset = prs_offset( &prs );
610
611				regval_ctr_addvalue( val, "Default Devmode", REG_BINARY, prs_data_p(&prs), offset );
612			}
613
614
615		}
616
617		prs_mem_clear( &prs );
618		prs_set_offset( &prs, 0 );
619
620		if ( info2->secdesc_buf && info2->secdesc_buf->len )
621		{
622			if ( sec_io_desc("sec_desc", &info2->secdesc_buf->sec, &prs, 0 ) ) {
623
624				offset = prs_offset( &prs );
625
626				regval_ctr_addvalue( val, "Security", REG_BINARY, prs_data_p(&prs), offset );
627			}
628		}
629
630		prs_mem_free( &prs );
631
632		num_values = regval_ctr_numvals( val );
633
634		goto done;
635
636	}
637
638	/* now enumerate the key */
639
640	if ( !W_ERROR_IS_OK( get_a_printer(NULL, &printer, 2, printername) ) )
641		goto done;
642
643	/* iterate over all printer data and fill the regval container */
644
645	p_data = &printer->info_2->data;
646	if ( (key_index = lookup_printerkey( p_data, new_path )) == -1  ) {
647		DEBUG(10,("print_subpath_values_printer: Unknown keyname [%s]\n", new_path));
648		goto done;
649	}
650
651	num_values = regval_ctr_numvals( &p_data->keys[key_index].values );
652
653	for ( i=0; i<num_values; i++ )
654		regval_ctr_copyvalue( val, regval_ctr_specific_value(&p_data->keys[key_index].values, i) );
655
656
657done:
658	if ( printer )
659		free_a_printer( &printer, 2 );
660
661	SAFE_FREE( key2 );
662
663	return num_values;
664}
665
666/**********************************************************************
667 Routine to handle enumeration of subkeys and values
668 below KEY_PRINTING (depending on whether or not subkeys/val are
669 valid pointers.
670 *********************************************************************/
671
672static int handle_printing_subpath( char *key, REGSUBKEY_CTR *subkeys, REGVAL_CTR *val )
673{
674	int result = 0;
675	char *p, *base;
676	int i;
677
678	DEBUG(10,("handle_printing_subpath: key=>[%s]\n", key ));
679
680	/*
681	 * break off the first part of the path
682	 * topmost base **must** be one of the strings
683	 * in top_level_keys[]
684	 */
685
686	reg_split_path( key, &base, &p);
687
688	for ( i=0; i<MAX_TOP_LEVEL_KEYS; i++ ) {
689		if ( StrCaseCmp( top_level_keys[i], base ) == 0 )
690			break;
691	}
692
693	DEBUG(10,("handle_printing_subpath: base=>[%s], i==[%d]\n", base, i));
694
695	if ( !(i < MAX_TOP_LEVEL_KEYS) )
696		return -1;
697
698	/* Call routine to handle each top level key */
699	switch ( i )
700	{
701		case KEY_INDEX_ENVIR:
702			if ( subkeys )
703				print_subpath_environments( p, subkeys );
704			if ( val )
705				print_subpath_values_environments( p, val );
706			break;
707
708		case KEY_INDEX_FORMS:
709			if ( subkeys )
710				print_subpath_forms( p, subkeys );
711			if ( val )
712				print_subpath_values_forms( p, val );
713			break;
714
715		case KEY_INDEX_PRINTER:
716			if ( subkeys )
717				print_subpath_printers( p, subkeys );
718			if ( val )
719				print_subpath_values_printers( p, val );
720			break;
721
722		/* default case for top level key that has no handler */
723
724		default:
725			break;
726	}
727
728
729
730	return result;
731
732}
733/**********************************************************************
734 Enumerate registry subkey names given a registry path.
735 Caller is responsible for freeing memory to **subkeys
736 *********************************************************************/
737
738int printing_subkey_info( char *key, REGSUBKEY_CTR *subkey_ctr )
739{
740	char 		*path;
741	BOOL		top_level = False;
742	int		num_subkeys = 0;
743
744	DEBUG(10,("printing_subkey_info: key=>[%s]\n", key));
745
746	path = trim_reg_path( key );
747
748	/* check to see if we are dealing with the top level key */
749
750	if ( !path )
751		top_level = True;
752
753	if ( top_level ) {
754		for ( num_subkeys=0; num_subkeys<MAX_TOP_LEVEL_KEYS; num_subkeys++ )
755			regsubkey_ctr_addkey( subkey_ctr, top_level_keys[num_subkeys] );
756	}
757	else
758		num_subkeys = handle_printing_subpath( path, subkey_ctr, NULL );
759
760	SAFE_FREE( path );
761
762	return num_subkeys;
763}
764
765/**********************************************************************
766 Enumerate registry values given a registry path.
767 Caller is responsible for freeing memory
768 *********************************************************************/
769
770int printing_value_info( char *key, REGVAL_CTR *val )
771{
772	char 		*path;
773	BOOL		top_level = False;
774	int		num_values = 0;
775
776	DEBUG(10,("printing_value_info: key=>[%s]\n", key));
777
778	path = trim_reg_path( key );
779
780	/* check to see if we are dealing with the top level key */
781
782	if ( !path )
783		top_level = True;
784
785	/* fill in values from the getprinterdata_printer_server() */
786	if ( top_level )
787		num_values = 0;
788	else
789		num_values = handle_printing_subpath( path, NULL, val );
790
791
792	return num_values;
793}
794
795/**********************************************************************
796 Stub function which always returns failure since we don't want
797 people storing printing information directly via regostry calls
798 (for now at least)
799 *********************************************************************/
800
801BOOL printing_store_subkey( char *key, REGSUBKEY_CTR *subkeys )
802{
803	return False;
804}
805
806/**********************************************************************
807 Stub function which always returns failure since we don't want
808 people storing printing information directly via regostry calls
809 (for now at least)
810 *********************************************************************/
811
812BOOL printing_store_value( char *key, REGVAL_CTR *val )
813{
814	return False;
815}
816
817/*
818 * Table of function pointers for accessing printing data
819 */
820
821REGISTRY_OPS printing_ops = {
822	printing_subkey_info,
823	printing_value_info,
824	printing_store_subkey,
825	printing_store_value
826};
827
828
829