r4088: Get medieval on our ass about malloc.... :-). Take control of all our allocation
[tprouty/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 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
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 SMB_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                 "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         
201 done:
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  
211 static 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  
229 static 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  
368 static 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  
384 static 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  
462 static 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
511 done:   
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  
522 static 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
657 done:
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  
672 static 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  
738 int 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
770 int 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
801 BOOL 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
812 BOOL 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  
821 REGISTRY_OPS printing_ops = {
822         printing_subkey_info,
823         printing_value_info,
824         printing_store_subkey,
825         printing_store_value
826 };
827
828