root/source3/registry/reg_backend_printing.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. dos_basename
  2. key_forms_fetch_keys
  3. key_forms_fetch_values
  4. strip_printers_prefix
  5. key_printers_fetch_keys
  6. add_printers_by_registry
  7. key_printers_store_keys
  8. fill_in_printer_values
  9. key_printers_fetch_values
  10. find_valuename_index
  11. convert_values_to_printer_info_2
  12. key_printers_store_values
  13. key_driver_fetch_keys
  14. fill_in_driver_values
  15. driver_arch_fetch_values
  16. key_driver_fetch_values
  17. key_print_fetch_keys
  18. match_registry_path
  19. regprint_fetch_reg_keys
  20. regprint_store_reg_keys
  21. regprint_fetch_reg_values
  22. regprint_store_reg_values

   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 3 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, see <http://www.gnu.org/licenses/>.
  18  */
  19 
  20 /* Implementation of registry virtual views for printing information */
  21 
  22 #include "includes.h"
  23 
  24 #undef DBGC_CLASS
  25 #define DBGC_CLASS DBGC_REGISTRY
  26 
  27 /* registrt paths used in the print_registry[] */
  28 
  29 #define KEY_MONITORS            "HKLM/SYSTEM/CURRENTCONTROLSET/CONTROL/PRINT/MONITORS"
  30 #define KEY_FORMS               "HKLM/SYSTEM/CURRENTCONTROLSET/CONTROL/PRINT/FORMS"
  31 #define KEY_CONTROL_PRINTERS    "HKLM/SYSTEM/CURRENTCONTROLSET/CONTROL/PRINT/PRINTERS"
  32 #define KEY_ENVIRONMENTS        "HKLM/SYSTEM/CURRENTCONTROLSET/CONTROL/PRINT/ENVIRONMENTS"
  33 #define KEY_CONTROL_PRINT       "HKLM/SYSTEM/CURRENTCONTROLSET/CONTROL/PRINT"
  34 #define KEY_WINNT_PRINTERS      "HKLM/SOFTWARE/MICROSOFT/WINDOWS NT/CURRENTVERSION/PRINT/PRINTERS"
  35 #define KEY_WINNT_PRINT         "HKLM/SOFTWARE/MICROSOFT/WINDOWS NT/CURRENTVERSION/PRINT"
  36 #define KEY_PORTS               "HKLM/SOFTWARE/MICROSOFT/WINDOWS NT/CURRENTVERSION/PORTS"
  37 
  38 /* callback table for various registry paths below the ones we service in this module */
  39 
  40 struct reg_dyn_tree {
  41         /* full key path in normalized form */
  42         const char *path;
  43 
  44         /* callbscks for fetch/store operations */
  45         int ( *fetch_subkeys) ( const char *path, struct regsubkey_ctr *subkeys );
  46         bool (*store_subkeys) ( const char *path, struct regsubkey_ctr *subkeys );
  47         int  (*fetch_values)  ( const char *path, REGVAL_CTR *values );
  48         bool (*store_values)  ( const char *path, REGVAL_CTR *values );
  49 };
  50 
  51 /*********************************************************************
  52  *********************************************************************
  53  ** Utility Functions
  54  *********************************************************************
  55  *********************************************************************/
  56 
  57 /***********************************************************************
  58  simple function to prune a pathname down to the basename of a file
  59  **********************************************************************/
  60 
  61 static const char *dos_basename(const char *path)
     /* [<][>][^][v][top][bottom][index][help] */
  62 {
  63         const char *p;
  64 
  65         if (!(p = strrchr( path, '\\'))) {
  66                 p = path;
  67         } else {
  68                 p++;
  69         }
  70 
  71         return p;
  72 }
  73 
  74 /*********************************************************************
  75  *********************************************************************
  76  ** "HKLM/SYSTEM/CURRENTCONTROLSET/CONTROL/PRINT/FORMS"
  77  *********************************************************************
  78  *********************************************************************/
  79 
  80 static int key_forms_fetch_keys(const char *key, struct regsubkey_ctr *subkeys)
     /* [<][>][^][v][top][bottom][index][help] */
  81 {
  82         char *p = reg_remaining_path(talloc_tos(), key + strlen(KEY_FORMS));
  83 
  84         /* no keys below Forms */
  85 
  86         if (p) {
  87                 return -1;
  88         }
  89 
  90         return 0;
  91 }
  92 
  93 /**********************************************************************
  94  *********************************************************************/
  95 
  96 static int key_forms_fetch_values( const char *key, REGVAL_CTR *values )
     /* [<][>][^][v][top][bottom][index][help] */
  97 {
  98         uint32          data[8];
  99         int             i, num_values, form_index = 1;
 100         nt_forms_struct *forms_list = NULL;
 101         nt_forms_struct *form;
 102 
 103         DEBUG(10,("print_values_forms: key=>[%s]\n", key ? key : "NULL" ));
 104 
 105         num_values = get_ntforms( &forms_list );
 106 
 107         DEBUG(10,("hive_forms_fetch_values: [%d] user defined forms returned\n",
 108                 num_values));
 109 
 110         /* handle user defined forms */
 111 
 112         for ( i=0; i<num_values; i++ ) {
 113                 form = &forms_list[i];
 114 
 115                 data[0] = form->width;
 116                 data[1] = form->length;
 117                 data[2] = form->left;
 118                 data[3] = form->top;
 119                 data[4] = form->right;
 120                 data[5] = form->bottom;
 121                 data[6] = form_index++;
 122                 data[7] = form->flag;
 123 
 124                 regval_ctr_addvalue( values, form->name, REG_BINARY, (char*)data, sizeof(data) );       
 125         }
 126 
 127         SAFE_FREE( forms_list );
 128         forms_list = NULL;
 129 
 130         /* handle built-on forms */
 131 
 132         num_values = get_builtin_ntforms( &forms_list );
 133 
 134         DEBUG(10,("print_subpath_values_forms: [%d] built-in forms returned\n",
 135                 num_values));
 136 
 137         for ( i=0; i<num_values; i++ ) {
 138                 form = &forms_list[i];
 139 
 140                 data[0] = form->width;
 141                 data[1] = form->length;
 142                 data[2] = form->left;
 143                 data[3] = form->top;
 144                 data[4] = form->right;
 145                 data[5] = form->bottom;
 146                 data[6] = form_index++;
 147                 data[7] = form->flag;
 148 
 149                 regval_ctr_addvalue(values, form->name, REG_BINARY, (char*)data, sizeof(data) );
 150         }
 151 
 152         SAFE_FREE(forms_list);
 153 
 154         return regval_ctr_numvals(values);
 155 }
 156 
 157 /*********************************************************************
 158  *********************************************************************
 159  ** "HKLM/SYSTEM/CURRENTCONTROLSET/CONTROL/PRINT/PRINTERS"
 160  ** "HKLM/SOFTWARE/MICROSOFT/WINDOWS NT/CURRENTVERSION/PRINT/PRINTERS"
 161  *********************************************************************
 162  *********************************************************************/
 163 
 164 /*********************************************************************
 165  strip off prefix for printers key.  DOes return a pointer to static
 166  memory.
 167  *********************************************************************/
 168 
 169 static char *strip_printers_prefix(const char *key)
     /* [<][>][^][v][top][bottom][index][help] */
 170 {
 171         char *subkeypath = NULL;
 172         char *path = NULL;
 173         TALLOC_CTX *ctx = talloc_tos();
 174 
 175         path = talloc_strdup(ctx, key);
 176         if (!path) {
 177                 return NULL;
 178         }
 179         path = normalize_reg_path(ctx, path);
 180         if (!path) {
 181                 return NULL;
 182         }
 183 
 184         /* normalizing the path does not change length, just key delimiters and case */
 185 
 186         if (strncmp(path, KEY_WINNT_PRINTERS, strlen(KEY_WINNT_PRINTERS)) == 0) {
 187                 subkeypath = reg_remaining_path(ctx, key + strlen(KEY_WINNT_PRINTERS));
 188         } else {
 189                 subkeypath = reg_remaining_path(ctx, key + strlen(KEY_CONTROL_PRINTERS));
 190         }
 191 
 192         TALLOC_FREE(path);
 193         return subkeypath;
 194 }
 195 
 196 /*********************************************************************
 197  *********************************************************************/
 198 
 199 static int key_printers_fetch_keys( const char *key, struct regsubkey_ctr *subkeys )
     /* [<][>][^][v][top][bottom][index][help] */
 200 {
 201         int n_services = lp_numservices();
 202         int snum;
 203         fstring sname;
 204         int i;
 205         int num_subkeys = 0;
 206         char *printers_key;
 207         char *printername, *printerdatakey;
 208         NT_PRINTER_INFO_LEVEL *printer = NULL;
 209         fstring *subkey_names = NULL;
 210 
 211         DEBUG(10,("key_printers_fetch_keys: key=>[%s]\n", key ? key : "NULL" ));
 212 
 213         printers_key = strip_printers_prefix( key );
 214 
 215         if ( !printers_key ) {
 216                 /* enumerate all printers */
 217 
 218                 for (snum=0; snum<n_services; snum++) {
 219                         if ( !(lp_snum_ok(snum) && lp_print_ok(snum) ) )
 220                                 continue;
 221 
 222                         /* don't report the [printers] share */
 223 
 224                         if ( strequal( lp_servicename(snum), PRINTERS_NAME ) )
 225                                 continue;
 226 
 227                         fstrcpy( sname, lp_servicename(snum) );
 228 
 229                         regsubkey_ctr_addkey( subkeys, sname );
 230                 }
 231 
 232                 num_subkeys = regsubkey_ctr_numkeys( subkeys );
 233                 goto done;
 234         }
 235 
 236         /* get information for a specific printer */
 237 
 238         if (!reg_split_path( printers_key, &printername, &printerdatakey )) {
 239                 return -1;
 240         }
 241 
 242         /* validate the printer name */
 243 
 244         for (snum=0; snum<n_services; snum++) {
 245                 if ( !lp_snum_ok(snum) || !lp_print_ok(snum) )
 246                         continue;
 247                 if (strequal( lp_servicename(snum), printername ) )
 248                         break;
 249         }
 250 
 251         if ( snum>=n_services
 252                 || !W_ERROR_IS_OK( get_a_printer(NULL, &printer, 2, printername) ) ) 
 253         {
 254                 return -1;
 255         }
 256 
 257         num_subkeys = get_printer_subkeys( printer->info_2->data, printerdatakey?printerdatakey:"", &subkey_names );
 258         
 259         for ( i=0; i<num_subkeys; i++ )
 260                 regsubkey_ctr_addkey( subkeys, subkey_names[i] );
 261         
 262         free_a_printer( &printer, 2 );
 263                         
 264         /* no other subkeys below here */
 265 
 266 done:   
 267         SAFE_FREE( subkey_names );
 268         
 269         return num_subkeys;
 270 }
 271 
 272 /**********************************************************************
 273  Take a list of names and call add_printer_hook() if necessary
 274  Note that we do this a little differently from Windows since the 
 275  keyname is the sharename and not the printer name.
 276  *********************************************************************/
 277 
 278 static bool add_printers_by_registry( struct regsubkey_ctr *subkeys )
     /* [<][>][^][v][top][bottom][index][help] */
 279 {
 280         int i, num_keys, snum;
 281         char *printername;
 282         NT_PRINTER_INFO_LEVEL_2 info2;
 283         NT_PRINTER_INFO_LEVEL printer;
 284         
 285         ZERO_STRUCT( info2 );
 286         printer.info_2 = &info2;
 287         
 288         num_keys = regsubkey_ctr_numkeys( subkeys );
 289         
 290         become_root();
 291         for ( i=0; i<num_keys; i++ ) {
 292                 printername = regsubkey_ctr_specific_key( subkeys, i );
 293                 snum = find_service( printername );
 294                 
 295                 /* just verify a valied snum for now */
 296                 if ( snum == -1 ) {
 297                         fstrcpy( info2.printername, printername );
 298                         fstrcpy( info2.sharename, printername );
 299                         if ( !add_printer_hook(talloc_tos(), NULL, &printer ) ) {
 300                                 DEBUG(0,("add_printers_by_registry: Failed to add printer [%s]\n",
 301                                         printername));
 302                         }       
 303                 }
 304         }
 305         unbecome_root();
 306 
 307         return True;
 308 }
 309 
 310 /**********************************************************************
 311  *********************************************************************/
 312 
 313 static bool key_printers_store_keys( const char *key, struct regsubkey_ctr *subkeys )
     /* [<][>][^][v][top][bottom][index][help] */
 314 {
 315         char *printers_key;
 316         char *printername, *printerdatakey;
 317         NT_PRINTER_INFO_LEVEL *printer = NULL;
 318         int i, num_subkeys, num_existing_keys;
 319         char *subkeyname;
 320         fstring *existing_subkeys = NULL;
 321         
 322         printers_key = strip_printers_prefix( key );
 323         
 324         if ( !printers_key ) {
 325                 /* have to deal with some new or deleted printer */
 326                 return add_printers_by_registry( subkeys );
 327         }
 328         
 329         if (!reg_split_path( printers_key, &printername, &printerdatakey )) {
 330                 return False;
 331         }
 332         
 333         /* lookup the printer */
 334         
 335         if ( !W_ERROR_IS_OK(get_a_printer(NULL, &printer, 2, printername)) ) {
 336                 DEBUG(0,("key_printers_store_keys: Tried to store subkey for bad printername %s\n", 
 337                         printername));
 338                 return False;
 339         }
 340         
 341         /* get the top level printer keys */
 342         
 343         num_existing_keys = get_printer_subkeys( printer->info_2->data, "", &existing_subkeys );
 344         
 345         for ( i=0; i<num_existing_keys; i++ ) {
 346         
 347                 /* remove the key if it has been deleted */
 348                 
 349                 if ( !regsubkey_ctr_key_exists( subkeys, existing_subkeys[i] ) ) {
 350                         DEBUG(5,("key_printers_store_keys: deleting key %s\n", 
 351                                 existing_subkeys[i]));
 352                         delete_printer_key( printer->info_2->data, existing_subkeys[i] );
 353                 }
 354         }
 355 
 356         num_subkeys = regsubkey_ctr_numkeys( subkeys );
 357         for ( i=0; i<num_subkeys; i++ ) {
 358                 subkeyname = regsubkey_ctr_specific_key(subkeys, i);
 359                 /* add any missing printer keys */
 360                 if ( lookup_printerkey(printer->info_2->data, subkeyname) == -1 ) {
 361                         DEBUG(5,("key_printers_store_keys: adding key %s\n", 
 362                                 existing_subkeys[i]));
 363                         if ( add_new_printer_key( printer->info_2->data, subkeyname ) == -1 ) {
 364                                 SAFE_FREE( existing_subkeys );
 365                                 return False;
 366                         }
 367                 }
 368         }
 369         
 370         /* write back to disk */
 371         
 372         mod_a_printer( printer, 2 );
 373         
 374         /* cleanup */
 375         
 376         free_a_printer( &printer, 2 );
 377 
 378         SAFE_FREE( existing_subkeys );
 379 
 380         return True;
 381 }
 382 
 383 /**********************************************************************
 384  *********************************************************************/
 385 
 386 static void fill_in_printer_values( NT_PRINTER_INFO_LEVEL_2 *info2, REGVAL_CTR *values )
     /* [<][>][^][v][top][bottom][index][help] */
 387 {
 388         struct spoolss_DeviceMode *devmode;
 389         UNISTR2         data;
 390         char            *p;
 391         uint32 printer_status = PRINTER_STATUS_OK;
 392         
 393         regval_ctr_addvalue( values, "Attributes",       REG_DWORD, (char*)&info2->attributes,       sizeof(info2->attributes) );
 394         regval_ctr_addvalue( values, "Priority",         REG_DWORD, (char*)&info2->priority,         sizeof(info2->attributes) );
 395         regval_ctr_addvalue( values, "ChangeID",         REG_DWORD, (char*)&info2->changeid,         sizeof(info2->changeid) );
 396         regval_ctr_addvalue( values, "Default Priority", REG_DWORD, (char*)&info2->default_priority, sizeof(info2->default_priority) );
 397         
 398         /* lie and say everything is ok since we don't want to call print_queue_length() to get the real status */
 399         regval_ctr_addvalue( values, "Status",           REG_DWORD, (char*)&printer_status,          sizeof(info2->status) );
 400 
 401         regval_ctr_addvalue( values, "StartTime",        REG_DWORD, (char*)&info2->starttime,        sizeof(info2->starttime) );
 402         regval_ctr_addvalue( values, "UntilTime",        REG_DWORD, (char*)&info2->untiltime,        sizeof(info2->untiltime) );
 403 
 404         /* strip the \\server\ from this string */
 405         if ( !(p = strrchr( info2->printername, '\\' ) ) )
 406                 p = info2->printername;
 407         else
 408                 p++;
 409         init_unistr2( &data, p, UNI_STR_TERMINATE);
 410         regval_ctr_addvalue( values, "Name", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
 411 
 412         init_unistr2( &data, info2->location, UNI_STR_TERMINATE);
 413         regval_ctr_addvalue( values, "Location", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
 414 
 415         init_unistr2( &data, info2->comment, UNI_STR_TERMINATE);
 416         regval_ctr_addvalue( values, "Description", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
 417 
 418         init_unistr2( &data, info2->parameters, UNI_STR_TERMINATE);
 419         regval_ctr_addvalue( values, "Parameters", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
 420 
 421         init_unistr2( &data, info2->portname, UNI_STR_TERMINATE);
 422         regval_ctr_addvalue( values, "Port", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
 423 
 424         init_unistr2( &data, info2->sharename, UNI_STR_TERMINATE);
 425         regval_ctr_addvalue( values, "Share Name", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
 426 
 427         init_unistr2( &data, info2->drivername, UNI_STR_TERMINATE);
 428         regval_ctr_addvalue( values, "Printer Driver", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
 429 
 430         init_unistr2( &data, info2->sepfile, UNI_STR_TERMINATE);
 431         regval_ctr_addvalue( values, "Separator File", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
 432 
 433         init_unistr2( &data, "WinPrint", UNI_STR_TERMINATE);
 434         regval_ctr_addvalue( values, "Print Processor",  REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
 435 
 436         init_unistr2( &data, "RAW", UNI_STR_TERMINATE);
 437         regval_ctr_addvalue( values, "Datatype", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
 438 
 439         /* stream the device mode */
 440 
 441         devmode = construct_dev_mode(values,info2->sharename);
 442         if (devmode) {
 443                 DATA_BLOB blob;
 444                 enum ndr_err_code ndr_err;
 445 
 446                 ndr_err = ndr_push_struct_blob(&blob, values, NULL, devmode,
 447                                 (ndr_push_flags_fn_t)ndr_push_spoolss_DeviceMode);
 448 
 449                 if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 450                         regval_ctr_addvalue(values, "Default Devmode", REG_BINARY,
 451                                             (const char *)blob.data, blob.length);
 452                 }
 453         }
 454 
 455         /* stream the printer security descriptor */
 456 
 457         if (info2->secdesc_buf &&
 458             info2->secdesc_buf->sd &&
 459             info2->secdesc_buf->sd_size)
 460         {
 461                 NTSTATUS status;
 462                 DATA_BLOB blob;
 463 
 464                 status = marshall_sec_desc(values, info2->secdesc_buf->sd,
 465                                            &blob.data, &blob.length);
 466                 if (NT_STATUS_IS_OK(status)) {
 467                         regval_ctr_addvalue(values, "Security", REG_BINARY,
 468                                             (const char *)blob.data, blob.length);
 469                 }
 470         }
 471 
 472         return;
 473 }
 474 
 475 /**********************************************************************
 476  *********************************************************************/
 477 
 478 static int key_printers_fetch_values( const char *key, REGVAL_CTR *values )
     /* [<][>][^][v][top][bottom][index][help] */
 479 {
 480         int             num_values;
 481         char            *printers_key;
 482         char            *printername, *printerdatakey;
 483         NT_PRINTER_INFO_LEVEL   *printer = NULL;
 484         NT_PRINTER_DATA *p_data;
 485         int             i, key_index;
 486         
 487         printers_key = strip_printers_prefix( key );    
 488         
 489         /* top level key values stored in the registry has no values */
 490         
 491         if ( !printers_key ) {
 492                 /* normalize to the 'HKLM\SOFTWARE\...\Print\Printers' key */
 493                 return regdb_fetch_values( KEY_WINNT_PRINTERS, values );
 494         }
 495         
 496         /* lookup the printer object */
 497         
 498         if (!reg_split_path( printers_key, &printername, &printerdatakey )) {
 499                 return -1;
 500         }
 501         
 502         if ( !W_ERROR_IS_OK( get_a_printer(NULL, &printer, 2, printername) ) )
 503                 goto done;
 504                 
 505         if ( !printerdatakey ) {
 506                 fill_in_printer_values( printer->info_2, values );
 507                 goto done;
 508         }
 509                 
 510         /* iterate over all printer data keys and fill the regval container */
 511         
 512         p_data = printer->info_2->data;
 513         if ( (key_index = lookup_printerkey( p_data, printerdatakey )) == -1  ) {
 514                 /* failure....should never happen if the client has a valid open handle first */
 515                 DEBUG(10,("key_printers_fetch_values: Unknown keyname [%s]\n", printerdatakey));
 516                 free_a_printer( &printer, 2 );
 517                 return -1;
 518         }
 519         
 520         num_values = regval_ctr_numvals( p_data->keys[key_index].values );      
 521         for ( i=0; i<num_values; i++ )
 522                 regval_ctr_copyvalue( values, regval_ctr_specific_value(p_data->keys[key_index].values, i) );
 523                         
 524 
 525 done:
 526         if ( printer )
 527                 free_a_printer( &printer, 2 );
 528                 
 529         return regval_ctr_numvals( values );
 530 }
 531 
 532 /**********************************************************************
 533  *********************************************************************/
 534 
 535 #define REG_IDX_ATTRIBUTES              1
 536 #define REG_IDX_PRIORITY                2
 537 #define REG_IDX_DEFAULT_PRIORITY        3
 538 #define REG_IDX_CHANGEID                4
 539 #define REG_IDX_STATUS                  5
 540 #define REG_IDX_STARTTIME               6
 541 #define REG_IDX_NAME                    7
 542 #define REG_IDX_LOCATION                8
 543 #define REG_IDX_DESCRIPTION             9
 544 #define REG_IDX_PARAMETERS              10
 545 #define REG_IDX_PORT                    12
 546 #define REG_IDX_SHARENAME               13
 547 #define REG_IDX_DRIVER                  14
 548 #define REG_IDX_SEP_FILE                15
 549 #define REG_IDX_PRINTPROC               16
 550 #define REG_IDX_DATATYPE                17
 551 #define REG_IDX_DEVMODE                 18
 552 #define REG_IDX_SECDESC                 19
 553 #define REG_IDX_UNTILTIME               20
 554 
 555 struct {
 556         const char *name;
 557         int index;      
 558 } printer_values_map[] = {
 559         { "Attributes",         REG_IDX_ATTRIBUTES },
 560         { "Priority",           REG_IDX_PRIORITY },
 561         { "Default Priority",   REG_IDX_DEFAULT_PRIORITY },
 562         { "ChangeID",           REG_IDX_CHANGEID },
 563         { "Status",             REG_IDX_STATUS },
 564         { "StartTime",          REG_IDX_STARTTIME },
 565         { "UntilTime",          REG_IDX_UNTILTIME },
 566         { "Name",               REG_IDX_NAME },
 567         { "Location",           REG_IDX_LOCATION },
 568         { "Description",        REG_IDX_DESCRIPTION },
 569         { "Parameters",         REG_IDX_PARAMETERS },
 570         { "Port",               REG_IDX_PORT },
 571         { "Share Name",         REG_IDX_SHARENAME },
 572         { "Printer Driver",     REG_IDX_DRIVER },
 573         { "Separator File",     REG_IDX_SEP_FILE },
 574         { "Print Processor",    REG_IDX_PRINTPROC },
 575         { "Datatype",           REG_IDX_DATATYPE },
 576         { "Default Devmode",    REG_IDX_DEVMODE },
 577         { "Security",           REG_IDX_SECDESC },
 578         { NULL, -1 }
 579 };
 580 
 581 
 582 static int find_valuename_index( const char *valuename )
     /* [<][>][^][v][top][bottom][index][help] */
 583 {
 584         int i;
 585         
 586         for ( i=0; printer_values_map[i].name; i++ ) {
 587                 if ( strequal( valuename, printer_values_map[i].name ) )
 588                         return printer_values_map[i].index;
 589         }
 590         
 591         return -1;
 592 }
 593 
 594 /**********************************************************************
 595  *********************************************************************/
 596 
 597 static void convert_values_to_printer_info_2( NT_PRINTER_INFO_LEVEL_2 *printer2, REGVAL_CTR *values )
     /* [<][>][^][v][top][bottom][index][help] */
 598 {
 599         int num_values = regval_ctr_numvals( values );
 600         uint32 value_index;
 601         REGISTRY_VALUE *val;
 602         int i;
 603         
 604         for ( i=0; i<num_values; i++ ) {
 605                 val = regval_ctr_specific_value( values, i );
 606                 value_index = find_valuename_index( regval_name( val ) );
 607                 
 608                 switch( value_index ) {
 609                         case REG_IDX_ATTRIBUTES:
 610                                 printer2->attributes = (uint32)(*regval_data_p(val));
 611                                 break;
 612                         case REG_IDX_PRIORITY:
 613                                 printer2->priority = (uint32)(*regval_data_p(val));
 614                                 break;
 615                         case REG_IDX_DEFAULT_PRIORITY:
 616                                 printer2->default_priority = (uint32)(*regval_data_p(val));
 617                                 break;
 618                         case REG_IDX_CHANGEID:
 619                                 printer2->changeid = (uint32)(*regval_data_p(val));
 620                                 break;
 621                         case REG_IDX_STARTTIME:
 622                                 printer2->starttime = (uint32)(*regval_data_p(val));
 623                                 break;
 624                         case REG_IDX_UNTILTIME:
 625                                 printer2->untiltime = (uint32)(*regval_data_p(val));
 626                                 break;
 627                         case REG_IDX_NAME:
 628                                 rpcstr_pull( printer2->printername, regval_data_p(val), sizeof(fstring), regval_size(val), 0 );
 629                                 break;
 630                         case REG_IDX_LOCATION:
 631                                 rpcstr_pull( printer2->location, regval_data_p(val), sizeof(fstring), regval_size(val), 0 );
 632                                 break;
 633                         case REG_IDX_DESCRIPTION:
 634                                 rpcstr_pull( printer2->comment, regval_data_p(val), sizeof(fstring), regval_size(val), 0 );
 635                                 break;
 636                         case REG_IDX_PARAMETERS:
 637                                 rpcstr_pull( printer2->parameters, regval_data_p(val), sizeof(fstring), regval_size(val), 0 );
 638                                 break;
 639                         case REG_IDX_PORT:
 640                                 rpcstr_pull( printer2->portname, regval_data_p(val), sizeof(fstring), regval_size(val), 0 );
 641                                 break;
 642                         case REG_IDX_SHARENAME:
 643                                 rpcstr_pull( printer2->sharename, regval_data_p(val), sizeof(fstring), regval_size(val), 0 );
 644                                 break;
 645                         case REG_IDX_DRIVER:
 646                                 rpcstr_pull( printer2->drivername, regval_data_p(val), sizeof(fstring), regval_size(val), 0 );
 647                                 break;
 648                         case REG_IDX_SEP_FILE:
 649                                 rpcstr_pull( printer2->sepfile, regval_data_p(val), sizeof(fstring), regval_size(val), 0 );
 650                                 break;
 651                         case REG_IDX_PRINTPROC:
 652                                 rpcstr_pull( printer2->printprocessor, regval_data_p(val), sizeof(fstring), regval_size(val), 0 );
 653                                 break;
 654                         case REG_IDX_DATATYPE:
 655                                 rpcstr_pull( printer2->datatype, regval_data_p(val), sizeof(fstring), regval_size(val), 0 );
 656                                 break;
 657                         case REG_IDX_DEVMODE:
 658                                 break;
 659                         case REG_IDX_SECDESC:
 660                                 break;          
 661                         default:
 662                                 /* unsupported value...throw away */
 663                                 DEBUG(8,("convert_values_to_printer_info_2: Unsupported registry value [%s]\n", 
 664                                         regval_name( val ) ));
 665                 }
 666         }
 667         
 668         return;
 669 }       
 670 
 671 /**********************************************************************
 672  *********************************************************************/
 673 
 674 static bool key_printers_store_values( const char *key, REGVAL_CTR *values )
     /* [<][>][^][v][top][bottom][index][help] */
 675 {
 676         char *printers_key;
 677         char *printername, *keyname;
 678         NT_PRINTER_INFO_LEVEL   *printer = NULL;
 679         WERROR result;
 680         
 681         printers_key = strip_printers_prefix( key );
 682         
 683         /* values in the top level key get stored in the registry */
 684 
 685         if ( !printers_key ) {
 686                 /* normalize on the 'HKLM\SOFTWARE\....\Print\Printers' key */
 687                 return regdb_store_values( KEY_WINNT_PRINTERS, values );
 688         }
 689         
 690         if (!reg_split_path( printers_key, &printername, &keyname )) {
 691                 return False;
 692         }
 693 
 694         if ( !W_ERROR_IS_OK(get_a_printer(NULL, &printer, 2, printername) ) )
 695                 return False;
 696 
 697         /* deal with setting values directly under the printername */
 698 
 699         if ( !keyname ) {
 700                 convert_values_to_printer_info_2( printer->info_2, values );
 701         }
 702         else {
 703                 int num_values = regval_ctr_numvals( values );
 704                 int i;
 705                 REGISTRY_VALUE *val;
 706                 
 707                 delete_printer_key( printer->info_2->data, keyname );
 708                 
 709                 /* deal with any subkeys */
 710                 for ( i=0; i<num_values; i++ ) {
 711                         val = regval_ctr_specific_value( values, i );
 712                         result = set_printer_dataex( printer, keyname, 
 713                                 regval_name( val ),
 714                                 regval_type( val ),
 715                                 regval_data_p( val ),
 716                                 regval_size( val ) );
 717                         if ( !W_ERROR_IS_OK(result) ) {
 718                                 DEBUG(0,("key_printers_store_values: failed to set printer data [%s]!\n",
 719                                         keyname));
 720                                 free_a_printer( &printer, 2 );
 721                                 return False;
 722                         }
 723                 }
 724         }
 725 
 726         result = mod_a_printer( printer, 2 );
 727 
 728         free_a_printer( &printer, 2 );
 729 
 730         return W_ERROR_IS_OK(result);
 731 }
 732 
 733 /*********************************************************************
 734  *********************************************************************
 735  ** "HKLM/SYSTEM/CURRENTCONTROLSET/CONTROL/PRINT/ENVIRONMENTS"
 736  *********************************************************************
 737  *********************************************************************/
 738 
 739 static int key_driver_fetch_keys( const char *key, struct regsubkey_ctr *subkeys )
     /* [<][>][^][v][top][bottom][index][help] */
 740 {
 741         const char *environments[] = {
 742                 "Windows 4.0",
 743                 "Windows NT x86",
 744                 "Windows NT R4000",
 745                 "Windows NT Alpha_AXP",
 746                 "Windows NT PowerPC",
 747                 "Windows IA64",
 748                 "Windows x64",
 749                 NULL };
 750         fstring *drivers = NULL;
 751         int i, env_index, num_drivers;
 752         char *keystr, *base, *subkeypath;
 753         char *key2 = NULL;
 754         int num_subkeys = -1;
 755         int version;
 756         TALLOC_CTX *ctx = talloc_tos();
 757 
 758         DEBUG(10,("key_driver_fetch_keys key=>[%s]\n", key ? key : "NULL" ));
 759 
 760         keystr = reg_remaining_path(ctx, key + strlen(KEY_ENVIRONMENTS) );
 761 
 762         /* list all possible architectures */
 763 
 764         if ( !keystr ) {
 765                 for ( num_subkeys=0; environments[num_subkeys]; num_subkeys++ )
 766                         regsubkey_ctr_addkey( subkeys,  environments[num_subkeys] );
 767 
 768                 return num_subkeys;
 769         }
 770 
 771         /* we are dealing with a subkey of "Environments */
 772         key2 = talloc_strdup(ctx, keystr);
 773         if (!key2) {
 774                 return -1;
 775         }
 776         keystr = key2;
 777         if (!reg_split_path(keystr, &base, &subkeypath )) {
 778                 return -1;
 779         }
 780 
 781         /* sanity check */
 782 
 783         for ( env_index=0; environments[env_index]; env_index++ ) {
 784                 if ( strequal( environments[env_index], base ) )
 785                         break;
 786         }
 787         if ( !environments[env_index] )
 788                 return -1;
 789 
 790         /* ...\Print\Environements\...\ */
 791 
 792         if ( !subkeypath ) {
 793                 regsubkey_ctr_addkey( subkeys, "Drivers" );
 794                 regsubkey_ctr_addkey( subkeys, "Print Processors" );
 795 
 796                 return 2;
 797         }
 798 
 799         /* more of the key path to process */
 800 
 801         keystr = subkeypath;
 802         if (!reg_split_path( keystr, &base, &subkeypath )) {
 803                 return -1;
 804         }
 805 
 806         /* ...\Print\Environements\...\Drivers\ */
 807 
 808         if ( !subkeypath ) {
 809                 if ( strequal(base, "Drivers") ) {
 810                         switch ( env_index ) {
 811                                 case 0: /* Win9x */
 812                                         regsubkey_ctr_addkey( subkeys, "Version-0" );
 813                                         break;
 814                                 default: /* Windows NT based systems */
 815                                         regsubkey_ctr_addkey( subkeys, "Version-2" );
 816                                         regsubkey_ctr_addkey( subkeys, "Version-3" );
 817                                         break;
 818                         }
 819 
 820                         return regsubkey_ctr_numkeys( subkeys );
 821                 } else if ( strequal(base, "Print Processors") ) {
 822                         if ( env_index == 1 || env_index == 5 || env_index == 6 )
 823 
 824 
 825                         return regsubkey_ctr_numkeys( subkeys );
 826                 } else
 827                         return -1;      /* bad path */
 828         }
 829 
 830         /* we finally get to enumerate the drivers */
 831 
 832         /* only one possible subkey below PrintProc key */
 833 
 834         if ( strequal(base, "Print Processors") ) {
 835                 keystr = subkeypath;
 836                 if (!reg_split_path( keystr, &base, &subkeypath )) {
 837                         return -1;
 838                 }
 839 
 840                 /* no subkeys below this point */
 841 
 842                 if ( subkeypath )
 843                         return -1;
 844 
 845                 /* only allow one keyname here -- 'winprint' */
 846 
 847                 return strequal( base, "winprint" ) ? 0 : -1;
 848         }
 849 
 850         /* only dealing with drivers from here on out */
 851 
 852         keystr = subkeypath;
 853         if (!reg_split_path( keystr, &base, &subkeypath )) {
 854                 return -1;
 855         }
 856 
 857         version = atoi(&base[strlen(base)-1]);
 858 
 859         switch (env_index) {
 860         case 0:
 861                 if ( version != 0 )
 862                         return -1;
 863                 break;
 864         default:
 865                 if ( version != 2 && version != 3 )
 866                         return -1;
 867                 break;
 868         }
 869 
 870 
 871         if ( !subkeypath ) {
 872                 num_drivers = get_ntdrivers( &drivers, environments[env_index], version );
 873                 for ( i=0; i<num_drivers; i++ )
 874                         regsubkey_ctr_addkey( subkeys, drivers[i] );
 875 
 876                 return regsubkey_ctr_numkeys( subkeys );
 877         }
 878 
 879         /* if anything else left, just say if has no subkeys */
 880 
 881         DEBUG(1,("key_driver_fetch_keys unhandled key [%s] (subkey == %s)\n",
 882                 key, subkeypath ));
 883 
 884         return 0;
 885 }
 886 
 887 
 888 /**********************************************************************
 889  *********************************************************************/
 890 
 891 static void fill_in_driver_values( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info3, REGVAL_CTR *values )
     /* [<][>][^][v][top][bottom][index][help] */
 892 {
 893         char *buffer = NULL;
 894         int buffer_size = 0;
 895         int i, length;
 896         const char *filename;
 897         UNISTR2 data;
 898 
 899         filename = dos_basename( info3->driverpath );
 900         init_unistr2( &data, filename, UNI_STR_TERMINATE);
 901         regval_ctr_addvalue( values, "Driver", REG_SZ, (char*)data.buffer,
 902                 data.uni_str_len*sizeof(uint16) );
 903 
 904         filename = dos_basename( info3->configfile );
 905         init_unistr2( &data, filename, UNI_STR_TERMINATE);
 906         regval_ctr_addvalue( values, "Configuration File", REG_SZ, (char*)data.buffer, 
 907                 data.uni_str_len*sizeof(uint16) );
 908 
 909         filename = dos_basename( info3->datafile );
 910         init_unistr2( &data, filename, UNI_STR_TERMINATE);
 911         regval_ctr_addvalue( values, "Data File", REG_SZ, (char*)data.buffer,
 912                 data.uni_str_len*sizeof(uint16) );
 913 
 914         filename = dos_basename( info3->helpfile );
 915         init_unistr2( &data, filename, UNI_STR_TERMINATE);
 916         regval_ctr_addvalue( values, "Help File", REG_SZ, (char*)data.buffer,
 917                 data.uni_str_len*sizeof(uint16) );
 918 
 919         init_unistr2( &data, info3->defaultdatatype, UNI_STR_TERMINATE);
 920         regval_ctr_addvalue( values, "Data Type", REG_SZ, (char*)data.buffer,
 921                 data.uni_str_len*sizeof(uint16) );
 922 
 923         regval_ctr_addvalue( values, "Version", REG_DWORD, (char*)&info3->cversion, 
 924                 sizeof(info3->cversion) );
 925 
 926         if ( info3->dependentfiles ) {
 927                 /* place the list of dependent files in a single
 928                    character buffer, separating each file name by
 929                    a NULL */
 930 
 931                 for ( i=0; strcmp(info3->dependentfiles[i], ""); i++ ) {
 932                         /* strip the path to only the file's base name */
 933 
 934                         filename = dos_basename( info3->dependentfiles[i] );
 935 
 936                         length = strlen(filename);
 937 
 938                         buffer = (char *)SMB_REALLOC( buffer, buffer_size + (length + 1)*sizeof(uint16) );
 939                         if ( !buffer ) {
 940                                 break;
 941                         }
 942 
 943                         init_unistr2( &data, filename, UNI_STR_TERMINATE);
 944                         memcpy( buffer+buffer_size, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
 945 
 946                         buffer_size += (length + 1)*sizeof(uint16);
 947                 }
 948 
 949                 /* terminated by double NULL.  Add the final one here */
 950 
 951                 buffer = (char *)SMB_REALLOC( buffer, buffer_size + 2 );
 952                 if ( !buffer ) {
 953                         buffer_size = 0;
 954                 } else {
 955                         buffer[buffer_size++] = '\0';
 956                         buffer[buffer_size++] = '\0';
 957                 }
 958         }
 959 
 960         regval_ctr_addvalue( values, "Dependent Files",    REG_MULTI_SZ, buffer, buffer_size );
 961 
 962         SAFE_FREE( buffer );
 963 
 964         return;
 965 }
 966 
 967 /**********************************************************************
 968  *********************************************************************/
 969 
 970 static int driver_arch_fetch_values( char *key, REGVAL_CTR *values )
     /* [<][>][^][v][top][bottom][index][help] */
 971 {
 972         char            *keystr, *base, *subkeypath;
 973         fstring         arch_environment;
 974         fstring         driver;
 975         int             version;
 976         NT_PRINTER_DRIVER_INFO_LEVEL    driver_ctr;
 977         WERROR          w_result;
 978 
 979         if (!reg_split_path( key, &base, &subkeypath )) {
 980                 return -1;
 981         }
 982 
 983         /* no values in 'Environments\Drivers\Windows NT x86' */
 984 
 985         if ( !subkeypath )
 986                 return 0;
 987 
 988         /* We have the Architecture string and some subkey name:
 989            Currently we only support
 990            * Drivers
 991            * Print Processors
 992            Anything else is an error.
 993            */
 994 
 995         fstrcpy( arch_environment, base );
 996 
 997         keystr = subkeypath;
 998         if (!reg_split_path( keystr, &base, &subkeypath )) {
 999                 return -1;
1000         }
1001 
1002         if ( strequal(base, "Print Processors") )
1003                 return 0;
1004 
1005         /* only Drivers key can be left */
1006 
1007         if ( !strequal(base, "Drivers") )
1008                 return -1;
1009 
1010         if ( !subkeypath )
1011                 return 0;
1012 
1013         /* We know that we have Architechure\Drivers with some subkey name
1014            The subkey name has to be Version-XX */
1015 
1016         keystr = subkeypath;
1017         if (!reg_split_path( keystr, &base, &subkeypath )) {
1018                 return -1;
1019         }
1020 
1021         if ( !subkeypath )
1022                 return 0;
1023 
1024         version = atoi(&base[strlen(base)-1]);
1025 
1026         /* BEGIN PRINTER DRIVER NAME BLOCK */
1027 
1028         keystr = subkeypath;
1029         if (!reg_split_path( keystr, &base, &subkeypath )) {
1030                 return -1;
1031         }
1032 
1033         /* don't go any deeper for now */
1034 
1035         fstrcpy( driver, base );
1036 
1037         w_result = get_a_printer_driver( &driver_ctr, 3, driver, arch_environment, version );
1038 
1039         if ( !W_ERROR_IS_OK(w_result) )
1040                 return -1;
1041 
1042         fill_in_driver_values( driver_ctr.info_3, values );
1043 
1044         free_a_printer_driver( driver_ctr, 3 );
1045 
1046         /* END PRINTER DRIVER NAME BLOCK */
1047 
1048 
1049         DEBUG(8,("key_driver_fetch_values: Exit\n"));
1050 
1051         return regval_ctr_numvals( values );
1052 }
1053 
1054 /**********************************************************************
1055  *********************************************************************/
1056 
1057 static int key_driver_fetch_values( const char *key, REGVAL_CTR *values )
     /* [<][>][^][v][top][bottom][index][help] */
1058 {
1059         char *keystr = NULL;
1060         char *subkey = NULL;
1061         TALLOC_CTX *ctx = talloc_tos();
1062 
1063         DEBUG(8,("key_driver_fetch_values: Enter key => [%s]\n", key ? key : "NULL"));
1064 
1065         /* no values in the Environments key */
1066 
1067         if (!(keystr = reg_remaining_path(ctx, key + strlen(KEY_ENVIRONMENTS))))
1068                 return 0;
1069 
1070         subkey = talloc_strdup(ctx, keystr);
1071         if (!subkey) {
1072                 return 0;
1073         }
1074 
1075         /* pass off to handle subkeys */
1076 
1077         return driver_arch_fetch_values( subkey, values );
1078 }
1079 
1080 /*********************************************************************
1081  *********************************************************************
1082  ** "HKLM/SYSTEM/CURRENTCONTROLSET/CONTROL/PRINT"
1083  *********************************************************************
1084  *********************************************************************/
1085 
1086 static int key_print_fetch_keys( const char *key, struct regsubkey_ctr *subkeys )
     /* [<][>][^][v][top][bottom][index][help] */
1087 {
1088         int key_len = strlen(key);
1089 
1090         /* no keys below 'Print' handled here */
1091 
1092         if ( (key_len != strlen(KEY_CONTROL_PRINT)) && (key_len != strlen(KEY_WINNT_PRINT)) )
1093                 return -1;
1094 
1095         regsubkey_ctr_addkey( subkeys, "Environments" );
1096         regsubkey_ctr_addkey( subkeys, "Monitors" );
1097         regsubkey_ctr_addkey( subkeys, "Forms" );
1098         regsubkey_ctr_addkey( subkeys, "Printers" );
1099 
1100         return regsubkey_ctr_numkeys( subkeys );
1101 }
1102 
1103 /**********************************************************************
1104  *********************************************************************
1105  ** Structure to hold dispatch table of ops for various printer keys.
1106  ** Make sure to always store deeper keys along the same path first so
1107  ** we ge a more specific match.
1108  *********************************************************************
1109  *********************************************************************/
1110 
1111 static struct reg_dyn_tree print_registry[] = {
1112 /* just pass the monitor onto the registry tdb */
1113 { KEY_MONITORS,
1114         &regdb_fetch_keys,
1115         &regdb_store_keys,
1116         &regdb_fetch_values,
1117         &regdb_store_values },
1118 { KEY_FORMS,
1119         &key_forms_fetch_keys,
1120         NULL,
1121         &key_forms_fetch_values,
1122         NULL },
1123 { KEY_CONTROL_PRINTERS,
1124         &key_printers_fetch_keys,
1125         &key_printers_store_keys,
1126         &key_printers_fetch_values,
1127         &key_printers_store_values },
1128 { KEY_ENVIRONMENTS,
1129         &key_driver_fetch_keys,
1130         NULL,
1131         &key_driver_fetch_values,
1132         NULL },
1133 { KEY_CONTROL_PRINT,
1134         &key_print_fetch_keys,
1135         NULL,
1136         NULL,
1137         NULL },
1138 { KEY_WINNT_PRINTERS,
1139         &key_printers_fetch_keys,
1140         &key_printers_store_keys,
1141         &key_printers_fetch_values,
1142         &key_printers_store_values },
1143 { KEY_PORTS,
1144         &regdb_fetch_keys,
1145         &regdb_store_keys,
1146         &regdb_fetch_values,
1147         &regdb_store_values },
1148 
1149 { NULL, NULL, NULL, NULL, NULL }
1150 };
1151 
1152 
1153 /**********************************************************************
1154  *********************************************************************
1155  ** Main reg_printing interface functions
1156  *********************************************************************
1157  *********************************************************************/
1158 
1159 /***********************************************************************
1160  Lookup a key in the print_registry table, returning its index.
1161  -1 on failure
1162  **********************************************************************/
1163 
1164 static int match_registry_path(const char *key)
     /* [<][>][^][v][top][bottom][index][help] */
1165 {
1166         int i;
1167         char *path = NULL;
1168         TALLOC_CTX *ctx = talloc_tos();
1169 
1170         if ( !key )
1171                 return -1;
1172 
1173         path = talloc_strdup(ctx, key);
1174         if (!path) {
1175                 return -1;
1176         }
1177         path = normalize_reg_path(ctx, path);
1178         if (!path) {
1179                 return -1;
1180         }
1181 
1182         for ( i=0; print_registry[i].path; i++ ) {
1183                 if (strncmp( path, print_registry[i].path, strlen(print_registry[i].path) ) == 0 )
1184                         return i;
1185         }
1186 
1187         return -1;
1188 }
1189 
1190 /***********************************************************************
1191  **********************************************************************/
1192 
1193 static int regprint_fetch_reg_keys( const char *key, struct regsubkey_ctr *subkeys )
     /* [<][>][^][v][top][bottom][index][help] */
1194 {
1195         int i = match_registry_path( key );
1196 
1197         if ( i == -1 )
1198                 return -1;
1199 
1200         if ( !print_registry[i].fetch_subkeys )
1201                 return -1;
1202 
1203         return print_registry[i].fetch_subkeys( key, subkeys );
1204 }
1205 
1206 /**********************************************************************
1207  *********************************************************************/
1208 
1209 static bool regprint_store_reg_keys( const char *key, struct regsubkey_ctr *subkeys )
     /* [<][>][^][v][top][bottom][index][help] */
1210 {
1211         int i = match_registry_path( key );
1212 
1213         if ( i == -1 )
1214                 return False;
1215 
1216         if ( !print_registry[i].store_subkeys )
1217                 return False;
1218 
1219         return print_registry[i].store_subkeys( key, subkeys );
1220 }
1221 
1222 /**********************************************************************
1223  *********************************************************************/
1224 
1225 static int regprint_fetch_reg_values( const char *key, REGVAL_CTR *values )
     /* [<][>][^][v][top][bottom][index][help] */
1226 {
1227         int i = match_registry_path( key );
1228 
1229         if ( i == -1 )
1230                 return -1;
1231 
1232         /* return 0 values by default since we know the key had
1233            to exist because the client opened a handle */
1234 
1235         if ( !print_registry[i].fetch_values )
1236                 return 0;
1237 
1238         return print_registry[i].fetch_values( key, values );
1239 }
1240 
1241 /**********************************************************************
1242  *********************************************************************/
1243 
1244 static bool regprint_store_reg_values( const char *key, REGVAL_CTR *values )
     /* [<][>][^][v][top][bottom][index][help] */
1245 {
1246         int i = match_registry_path( key );
1247 
1248         if ( i == -1 )
1249                 return False;
1250 
1251         if ( !print_registry[i].store_values )
1252                 return False;
1253 
1254         return print_registry[i].store_values( key, values );
1255 }
1256 
1257 /*
1258  * Table of function pointers for accessing printing data
1259  */
1260 
1261 REGISTRY_OPS printing_ops = {
1262         .fetch_subkeys = regprint_fetch_reg_keys,
1263         .fetch_values = regprint_fetch_reg_values,
1264         .store_subkeys = regprint_store_reg_keys,
1265         .store_values = regprint_store_reg_values,
1266 };

/* [<][>][^][v][top][bottom][index][help] */