r8027: driver information is now back via winreg
[gd/samba/.git] / source / registry / reg_printing.c
1 /* 
2  *  Unix SMB/CIFS implementation.
3  *  Virtual Windows Registry Layer
4  *  Copyright (C) Gerald Carter                     2002-2005
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 /* registrt paths used in the print_registry[] */
29
30 #define KEY_MONITORS            "HKLM/SYSTEM/CURRENTCONTROLSET/CONTROL/PRINT/MONITORS"
31 #define KEY_FORMS               "HKLM/SYSTEM/CURRENTCONTROLSET/CONTROL/PRINT/FORMS"
32 #define KEY_CONTROL_PRINTERS    "HKLM/SYSTEM/CURRENTCONTROLSET/CONTROL/PRINT/PRINTERS"
33 #define KEY_ENVIRONMENTS        "HKLM/SYSTEM/CURRENTCONTROLSET/CONTROL/PRINT/ENVIRONMENTS"
34 #define KEY_CONTROL_PRINT       "HKLM/SYSTEM/CURRENTCONTROLSET/CONTROL/PRINT"
35 #define KEY_WINNT_PRINTERS      "HKLM/SOFTWARE/MICROSOFT/WINDOWS NT/CURRENTVERSION/PRINT/PRINTERS"
36 #define KEY_WINNT_PRINT         "HKLM/SOFTWARE/MICROSOFT/WINDOWS NT/CURRENTVERSION/PRINT"
37 #define KEY_PORTS               "HKLM/SOFTWARE/MICROSOFT/WINDOWS NT/CURRENTVERSION/PORTS"
38
39 /* callback table for various registry paths below the ones we service in this module */
40         
41 struct reg_dyn_tree {
42         /* full key path in normalized form */
43         const char *path;
44         
45         /* callbscks for fetch/store operations */
46         int ( *fetch_subkeys) ( const char *path, REGSUBKEY_CTR *subkeys );
47         BOOL (*store_subkeys) ( const char *path, REGSUBKEY_CTR *subkeys );
48         int  (*fetch_values)  ( const char *path, REGVAL_CTR *values );
49         BOOL (*store_values)  ( const char *path, REGVAL_CTR *values );
50 };
51
52
53 /**********************************************************************
54  move to next non-delimter character
55 *********************************************************************/
56
57 static char* remaining_path( const char *key )
58 {
59         static pstring new_path;
60         char *p;
61         
62         if ( !key || !*key )
63                 return NULL;
64
65         pstrcpy( new_path, key );
66         /* normalize_reg_path( new_path ); */
67         
68         if ( !(p = strchr( new_path, '\\' )) ) 
69         {
70                 if ( !(p = strchr( new_path, '/' )) )
71                         p = new_path;
72                 else 
73                         p++;
74         }
75         else
76                 p++;
77                 
78         return p;
79 }
80
81 /***********************************************************************
82  simple function to prune a pathname down to the basename of a file 
83  **********************************************************************/
84  
85 static char* dos_basename ( char *path )
86 {
87         char *p;
88         
89         if ( !(p = strrchr( path, '\\' )) )
90                 p = path;
91         else
92                 p++;
93                 
94         return p;
95 }
96
97 /**********************************************************************
98  *********************************************************************/
99
100 static int key_forms_fetch_keys( const char *key, REGSUBKEY_CTR *subkeys )
101 {
102         char *p = remaining_path( key + strlen(KEY_FORMS) );
103         
104         /* no keys below Forms */
105         
106         if ( p )
107                 return -1;
108                 
109         return 0;
110 }
111
112 static int key_forms_fetch_values( const char *key, REGVAL_CTR *values )
113 {
114         uint32          data[8];
115         int             i, num_values, form_index = 1;
116         nt_forms_struct *forms_list = NULL;
117         nt_forms_struct *form;
118                 
119         DEBUG(10,("print_values_forms: key=>[%s]\n", key ? key : "NULL" ));
120         
121         num_values = get_ntforms( &forms_list );
122                 
123         DEBUG(10,("hive_forms_fetch_values: [%d] user defined forms returned\n",
124                 num_values));
125
126         /* handle user defined forms */
127                                 
128         for ( i=0; i<num_values; i++ ) {
129                 form = &forms_list[i];
130                         
131                 data[0] = form->width;
132                 data[1] = form->length;
133                 data[2] = form->left;
134                 data[3] = form->top;
135                 data[4] = form->right;
136                 data[5] = form->bottom;
137                 data[6] = form_index++;
138                 data[7] = form->flag;
139                         
140                 regval_ctr_addvalue( values, form->name, REG_BINARY, (char*)data, sizeof(data) );       
141         }
142                 
143         SAFE_FREE( forms_list );
144         forms_list = NULL;
145                 
146         /* handle built-on forms */
147                 
148         num_values = get_builtin_ntforms( &forms_list );
149                 
150         DEBUG(10,("print_subpath_values_forms: [%d] built-in forms returned\n",
151                 num_values));
152                         
153         for ( i=0; i<num_values; i++ ) {
154                 form = &forms_list[i];
155                         
156                 data[0] = form->width;
157                 data[1] = form->length;
158                 data[2] = form->left;
159                 data[3] = form->top;
160                 data[4] = form->right;
161                 data[5] = form->bottom;
162                 data[6] = form_index++;
163                 data[7] = form->flag;
164                                         
165                 regval_ctr_addvalue( values, form->name, REG_BINARY, (char*)data, sizeof(data) );
166         }
167                 
168         SAFE_FREE( forms_list );
169         
170         return regval_ctr_numvals( values );
171 }
172
173 /**********************************************************************
174  *********************************************************************/
175
176 static int key_printer_fetch_keys( const char *key, REGSUBKEY_CTR *subkeys )
177 {
178         int n_services = lp_numservices();      
179         int snum;
180         fstring sname;
181         int i;
182         int num_subkeys = 0;
183         char *keystr;
184         char *base, *new_path;
185         NT_PRINTER_INFO_LEVEL *printer = NULL;
186         fstring *subkey_names = NULL;
187         pstring path;
188         
189         DEBUG(10,("print_subpath_printers: key=>[%s]\n", key ? key : "NULL" ));
190         
191         pstrcpy( path, key );
192         normalize_reg_path( path );
193
194         /* normalizing the path does not change length, just key delimiters and case */
195
196         if ( strncmp( path, KEY_WINNT_PRINTERS, strlen(KEY_WINNT_PRINTERS) ) == 0 )
197                 keystr = remaining_path( key + strlen(KEY_WINNT_PRINTERS) );
198         else
199                 keystr = remaining_path( key + strlen(KEY_CONTROL_PRINTERS) );
200         
201         
202         if ( !keystr ) {
203                 /* enumerate all printers */
204                 
205                 for (snum=0; snum<n_services; snum++) {
206                         if ( !(lp_snum_ok(snum) && lp_print_ok(snum) ) )
207                                 continue;
208
209                         /* don't report the [printers] share */
210
211                         if ( strequal( lp_servicename(snum), PRINTERS_NAME ) )
212                                 continue;
213                                 
214                         fstrcpy( sname, lp_servicename(snum) );
215                                 
216                         regsubkey_ctr_addkey( subkeys, sname );
217                 }
218                 
219                 num_subkeys = regsubkey_ctr_numkeys( subkeys );
220                 goto done;
221         }
222
223         /* get information for a specific printer */
224         
225         reg_split_path( keystr, &base, &new_path );
226
227                 if ( !W_ERROR_IS_OK( get_a_printer(NULL, &printer, 2, base) ) )
228                 goto done;
229
230         num_subkeys = get_printer_subkeys( &printer->info_2->data, new_path?new_path:"", &subkey_names );
231         
232         for ( i=0; i<num_subkeys; i++ )
233                 regsubkey_ctr_addkey( subkeys, subkey_names[i] );
234         
235         free_a_printer( &printer, 2 );
236                         
237         /* no other subkeys below here */
238
239 done:   
240         SAFE_FREE( subkey_names );
241         
242         return num_subkeys;
243 }
244
245 static BOOL key_printer_store_keys( const char *key, REGSUBKEY_CTR *subkeys )
246 {
247         return True;
248 }
249
250 static int key_printer_fetch_values( const char *key, REGVAL_CTR *values )
251 {
252         int             num_values = 0;
253         char            *keystr, *key2 = NULL;
254         char            *base, *new_path;
255         NT_PRINTER_INFO_LEVEL   *printer = NULL;
256         NT_PRINTER_INFO_LEVEL_2 *info2;
257         DEVICEMODE      *devmode;
258         prs_struct      prs;
259         uint32          offset;
260         int             snum;
261         fstring         printername; 
262         NT_PRINTER_DATA *p_data;
263         int             i, key_index;
264         UNISTR2         data;
265         pstring         path;
266         
267         /* 
268          * Theres are tw cases to deal with here
269          * (1) enumeration of printer_info_2 values
270          * (2) enumeration of the PrinterDriverData subney
271          */
272          
273         pstrcpy( path, key );
274         normalize_reg_path( path );
275
276         /* normalizing the path does not change length, just key delimiters and case */
277
278         if ( strncmp( path, KEY_WINNT_PRINTERS, strlen(KEY_WINNT_PRINTERS) ) == 0 )
279                 keystr = remaining_path( key + strlen(KEY_WINNT_PRINTERS) );
280         else
281                 keystr = remaining_path( key + strlen(KEY_CONTROL_PRINTERS) );
282         
283         if ( !keystr ) {
284                 /* top level key has no values */
285                 goto done;
286         }
287         
288         key2 = SMB_STRDUP( keystr );
289         keystr = key2;
290         reg_split_path( keystr, &base, &new_path );
291         
292         fstrcpy( printername, base );
293         
294         if ( !new_path ) {
295                 char *p;
296                 uint32 printer_status = PRINTER_STATUS_OK;
297
298                 /* we are dealing with the printer itself */
299
300                 if ( !W_ERROR_IS_OK( get_a_printer(NULL, &printer, 2, printername) ) )
301                         goto done;
302
303                 info2 = printer->info_2;
304                 
305
306                 regval_ctr_addvalue( values, "Attributes",       REG_DWORD, (char*)&info2->attributes,       sizeof(info2->attributes) );
307                 regval_ctr_addvalue( values, "Priority",         REG_DWORD, (char*)&info2->priority,         sizeof(info2->attributes) );
308                 regval_ctr_addvalue( values, "ChangeID",         REG_DWORD, (char*)&info2->changeid,         sizeof(info2->changeid) );
309                 regval_ctr_addvalue( values, "Default Priority", REG_DWORD, (char*)&info2->default_priority, sizeof(info2->default_priority) );
310
311                 /* lie and say everything is ok since we don't want to call print_queue_length() to get the real status */
312                 regval_ctr_addvalue( values, "Status",           REG_DWORD, (char*)&printer_status,          sizeof(info2->status) );
313
314                 regval_ctr_addvalue( values, "StartTime",        REG_DWORD, (char*)&info2->starttime,        sizeof(info2->starttime) );
315                 regval_ctr_addvalue( values, "UntilTime",        REG_DWORD, (char*)&info2->untiltime,        sizeof(info2->untiltime) );
316
317                 /* strip the \\server\ from this string */
318                 if ( !(p = strrchr( info2->printername, '\\' ) ) )
319                         p = info2->printername;
320                 else
321                         p++;
322                 init_unistr2( &data, p, UNI_STR_TERMINATE);
323                 regval_ctr_addvalue( values, "Name", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
324
325                 init_unistr2( &data, info2->location, UNI_STR_TERMINATE);
326                 regval_ctr_addvalue( values, "Location", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
327
328                 init_unistr2( &data, info2->comment, UNI_STR_TERMINATE);
329                 regval_ctr_addvalue( values, "Description", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
330
331                 init_unistr2( &data, info2->parameters, UNI_STR_TERMINATE);
332                 regval_ctr_addvalue( values, "Parameters", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
333
334                 init_unistr2( &data, info2->portname, UNI_STR_TERMINATE);
335                 regval_ctr_addvalue( values, "Port", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
336
337                 init_unistr2( &data, info2->sharename, UNI_STR_TERMINATE);
338                 regval_ctr_addvalue( values, "Share Name", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
339
340                 init_unistr2( &data, info2->drivername, UNI_STR_TERMINATE);
341                 regval_ctr_addvalue( values, "Printer Driver", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
342
343                 init_unistr2( &data, info2->sepfile, UNI_STR_TERMINATE);
344                 regval_ctr_addvalue( values, "Separator File", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
345
346                 init_unistr2( &data, "WinPrint", UNI_STR_TERMINATE);
347                 regval_ctr_addvalue( values, "Print Processor",  REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
348
349                 init_unistr2( &data, "RAW", UNI_STR_TERMINATE);
350                 regval_ctr_addvalue( values, "Datatype", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
351
352                 
353                 /* use a prs_struct for converting the devmode and security 
354                    descriptor to REG_BINARY */
355                 
356                 prs_init( &prs, MAX_PDU_FRAG_LEN, regval_ctr_getctx(values), MARSHALL);
357
358                 /* stream the device mode */
359                 
360                 snum = lp_servicenumber(info2->sharename);
361                 if ( (devmode = construct_dev_mode( snum )) != NULL )
362                 {                       
363                         if ( spoolss_io_devmode( "devmode", &prs, 0, devmode ) ) {
364                         
365                                 offset = prs_offset( &prs );
366                                 
367                                 regval_ctr_addvalue( values, "Default Devmode", REG_BINARY, prs_data_p(&prs), offset );
368                         }
369                         
370                         
371                 }
372                 
373                 prs_mem_clear( &prs );
374                 prs_set_offset( &prs, 0 );
375                 
376                 if ( info2->secdesc_buf && info2->secdesc_buf->len ) 
377                 {
378                         if ( sec_io_desc("sec_desc", &info2->secdesc_buf->sec, &prs, 0 ) ) {
379                         
380                                 offset = prs_offset( &prs );
381                         
382                                 regval_ctr_addvalue( values, "Security", REG_BINARY, prs_data_p(&prs), offset );
383                         }
384                 }
385
386                 prs_mem_free( &prs );
387                 
388                 num_values = regval_ctr_numvals( values );      
389                 
390                 goto done;
391                 
392         }
393                 
394         /* now enumerate the key */
395         
396         if ( !W_ERROR_IS_OK( get_a_printer(NULL, &printer, 2, printername) ) )
397                 goto done;
398         
399         /* iterate over all printer data and fill the regval container */
400         
401         p_data = &printer->info_2->data;
402         if ( (key_index = lookup_printerkey( p_data, new_path )) == -1  ) {
403                 DEBUG(10,("key_printer_fetch_values: Unknown keyname [%s]\n", new_path));
404                 goto done;
405         }
406         
407         num_values = regval_ctr_numvals( &p_data->keys[key_index].values );
408         
409         for ( i=0; i<num_values; i++ )
410                 regval_ctr_copyvalue( values, regval_ctr_specific_value(&p_data->keys[key_index].values, i) );
411                         
412
413 done:
414         if ( printer )
415                 free_a_printer( &printer, 2 );
416                 
417         SAFE_FREE( key2 ); 
418         
419         return num_values;
420 }
421
422 static BOOL key_printer_store_values( const char *key, REGVAL_CTR *values )
423 {
424         return True;
425 }
426
427 /**********************************************************************
428  *********************************************************************/
429 #define ENVIRONMENT_DRIVERS     1
430 #define ENVIRONMENT_PRINTPROC   2
431
432 static int key_driver_fetch_keys( const char *key, REGSUBKEY_CTR *subkeys )
433 {
434         const char *environments[] = {
435                 "Windows 4.0",
436                 "Windows NT x86",
437                 "Windows NT R4000",
438                 "Windows NT Alpha_AXP",
439                 "Windows NT PowerPC",
440                 "Windows IA64",
441                 "Windows x64",
442                 NULL };
443         fstring *drivers = NULL;
444         int i, env_index, num_drivers;
445         char *keystr, *base, *subkeypath;
446         pstring key2;
447         int num_subkeys = -1;
448         int env_subkey_type = 0;
449         int version;
450
451         DEBUG(10,("key_driver_fetch_keys key=>[%s]\n", key ? key : "NULL" ));
452         
453         keystr = remaining_path( key + strlen(KEY_ENVIRONMENTS) );      
454         
455         /* list all possible architectures */
456         
457         if ( !keystr ) {
458                 for ( num_subkeys=0; environments[num_subkeys]; num_subkeys++ ) 
459                         regsubkey_ctr_addkey( subkeys,  environments[num_subkeys] );
460
461                 return num_subkeys;
462         }
463         
464         /* we are dealing with a subkey of "Environments */
465         
466         pstrcpy( key2, keystr );
467         keystr = key2;
468         reg_split_path( keystr, &base, &subkeypath );
469         
470         /* sanity check */
471         
472         for ( env_index=0; environments[env_index]; env_index++ ) {
473                 if ( strequal( environments[env_index], base ) )
474                         break;
475         }
476         if ( !environments[env_index] )
477                 return -1;
478         
479         /* ...\Print\Environements\...\ */
480         
481         if ( !subkeypath ) {
482                 regsubkey_ctr_addkey( subkeys, "Drivers" );
483                 regsubkey_ctr_addkey( subkeys, "Print Processors" );
484                                 
485                 return 2;
486         }
487         
488         /* more of the key path to process */
489         
490         keystr = subkeypath;
491         reg_split_path( keystr, &base, &subkeypath );   
492                 
493         /* ...\Print\Environements\...\Drivers\ */
494         
495         if ( strequal(base, "Drivers") )
496                 env_subkey_type = ENVIRONMENT_DRIVERS;
497         else if ( strequal(base, "Print Processors") )
498                 env_subkey_type = ENVIRONMENT_PRINTPROC;
499         else
500                 /* invalid path */
501                 return -1;
502         
503         if ( !subkeypath ) {
504                 switch ( env_subkey_type ) {
505                 case ENVIRONMENT_DRIVERS:
506                         switch ( env_index ) {
507                                 case 0: /* Win9x */
508                                         regsubkey_ctr_addkey( subkeys, "Version-0" );
509                                         break;
510                                 default: /* Windows NT based systems */
511                                         regsubkey_ctr_addkey( subkeys, "Version-2" );
512                                         regsubkey_ctr_addkey( subkeys, "Version-3" );
513                                         break;                  
514                         }
515                 
516                         return regsubkey_ctr_numkeys( subkeys );
517                 
518                 case ENVIRONMENT_PRINTPROC:
519                         if ( env_index == 1 || env_index == 5 || env_index == 6 )
520                                 regsubkey_ctr_addkey( subkeys, "winprint" );
521                                 
522                         return regsubkey_ctr_numkeys( subkeys );
523                 }
524         }
525         
526         /* we finally get to enumerate the drivers */
527         
528         keystr = subkeypath;
529         reg_split_path( keystr, &base, &subkeypath );
530
531         /* get thr print processors key out of the way */
532         if ( env_subkey_type == ENVIRONMENT_PRINTPROC ) {
533                 if ( !strequal( base, "winprint" ) )
534                         return -1;
535                 return !subkeypath ? 0 : -1;
536         }
537         
538         /* only dealing with drivers from here on out */
539         
540         version = atoi(&base[strlen(base)-1]);
541                         
542         switch (env_index) {
543         case 0:
544                 if ( version != 0 )
545                         return -1;
546                 break;
547         default:
548                 if ( version != 2 && version != 3 )
549                         return -1;
550                 break;
551         }
552
553         
554         if ( !subkeypath ) {
555                 num_drivers = get_ntdrivers( &drivers, environments[env_index], version );
556                 for ( i=0; i<num_drivers; i++ )
557                         regsubkey_ctr_addkey( subkeys, drivers[i] );
558                         
559                 return regsubkey_ctr_numkeys( subkeys );        
560         }       
561         
562         /* if anything else left, just say if has no subkeys */
563         
564         DEBUG(1,("key_driver_fetch_keys unhandled key [%s] (subkey == %s\n", 
565                 key, subkeypath ));
566         
567         return 0;
568 }
569
570 static BOOL key_driver_store_keys( const char *key, REGSUBKEY_CTR *subkeys )
571 {
572         return True;
573 }
574
575 static int key_driver_fetch_values( const char *key, REGVAL_CTR *values )
576 {
577         char            *keystr, *base, *subkeypath;
578         pstring         key2;
579         fstring         arch_environment;
580         fstring         driver;
581         int             version;
582         NT_PRINTER_DRIVER_INFO_LEVEL    driver_ctr;
583         NT_PRINTER_DRIVER_INFO_LEVEL_3  *info3;
584         WERROR          w_result;
585         char            *buffer = NULL;
586         char            *buffer2 = NULL;
587         int             buffer_size = 0;
588         int             i, length;
589         char            *filename;
590         UNISTR2         data;
591         int             env_subkey_type = 0;
592         
593         
594         DEBUG(8,("key_driver_fetch_values: Enter key => [%s]\n", key ? key : "NULL"));
595
596         keystr = remaining_path( key + strlen(KEY_ENVIRONMENTS) );      
597         
598         if ( !keystr )
599                 return 0;
600                 
601         /* The only keys below KEY_PRINTING\Environments is the 
602            specific printer driver info */
603         
604         /* environment */
605         
606         pstrcpy( key2, keystr);
607         keystr = key2;
608         reg_split_path( keystr, &base, &subkeypath );
609         if ( !subkeypath ) 
610                 return 0;
611         fstrcpy( arch_environment, base );
612         
613         /* Driver */
614         
615         keystr = subkeypath;
616         reg_split_path( keystr, &base, &subkeypath );
617
618         if ( strequal(base, "Drivers") )
619                 env_subkey_type = ENVIRONMENT_DRIVERS;
620         else if ( strequal(base, "Print Processors") )
621                 env_subkey_type = ENVIRONMENT_PRINTPROC;
622         else
623                 /* invalid path */
624                 return -1;
625         
626         if ( !subkeypath )
627                 return 0;
628
629         /* for now bail out if we are seeing anything other than the drivers key */
630         
631         if ( env_subkey_type == ENVIRONMENT_PRINTPROC )
632                 return 0;
633                 
634         keystr = subkeypath;
635         reg_split_path( keystr, &base, &subkeypath );
636
637         /* no values under Version-XX */
638
639         if ( !subkeypath )
640                 return 0;
641                 
642         version = atoi(&base[strlen(base)-1]);
643
644         /* printer driver name */
645         
646         keystr = subkeypath;
647         reg_split_path( keystr, &base, &subkeypath );
648         /* don't go any deeper for now */
649         if ( subkeypath )
650                 return 0;
651         fstrcpy( driver, base );
652
653         w_result = get_a_printer_driver( &driver_ctr, 3, driver, arch_environment, version );
654
655         if ( !W_ERROR_IS_OK(w_result) )
656                 return -1;
657                 
658         /* build the values out of the driver information */
659         info3 = driver_ctr.info_3;
660         
661         filename = dos_basename( info3->driverpath );
662         init_unistr2( &data, filename, UNI_STR_TERMINATE);
663         regval_ctr_addvalue( values, "Driver",             REG_SZ,       (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
664         
665         filename = dos_basename( info3->configfile );
666         init_unistr2( &data, filename, UNI_STR_TERMINATE);
667         regval_ctr_addvalue( values, "Configuration File", REG_SZ,       (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
668         
669         filename = dos_basename( info3->datafile );
670         init_unistr2( &data, filename, UNI_STR_TERMINATE);
671         regval_ctr_addvalue( values, "Data File",          REG_SZ,       (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
672         
673         filename = dos_basename( info3->helpfile );
674         init_unistr2( &data, filename, UNI_STR_TERMINATE);
675         regval_ctr_addvalue( values, "Help File",          REG_SZ,       (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
676         
677         init_unistr2( &data, info3->defaultdatatype, UNI_STR_TERMINATE);
678         regval_ctr_addvalue( values, "Data Type",          REG_SZ,       (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
679         
680         regval_ctr_addvalue( values, "Version",            REG_DWORD,    (char*)&info3->cversion, sizeof(info3->cversion) );
681         
682         if ( info3->dependentfiles ) {
683                 /* place the list of dependent files in a single 
684                    character buffer, separating each file name by
685                    a NULL */
686                    
687                 for ( i=0; strcmp(info3->dependentfiles[i], ""); i++ ) {
688                         /* strip the path to only the file's base name */
689                 
690                         filename = dos_basename( info3->dependentfiles[i] );
691                         
692                         length = strlen(filename);
693                 
694                         buffer2 = SMB_REALLOC( buffer, buffer_size + (length + 1)*sizeof(uint16) );
695                         if ( !buffer2 )
696                                 break;
697                         buffer = buffer2;
698                         
699                         init_unistr2( &data, filename, UNI_STR_TERMINATE);
700                         memcpy( buffer+buffer_size, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
701                 
702                         buffer_size += (length + 1)*sizeof(uint16);
703                 }
704                 
705                 /* terminated by double NULL.  Add the final one here */
706                 
707                 buffer2 = SMB_REALLOC( buffer, buffer_size + 2 );
708                 if ( !buffer2 ) {
709                         SAFE_FREE( buffer );
710                         buffer_size = 0;
711                 } else {
712                         buffer = buffer2;
713                         buffer[buffer_size++] = '\0';
714                         buffer[buffer_size++] = '\0';
715                 }
716         }
717         
718         regval_ctr_addvalue( values, "Dependent Files",    REG_MULTI_SZ, buffer, buffer_size );
719         
720         free_a_printer_driver( driver_ctr, 3 );
721         
722         SAFE_FREE( buffer );
723                 
724         DEBUG(8,("key_driver_fetch_values: Exit\n"));
725         
726         return regval_ctr_numvals( values );
727 }
728
729 static BOOL key_driver_store_values( const char *key, REGVAL_CTR *values )
730 {
731         return True;
732 }
733
734 /**********************************************************************
735  Deal with the 'Print' key the same whether it came from SYSTEM
736  or SOFTWARE
737  *********************************************************************/
738
739 static int key_print_fetch_keys( const char *key, REGSUBKEY_CTR *subkeys )
740 {       
741         int key_len = strlen(key);
742         
743         /* no keys below 'Print' handled here */
744         
745         if ( (key_len != strlen(KEY_CONTROL_PRINT)) && (key_len != strlen(KEY_WINNT_PRINT)) )
746                 return -1;
747
748         regsubkey_ctr_addkey( subkeys, "Environments" );
749         regsubkey_ctr_addkey( subkeys, "Monitors" );
750         regsubkey_ctr_addkey( subkeys, "Forms" );
751         regsubkey_ctr_addkey( subkeys, "Printers" );
752         
753         return regsubkey_ctr_numkeys( subkeys );
754 }
755
756 /**********************************************************************
757  If I can get rid of the 'enumports command', this code becomes 
758  a tdb lookup.
759  *********************************************************************/
760
761 static int key_ports_fetch_keys( const char *key, REGSUBKEY_CTR *subkeys )
762 {
763         /* no keys below ports */
764         
765         if ( remaining_path( key + strlen(KEY_PORTS) ) )
766                 return -1;
767                 
768         return 0;
769 }
770
771 static BOOL key_ports_store_keys( const char *key, REGSUBKEY_CTR *subkeys )
772 {
773         return True;
774 }
775
776 static int key_ports_fetch_values( const char *key, REGVAL_CTR *values )
777 {
778         int numlines, i;
779         char **lines;
780         UNISTR2 data;
781         WERROR result;
782         char *p = remaining_path( key + strlen(KEY_PORTS) );
783         
784         /* no keys below ports */
785         if ( p )
786                 return -1;
787
788         if ( !W_ERROR_IS_OK(result = enumports_hook( &numlines, &lines )) )
789                 return -1;
790
791         init_unistr2( &data, "", UNI_STR_TERMINATE);
792         for ( i=0; i<numlines; i++ )
793                 regval_ctr_addvalue( values, lines[i], REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
794         
795         return regval_ctr_numvals( values );
796 }
797
798 static BOOL key_ports_store_values( const char *key, REGVAL_CTR *values )
799 {
800         return True;
801 }
802
803 /**********************************************************************
804  Structure to hold dispatch table of ops for various printer keys.
805  Make sure to always store deeper keys along the same path first so 
806  we ge a more specific match.
807  *********************************************************************/
808
809 static struct reg_dyn_tree print_registry[] = {
810 /* just pass the monitor onto the registry tdb */
811 { KEY_MONITORS,
812         &regdb_fetch_keys, 
813         &regdb_store_keys,
814         &regdb_fetch_values,
815         &regdb_store_values },
816 { KEY_FORMS, 
817         &key_forms_fetch_keys, 
818         NULL, 
819         &key_forms_fetch_values,
820         NULL },
821 { KEY_CONTROL_PRINTERS, 
822         &key_printer_fetch_keys,
823         &key_printer_store_keys,
824         &key_printer_fetch_values,
825         &key_printer_store_values },
826 { KEY_ENVIRONMENTS,
827         &key_driver_fetch_keys,
828         &key_driver_store_keys,
829         &key_driver_fetch_values,
830         &key_driver_store_values },
831 { KEY_CONTROL_PRINT,
832         &key_print_fetch_keys,
833         NULL,
834         NULL,
835         NULL },
836 { KEY_WINNT_PRINTERS,
837         &key_printer_fetch_keys,
838         &key_printer_store_keys,
839         &key_printer_fetch_values,
840         &key_printer_store_values },
841 { KEY_PORTS,
842         &key_ports_fetch_keys,
843         &key_ports_store_keys,
844         &key_ports_fetch_values,
845         &key_ports_store_values },
846         
847 { NULL, NULL, NULL, NULL, NULL }
848 };
849
850
851 /**********************************************************************
852  *********************************************************************/
853  
854 static int match_registry_path( const char *key )
855 {
856         int i;
857         pstring path;
858         
859         if ( !key )
860                 return -1;
861
862         pstrcpy( path, key );
863         normalize_reg_path( path );
864         
865         for ( i=0; print_registry[i].path; i++ ) {
866                 if ( strncmp( path, print_registry[i].path, strlen(print_registry[i].path) ) == 0 )
867                         return i;
868         }
869         
870         return -1;
871 }
872
873 /**********************************************************************
874  *********************************************************************/
875  
876 static int regprint_fetch_reg_keys( const char *key, REGSUBKEY_CTR *subkeys )
877 {
878         int i = match_registry_path( key );
879         
880         if ( i == -1 )
881                 return -1;
882                 
883         if ( !print_registry[i].fetch_subkeys )
884                 return -1;
885                 
886         return print_registry[i].fetch_subkeys( key, subkeys );
887 }
888
889 /**********************************************************************
890  *********************************************************************/
891
892 static BOOL regprint_store_reg_keys( const char *key, REGSUBKEY_CTR *subkeys )
893 {
894         int i = match_registry_path( key );
895         
896         if ( i == -1 )
897                 return False;
898         
899         if ( !print_registry[i].store_subkeys )
900                 return False;
901                 
902         return print_registry[i].store_subkeys( key, subkeys );
903 }
904
905 /**********************************************************************
906  *********************************************************************/
907
908 static int regprint_fetch_reg_values( const char *key, REGVAL_CTR *values )
909 {
910         int i = match_registry_path( key );
911         
912         if ( i == -1 )
913                 return -1;
914         
915         /* return 0 values by default since we know the key had 
916            to exist because the client opened a handle */
917            
918         if ( !print_registry[i].fetch_values )
919                 return 0;
920                 
921         return print_registry[i].fetch_values( key, values );
922 }
923
924 /**********************************************************************
925  *********************************************************************/
926
927 static BOOL regprint_store_reg_values( const char *key, REGVAL_CTR *values )
928 {
929         int i = match_registry_path( key );
930         
931         if ( i == -1 )
932                 return False;
933         
934         if ( !print_registry[i].store_values )
935                 return False;
936                 
937         return print_registry[i].store_values( key, values );
938 }
939
940 /* 
941  * Table of function pointers for accessing printing data
942  */
943  
944 REGISTRY_OPS printing_ops = {
945         regprint_fetch_reg_keys,
946         regprint_fetch_reg_values,
947         regprint_store_reg_keys,
948         regprint_store_reg_values,
949         NULL
950 };
951
952