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