Merge from HEAD - make Samba compile with -Wwrite-strings without additional
[nivanova/samba-autobuild/.git] / source3 / 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         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                 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         UNISTR2         data;;
244         
245         DEBUG(8,("print_subpath_values_environments: Enter key => [%s]\n", key ? key : "NULL"));
246         
247         if ( !key )
248                 return 0;
249                 
250         /* 
251          * The only key below KEY_PRINTING\Environments that 
252          * posseses values is each specific printer driver 
253          * First get the arch, version, & driver name
254          */
255         
256         /* env */
257         
258         key2 = strdup( key );
259         keystr = key2;
260         reg_split_path( keystr, &base, &new_path );
261         if ( !base || !new_path )
262                 return 0;
263         fstrcpy( env, base );
264         
265         /* version */
266         
267         keystr = new_path;
268         reg_split_path( keystr, &base, &new_path );
269         if ( !base || !new_path )
270                 return 0;
271         version = atoi( base );
272
273         /* printer driver name */
274         
275         keystr = new_path;
276         reg_split_path( keystr, &base, &new_path );
277         /* new_path should be NULL here since this must be the last key */
278         if ( !base || new_path )
279                 return 0;
280         fstrcpy( driver, base );
281
282         w_result = get_a_printer_driver( &driver_ctr, 3, driver, env, version );
283
284         if ( !W_ERROR_IS_OK(w_result) )
285                 return -1;
286                 
287         /* build the values out of the driver information */
288         info3 = driver_ctr.info_3;
289         
290         filename = dos_basename( info3->driverpath );
291         init_unistr2( &data, filename, strlen(filename)+1 ); 
292         regval_ctr_addvalue( val, "Driver",             REG_SZ,       (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
293         
294         filename = dos_basename( info3->configfile );
295         init_unistr2( &data, filename, strlen(filename)+1 );
296         regval_ctr_addvalue( val, "Configuration File", REG_SZ,       (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
297         
298         filename = dos_basename( info3->datafile );
299         init_unistr2( &data, filename, strlen(filename)+1 );
300         regval_ctr_addvalue( val, "Data File",          REG_SZ,       (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
301         
302         filename = dos_basename( info3->helpfile );
303         init_unistr2( &data, filename, strlen(filename)+1 );
304         regval_ctr_addvalue( val, "Help File",          REG_SZ,       (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
305         
306         init_unistr2( &data, info3->defaultdatatype, strlen(info3->defaultdatatype)+1 );
307         regval_ctr_addvalue( val, "Data Type",          REG_SZ,       (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
308         
309         regval_ctr_addvalue( val, "Version",            REG_DWORD,    (char*)&info3->cversion, sizeof(info3->cversion) );
310         
311         if ( info3->dependentfiles )
312         {
313                 /* place the list of dependent files in a single 
314                    character buffer, separating each file name by
315                    a NULL */
316                    
317                 for ( i=0; strcmp(info3->dependentfiles[i], ""); i++ )
318                 {
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 = Realloc( buffer, buffer_size + (length + 1)*sizeof(uint16) );
326                         if ( !buffer2 )
327                                 break;
328                         buffer = buffer2;
329                         
330                         init_unistr2( &data, filename, length+1 );
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 = Realloc( buffer, buffer_size + 2 );
339                 if ( !buffer2 ) {
340                         SAFE_FREE( buffer );
341                         buffer_size = 0;
342                 }
343                 else {
344                         buffer = buffer2;
345                         buffer[buffer_size++] = '\0';
346                         buffer[buffer_size++] = '\0';
347                 }
348         }
349         
350         regval_ctr_addvalue( val, "Dependent Files",    REG_MULTI_SZ, buffer, buffer_size );
351         
352         free_a_printer_driver( driver_ctr, 3 );
353         
354         SAFE_FREE( key2 );
355         SAFE_FREE( buffer );
356                 
357         DEBUG(8,("print_subpath_values_environments: Exit\n"));
358         
359         return regval_ctr_numvals( val );
360 }
361
362
363 /**********************************************************************
364  handle enumeration of subkeys below KEY_PRINTING\Forms
365  Really just a stub function, but left here in case it needs to
366  be expanded later on
367  *********************************************************************/
368  
369 static int print_subpath_forms( char *key, REGSUBKEY_CTR *subkeys )
370 {
371         DEBUG(10,("print_subpath_forms: key=>[%s]\n", key ? key : "NULL" ));
372         
373         /* there are no subkeys */
374         
375         if ( key )
376                 return -1;
377         
378         return 0;
379 }
380
381 /**********************************************************************
382  handle enumeration of values below KEY_PRINTING\Forms
383  *********************************************************************/
384  
385 static int print_subpath_values_forms( char *key, REGVAL_CTR *val )
386 {
387         int             num_values = 0;
388         uint32          data[8];
389         int             form_index = 1;
390         
391         DEBUG(10,("print_values_forms: key=>[%s]\n", key ? key : "NULL" ));
392         
393         /* handle ..\Forms\ */
394         
395         if ( !key )
396         {
397                 nt_forms_struct *forms_list = NULL;
398                 nt_forms_struct *form = NULL;
399                 int i;
400                 
401                 if ( (num_values = get_ntforms( &forms_list )) == 0 ) 
402                         return 0;
403                 
404                 DEBUG(10,("print_subpath_values_forms: [%d] user defined forms returned\n",
405                         num_values));
406
407                 /* handle user defined forms */
408                                 
409                 for ( i=0; i<num_values; i++ )
410                 {
411                         form = &forms_list[i];
412                         
413                         data[0] = form->width;
414                         data[1] = form->length;
415                         data[2] = form->left;
416                         data[3] = form->top;
417                         data[4] = form->right;
418                         data[5] = form->bottom;
419                         data[6] = form_index++;
420                         data[7] = form->flag;
421                         
422                         regval_ctr_addvalue( val, form->name, REG_BINARY, (char*)data, sizeof(data) );
423                 
424                 }
425                 
426                 SAFE_FREE( forms_list );
427                 forms_list = NULL;
428                 
429                 /* handle built-on forms */
430                 
431                 if ( (num_values = get_builtin_ntforms( &forms_list )) == 0 ) 
432                         return 0;
433                 
434                 DEBUG(10,("print_subpath_values_forms: [%d] built-in forms returned\n",
435                         num_values));
436                         
437                 for ( i=0; i<num_values; i++ )
438                 {
439                         form = &forms_list[i];
440                         
441                         data[0] = form->width;
442                         data[1] = form->length;
443                         data[2] = form->left;
444                         data[3] = form->top;
445                         data[4] = form->right;
446                         data[5] = form->bottom;
447                         data[6] = form_index++;
448                         data[7] = form->flag;
449                                         
450                         regval_ctr_addvalue( val, form->name, REG_BINARY, (char*)data, sizeof(data) );
451                 }
452                 
453                 SAFE_FREE( forms_list );
454         }
455         
456         return num_values;
457 }
458
459 /**********************************************************************
460  handle enumeration of subkeys below KEY_PRINTING\Printers
461  *********************************************************************/
462  
463 static int print_subpath_printers( char *key, REGSUBKEY_CTR *subkeys )
464 {
465         int n_services = lp_numservices();      
466         int snum;
467         fstring sname;
468         int i;
469         int num_subkeys = 0;
470         char *keystr, *key2 = NULL;
471         char *base, *new_path;
472         NT_PRINTER_INFO_LEVEL *printer = NULL;
473         fstring *subkey_names = NULL;
474         
475         DEBUG(10,("print_subpath_printers: key=>[%s]\n", key ? key : "NULL" ));
476         
477         if ( !key )
478         {
479                 /* enumerate all printers */
480                 
481                 for (snum=0; snum<n_services; snum++) {
482                         if ( !(lp_snum_ok(snum) && lp_print_ok(snum) ) )
483                                 continue;
484                                 
485                         fstrcpy( sname, lp_servicename(snum) );
486                                 
487                         regsubkey_ctr_addkey( subkeys, sname );
488                 }
489                 
490                 num_subkeys = regsubkey_ctr_numkeys( subkeys );
491                 goto done;
492         }
493
494         /* get information for a specific printer */
495         
496         key2 = strdup( key );
497         keystr = key2;
498         reg_split_path( keystr, &base, &new_path );
499
500         if ( !W_ERROR_IS_OK( get_a_printer(&printer, 2, base) ) )
501                 goto done;
502
503         num_subkeys = get_printer_subkeys( &printer->info_2->data, new_path?new_path:"", &subkey_names );
504         
505         for ( i=0; i<num_subkeys; i++ )
506                 regsubkey_ctr_addkey( subkeys, subkey_names[i] );
507         
508         free_a_printer( &printer, 2 );
509                         
510         /* no other subkeys below here */
511
512 done:   
513         SAFE_FREE( key2 );
514         SAFE_FREE( subkey_names );
515         
516         return num_subkeys;
517 }
518
519 /**********************************************************************
520  handle enumeration of values below KEY_PRINTING\Printers
521  *********************************************************************/
522  
523 static int print_subpath_values_printers( char *key, REGVAL_CTR *val )
524 {
525         int             num_values = 0;
526         char            *keystr, *key2 = NULL;
527         char            *base, *new_path;
528         NT_PRINTER_INFO_LEVEL   *printer = NULL;
529         NT_PRINTER_INFO_LEVEL_2 *info2;
530         DEVICEMODE      *devmode;
531         prs_struct      prs;
532         uint32          offset;
533         int             snum;
534         fstring         printername; 
535         NT_PRINTER_DATA *p_data;
536         int             i, key_index;
537         UNISTR2         data;
538         
539         /* 
540          * Theres are tw cases to deal with here
541          * (1) enumeration of printer_info_2 values
542          * (2) enumeration of the PrinterDriverData subney
543          */
544          
545         if ( !key ) {
546                 /* top level key has no values */
547                 goto done;
548         }
549         
550         key2 = strdup( key );
551         keystr = key2;
552         reg_split_path( keystr, &base, &new_path );
553         
554         fstrcpy( printername, base );
555         
556         if ( !new_path ) 
557         {
558                 /* we are dealing with the printer itself */
559
560                 if ( !W_ERROR_IS_OK( get_a_printer(&printer, 2, printername) ) )
561                         goto done;
562
563                 info2 = printer->info_2;
564                 
565
566                 regval_ctr_addvalue( val, "Attributes",       REG_DWORD, (char*)&info2->attributes,       sizeof(info2->attributes) );
567                 regval_ctr_addvalue( val, "Priority",         REG_DWORD, (char*)&info2->priority,         sizeof(info2->attributes) );
568                 regval_ctr_addvalue( val, "ChangeID",         REG_DWORD, (char*)&info2->changeid,         sizeof(info2->changeid) );
569                 regval_ctr_addvalue( val, "Default Priority", REG_DWORD, (char*)&info2->default_priority, sizeof(info2->default_priority) );
570                 regval_ctr_addvalue( val, "Status",           REG_DWORD, (char*)&info2->status,           sizeof(info2->status) );
571                 regval_ctr_addvalue( val, "StartTime",        REG_DWORD, (char*)&info2->starttime,        sizeof(info2->starttime) );
572                 regval_ctr_addvalue( val, "UntilTime",        REG_DWORD, (char*)&info2->untiltime,        sizeof(info2->untiltime) );
573                 regval_ctr_addvalue( val, "cjobs",            REG_DWORD, (char*)&info2->cjobs,            sizeof(info2->cjobs) );
574                 regval_ctr_addvalue( val, "AveragePPM",       REG_DWORD, (char*)&info2->averageppm,       sizeof(info2->averageppm) );
575
576                 init_unistr2( &data, info2->printername, strlen(info2->printername)+1 );
577                 regval_ctr_addvalue( val, "Name",             REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
578                 init_unistr2( &data, info2->location, strlen(info2->location)+1 );
579                 regval_ctr_addvalue( val, "Location",         REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
580                 init_unistr2( &data, info2->comment, strlen(info2->comment)+1 );
581                 regval_ctr_addvalue( val, "Comment",          REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
582                 init_unistr2( &data, info2->parameters, strlen(info2->parameters)+1 );
583                 regval_ctr_addvalue( val, "Parameters",       REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
584                 init_unistr2( &data, info2->portname, strlen(info2->portname)+1 );
585                 regval_ctr_addvalue( val, "Port",             REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
586                 init_unistr2( &data, info2->servername, strlen(info2->servername)+1 );
587                 regval_ctr_addvalue( val, "Server",           REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
588                 init_unistr2( &data, info2->sharename, strlen(info2->sharename)+1 );
589                 regval_ctr_addvalue( val, "Share",            REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
590                 init_unistr2( &data, info2->drivername, strlen(info2->drivername)+1 );
591                 regval_ctr_addvalue( val, "Driver",           REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
592                 init_unistr2( &data, info2->sepfile, strlen(info2->sepfile)+1 );
593                 regval_ctr_addvalue( val, "Separator File",   REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
594                 init_unistr2( &data, "winprint", strlen("winprint")+1 );
595                 regval_ctr_addvalue( val, "Print Processor",  REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
596                 
597                 
598                 /* use a prs_struct for converting the devmode and security 
599                    descriptor to REG_BIARY */
600                 
601                 prs_init( &prs, MAX_PDU_FRAG_LEN, regval_ctr_getctx(val), MARSHALL);
602
603                 /* stream the device mode */
604                 
605                 snum = lp_servicenumber(info2->sharename);
606                 if ( (devmode = construct_dev_mode( snum )) != NULL )
607                 {                       
608                         if ( spoolss_io_devmode( "devmode", &prs, 0, devmode ) ) {
609                         
610                                 offset = prs_offset( &prs );
611                                 
612                                 regval_ctr_addvalue( val, "Default Devmode", REG_BINARY, prs_data_p(&prs), offset );
613                         }
614                         
615                         
616                 }
617                 
618                 prs_mem_clear( &prs );
619                 prs_set_offset( &prs, 0 );
620                 
621                 if ( info2->secdesc_buf && info2->secdesc_buf->len ) 
622                 {
623                         if ( sec_io_desc("sec_desc", &info2->secdesc_buf->sec, &prs, 0 ) ) {
624                         
625                                 offset = prs_offset( &prs );
626                         
627                                 regval_ctr_addvalue( val, "Security", REG_BINARY, prs_data_p(&prs), offset );
628                         }
629                 }
630
631                                 
632                 prs_mem_free( &prs );
633                 
634                 num_values = regval_ctr_numvals( val ); 
635                 
636                 goto done;
637                 
638         }
639                 
640         /* now enumerate the key */
641         
642         if ( !W_ERROR_IS_OK( get_a_printer(&printer, 2, printername) ) )
643                 goto done;
644         
645         /* iterate over all printer data and fill the regval container */
646         
647         p_data = &printer->info_2->data;
648         if ( (key_index = lookup_printerkey( p_data, new_path )) == -1  ) {
649                 DEBUG(10,("print_subpath_values_printer: Unknown keyname [%s]\n", new_path));
650                 goto done;
651         }
652         
653         num_values = regval_ctr_numvals( &p_data->keys[key_index].values );
654         
655         for ( i=0; i<num_values; i++ )
656                 regval_ctr_copyvalue( val, regval_ctr_specific_value(&p_data->keys[key_index].values, i) );
657                         
658
659 done:
660         if ( printer )
661                 free_a_printer( &printer, 2 );
662                 
663         SAFE_FREE( key2 ); 
664         
665         return num_values;
666 }
667
668 /**********************************************************************
669  Routine to handle enumeration of subkeys and values 
670  below KEY_PRINTING (depending on whether or not subkeys/val are 
671  valid pointers. 
672  *********************************************************************/
673  
674 static int handle_printing_subpath( char *key, REGSUBKEY_CTR *subkeys, REGVAL_CTR *val )
675 {
676         int result = 0;
677         char *p, *base;
678         int i;
679         
680         DEBUG(10,("handle_printing_subpath: key=>[%s]\n", key ));
681         
682         /* 
683          * break off the first part of the path 
684          * topmost base **must** be one of the strings 
685          * in top_level_keys[]
686          */
687         
688         reg_split_path( key, &base, &p);
689                 
690         for ( i=0; i<MAX_TOP_LEVEL_KEYS; i++ ) {
691                 if ( StrCaseCmp( top_level_keys[i], base ) == 0 )
692                         break;
693         }
694         
695         DEBUG(10,("handle_printing_subpath: base=>[%s], i==[%d]\n", base, i));  
696                 
697         if ( !(i < MAX_TOP_LEVEL_KEYS) )
698                 return -1;
699                                                 
700         /* Call routine to handle each top level key */
701         switch ( i )
702         {
703                 case KEY_INDEX_ENVIR:
704                         if ( subkeys )
705                                 print_subpath_environments( p, subkeys );
706                         if ( val )
707                                 print_subpath_values_environments( p, val );
708                         break;
709                 
710                 case KEY_INDEX_FORMS:
711                         if ( subkeys )
712                                 print_subpath_forms( p, subkeys );
713                         if ( val )
714                                 print_subpath_values_forms( p, val );
715                         break;
716                         
717                 case KEY_INDEX_PRINTER:
718                         if ( subkeys )
719                                 print_subpath_printers( p, subkeys );
720                         if ( val )
721                                 print_subpath_values_printers( p, val );
722                         break;
723         
724                 /* default case for top level key that has no handler */
725                 
726                 default:
727                         break;
728         }
729         
730         
731         
732         return result;
733
734 }
735 /**********************************************************************
736  Enumerate registry subkey names given a registry path.  
737  Caller is responsible for freeing memory to **subkeys
738  *********************************************************************/
739  
740 int printing_subkey_info( char *key, REGSUBKEY_CTR *subkey_ctr )
741 {
742         char            *path;
743         BOOL            top_level = False;
744         int             num_subkeys = 0;
745         
746         DEBUG(10,("printing_subkey_info: key=>[%s]\n", key));
747         
748         path = trim_reg_path( key );
749         
750         /* check to see if we are dealing with the top level key */
751         
752         if ( !path )
753                 top_level = True;
754                 
755         if ( top_level ) {
756                 for ( num_subkeys=0; num_subkeys<MAX_TOP_LEVEL_KEYS; num_subkeys++ )
757                         regsubkey_ctr_addkey( subkey_ctr, top_level_keys[num_subkeys] );
758         }
759         else
760                 num_subkeys = handle_printing_subpath( path, subkey_ctr, NULL );
761         
762         SAFE_FREE( path );
763         
764         return num_subkeys;
765 }
766
767 /**********************************************************************
768  Enumerate registry values given a registry path.  
769  Caller is responsible for freeing memory 
770  *********************************************************************/
771
772 int printing_value_info( char *key, REGVAL_CTR *val )
773 {
774         char            *path;
775         BOOL            top_level = False;
776         int             num_values = 0;
777         
778         DEBUG(10,("printing_value_info: key=>[%s]\n", key));
779         
780         path = trim_reg_path( key );
781         
782         /* check to see if we are dealing with the top level key */
783         
784         if ( !path )
785                 top_level = True;
786         
787         /* fill in values from the getprinterdata_printer_server() */
788         if ( top_level )
789                 num_values = 0;
790         else
791                 num_values = handle_printing_subpath( path, NULL, val );
792                 
793         
794         return num_values;
795 }
796
797 /**********************************************************************
798  Stub function which always returns failure since we don't want
799  people storing printing information directly via regostry calls
800  (for now at least)
801  *********************************************************************/
802
803 BOOL printing_store_subkey( char *key, REGSUBKEY_CTR *subkeys )
804 {
805         return False;
806 }
807
808 /**********************************************************************
809  Stub function which always returns failure since we don't want
810  people storing printing information directly via regostry calls
811  (for now at least)
812  *********************************************************************/
813
814 BOOL printing_store_value( char *key, REGVAL_CTR *val )
815 {
816         return False;
817 }
818
819 /* 
820  * Table of function pointers for accessing printing data
821  */
822  
823 REGISTRY_OPS printing_ops = {
824         printing_subkey_info,
825         printing_value_info,
826         printing_store_subkey,
827         printing_store_value
828 };
829
830