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