Fairly large change to printing code.
authorGerald Carter <jerry@samba.org>
Fri, 16 Aug 2002 15:36:37 +0000 (15:36 +0000)
committerGerald Carter <jerry@samba.org>
Fri, 16 Aug 2002 15:36:37 +0000 (15:36 +0000)
* removed support for PHANTOM_DEVMODE printer data

* s/NT_PRINTER_PARAM/REGISTRY_VALUE/g - This was a good bit
  of work.  Everything seems stable, but is not complete.

* support for printer data keys other than PrinterDriverData
  in the store and fetch routines.  Still needs to be plugged
  into the XxxPrinterDataEx() calls.

Tested against NT4.0 & 2k.  Like I said, it's not done, but doesn't
crash so it shouldn't upset anyone (unless you're trying to build
a Samba printer server off of HEAD).  More work to come.  Should
settle by Monday.

jerry
(This used to be commit 7ba7c04c0e961618c82c2112b9627af114c6cc42)

source3/include/nt_printing.h
source3/printing/nt_printing.c
source3/registry/reg_frontend.c
source3/registry/reg_printing.c
source3/rpc_parse/parse_spoolss.c
source3/rpc_server/srv_spoolss_nt.c

index 57181c66591912fcc3f7d38feb992524488e0c93..6303136894a792d8bc35f79eb55d31fb1b546c2b 100644 (file)
@@ -174,14 +174,26 @@ typedef struct nt_printer_driver_info_level
        NT_PRINTER_DRIVER_INFO_LEVEL_6 *info_6;
 } NT_PRINTER_DRIVER_INFO_LEVEL;
 
-typedef struct nt_printer_param
-{
-       fstring value;
-       uint32 type;
-       uint8 *data;
-       int data_len;
-       struct nt_printer_param *next;
-} NT_PRINTER_PARAM;
+/* predefined registry key names for printer data */
+
+#define SPOOL_PRINTERDATA_KEY          "PrinterDriverData"
+#define SPOOL_DSSPOOLER_KEY            "DsSpooler"
+#define SPOOL_DSDRIVER_KEY             "DsDriver"
+#define SPOOL_DSUSER_KEY               "DsUser"
+
+/* container for a single registry key */
+
+typedef struct {
+       char            *name;
+       REGVAL_CTR      values;
+} NT_PRINTER_KEY;
+
+/* container for all printer data */
+
+typedef struct {
+       int             num_keys;
+       NT_PRINTER_KEY  *keys;
+} NT_PRINTER_DATA;
 
 typedef struct ntdevicemode
 {
@@ -246,9 +258,8 @@ typedef struct nt_printer_info_level_2
        fstring printprocessor;
        fstring datatype;
        fstring parameters;
-       NT_PRINTER_PARAM *specific;
+       NT_PRINTER_DATA data;
        SEC_DESC_BUF *secdesc_buf;
-       /* not used but ... and how ??? */
        uint32 changeid;
        uint32 c_setprinter;
        uint32 setuptime;       
index e9ebb89d6056c91df58c91e82445070669b96911..c497c65bfea8c83b267e49d2c07c063debcd4074 100644 (file)
@@ -1962,22 +1962,52 @@ static int pack_devicemode(NT_DEVICEMODE *nt_devmode, char *buf, int buflen)
 }
 
 /****************************************************************************
-****************************************************************************/
-static int pack_specifics(NT_PRINTER_PARAM *param, char *buf, int buflen)
+ Pack all values in all printer keys
+ ***************************************************************************/
+static int pack_values(NT_PRINTER_DATA *data, char *buf, int buflen)
 {
-       int len = 0;
+       int             len = 0;
+       int             i, j;
+       REGISTRY_VALUE  *val;
+       REGVAL_CTR      *val_ctr;
+       pstring         path;
+       int             num_values;
 
-       while (param != NULL) {
-               len += tdb_pack(buf+len, buflen-len, "pfdB",
-                               param,
-                               param->value,
-                               param->type,
-                               param->data_len,
-                               param->data);
-               param=param->next;      
+       if ( !data )
+               return 0;
+
+       /* loop over all keys */
+               
+       for ( i=0; i<data->num_keys; i++ )
+       {       
+               val_ctr = &data->keys[i].values;
+               num_values = regval_ctr_numvals( val_ctr );
+               
+               /* loop over all values */
+               
+               for ( j=0; j<num_values; j++ )
+               {
+                       /* pathname should be stored as <key>\<value> */
+                       
+                       val = regval_ctr_specific_value( val_ctr, j );
+                       pstrcpy( path, data->keys[i].name );
+                       pstrcat( path, "\\" );
+                       pstrcat( path, regval_name(val) );
+                       
+                       len += tdb_pack(buf+len, buflen-len, "pPdB",
+                                       val,
+                                       path,
+                                       regval_type(val),
+                                       regval_size(val),
+                                       regval_data_p(val) );
+               }
+       
        }
 
-       len += tdb_pack(buf+len, buflen-len, "p", param);
+       /* terminator */
+       
+       len += tdb_pack(buf+len, buflen-len, "p", NULL);
 
        return len;
 }
@@ -2071,7 +2101,7 @@ static WERROR update_a_printer_2(NT_PRINTER_INFO_LEVEL_2 *info)
 
        len += pack_devicemode(info->devmode, buf+len, buflen-len);
        
-       len += pack_specifics(info->specific, buf+len, buflen-len);
+       len += pack_values( &info->data, buf+len, buflen-len );
 
        if (buflen != len) {
                char *tb;
@@ -2110,89 +2140,6 @@ done:
 }
 
 
-/****************************************************************************
-****************************************************************************/
-void add_a_specific_param(NT_PRINTER_INFO_LEVEL_2 *info_2, NT_PRINTER_PARAM **param)
-{
-       NT_PRINTER_PARAM *current;
-       
-       DEBUG(108,("add_a_specific_param\n"));  
-
-       (*param)->next=NULL;
-       
-       if (info_2->specific == NULL)
-       {
-               info_2->specific=*param;
-       }
-       else
-       {
-               current=info_2->specific;               
-               while (current->next != NULL) {
-                       current=current->next;
-               }               
-               current->next=*param;
-       }
-
-       *param = NULL;
-}
-
-/****************************************************************************
-****************************************************************************/
-BOOL unlink_specific_param_if_exist(NT_PRINTER_INFO_LEVEL_2 *info_2, NT_PRINTER_PARAM *param)
-{
-       NT_PRINTER_PARAM *current;
-       NT_PRINTER_PARAM *previous;
-       
-       current=info_2->specific;
-       previous=current;
-       
-       if (current==NULL) return (False);
-       
-       if ( !strcmp(current->value, param->value) &&
-           (strlen(current->value)==strlen(param->value)) ) {
-               DEBUG(109,("deleting first value\n"));
-               info_2->specific=current->next;
-               SAFE_FREE(current->data);
-               SAFE_FREE(current);
-               DEBUG(109,("deleted first value\n"));
-               return (True);
-       }
-
-       current=previous->next;
-               
-       while ( current!=NULL ) {
-               if (!strcmp(current->value, param->value) &&
-                   strlen(current->value)==strlen(param->value) ) {
-                       DEBUG(109,("deleting current value\n"));
-                       previous->next=current->next;
-                       SAFE_FREE(current->data);
-                       SAFE_FREE(current);
-                       DEBUG(109,("deleted current value\n"));
-                       return(True);
-               }
-               
-               previous=previous->next;
-               current=current->next;
-       }
-       return (False);
-}
-
-/****************************************************************************
- Clean up and deallocate a (maybe partially) allocated NT_PRINTER_PARAM.
-****************************************************************************/
-void free_nt_printer_param(NT_PRINTER_PARAM **param_ptr)
-{
-       NT_PRINTER_PARAM *param = *param_ptr;
-
-       if(param == NULL)
-               return;
-
-       DEBUG(106,("free_nt_printer_param: deleting param [%s]\n", param->value));
-
-               SAFE_FREE(param->data);
-       SAFE_FREE(*param_ptr);
-}
-
 /****************************************************************************
  Malloc and return an NT devicemode.
 ****************************************************************************/
@@ -2294,7 +2241,7 @@ void free_nt_devicemode(NT_DEVICEMODE **devmode_ptr)
 
        DEBUG(106,("free_nt_devicemode: deleting DEVMODE\n"));
 
-               SAFE_FREE(nt_devmode->private);
+       SAFE_FREE(nt_devmode->private);
        SAFE_FREE(*devmode_ptr);
 }
 
@@ -2304,23 +2251,29 @@ void free_nt_devicemode(NT_DEVICEMODE **devmode_ptr)
 static void free_nt_printer_info_level_2(NT_PRINTER_INFO_LEVEL_2 **info_ptr)
 {
        NT_PRINTER_INFO_LEVEL_2 *info = *info_ptr;
-       NT_PRINTER_PARAM *param_ptr;
+       NT_PRINTER_DATA         *data;
+       int                     i;
 
-       if(info == NULL)
+       if ( !info )
                return;
 
        DEBUG(106,("free_nt_printer_info_level_2: deleting info\n"));
 
        free_nt_devicemode(&info->devmode);
 
-       for(param_ptr = info->specific; param_ptr; ) {
-               NT_PRINTER_PARAM *tofree = param_ptr;
-
-               param_ptr = param_ptr->next;
-               free_nt_printer_param(&tofree);
+       /* clean up all registry keys */
+       
+       data = &info->data;
+       for ( i=0; i<data->num_keys; i++ ) 
+       {
+               SAFE_FREE( data->keys[i].name );
+               regval_ctr_destroy( &data->keys[i].values );
        }
+       SAFE_FREE( data->keys );
 
-       SAFE_FREE(*info_ptr);
+       /* finally the top level structure */
+       
+       SAFE_FREE( *info_ptr );
 }
 
 
@@ -2400,32 +2353,257 @@ static int unpack_devicemode(NT_DEVICEMODE **nt_devmode, char *buf, int buflen)
 }
 
 /****************************************************************************
-****************************************************************************/
-static int unpack_specifics(NT_PRINTER_PARAM **list, char *buf, int buflen)
+ allocate and initialize a new slot in 
+ ***************************************************************************/
+static int add_new_printer_key( NT_PRINTER_DATA *data, char *name )
 {
-       int len = 0;
-       NT_PRINTER_PARAM param, *p;
+       NT_PRINTER_KEY  *d;
+       int             key_index;
+       
+       if ( !data || !name )
+               return -1;
+       
+       /* allocate another slot in the NT_PRINTER_KEY array */
+       
+       d = Realloc( data->keys, sizeof(NT_PRINTER_KEY)*(data->num_keys+1) );
+       if ( d )
+               data->keys = d;
+       
+       key_index = data->num_keys;
+       
+       /* initialze new key */
+       
+       data->num_keys++;
+       data->keys[key_index].name = strdup( name );
+       
+       ZERO_STRUCTP( &data->keys[key_index].values );
+       
+       regval_ctr_init( &data->keys[key_index].values );
+       
+       DEBUG(10,("add_new_printer_key: Inserted new data key [%s]\n", name ));
+       
+       return key_index;
+}
+
+/****************************************************************************
+ search for a registry key name in the existing printer data
+ ***************************************************************************/
+int lookup_printerkey( NT_PRINTER_DATA *data, char *name )
+{
+       int             key_index = -1;
+       int             i;
+       
+       if ( !data || !name )
+               return -1;
+
+       DEBUG(12,("lookup_printerkey: Looking for [%s]\n", name));
 
-       *list = NULL;
+       /* loop over all existing keys */
+       
+       for ( i=0; i<data->num_keys; i++ ) 
+       {
+               if ( strcmp(data->keys[i].name, name) == 0 ) {
+                       DEBUG(12,("lookup_printerkey: Found [%s]!\n", name));
+                       key_index = i;
+                       break;
+               
+               }
+       }
+       
+       return key_index;
+}
+
+/****************************************************************************
+ ***************************************************************************/
+WERROR delete_all_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2 )
+{
+       WERROR          result = WERR_OK;
+       NT_PRINTER_DATA *data;
+       int             i;
+       
+       data = &p2->data;
+       
+       for ( i=0; i<data->num_keys; i++ ) 
+       {
+               DEBUG(8,("delete_all_printer_data: Removed all Printer Data from key [%s]\n",
+                       data->keys[i].name));
+               
+               SAFE_FREE( data->keys[i].name );
+               regval_ctr_destroy( &data->keys[i].values );
+       }
+       
+       SAFE_FREE( data->keys );
+
+       DEBUG(8,("delete_all_printer_data: Removed all Printer Data from printer [%s]\n",
+               p2->printername ));
+       
+       ZERO_STRUCTP( data );
+       
+       return result;
+}
+
+/****************************************************************************
+ ***************************************************************************/
+WERROR delete_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, char *key, char *value )
+{
+       WERROR          result = WERR_OK;
+       int             key_index;
+       
+       /* we must have names on non-zero length */
+       
+       if ( !key || !*key|| !value || !*value )
+               return WERR_INVALID_NAME;
+               
+       /* find the printer key first */
+
+       key_index = lookup_printerkey( &p2->data, key );
+       if ( key_index == -1 )
+               key_index = add_new_printer_key( &p2->data, key );
+               
+       if ( key_index == -1 )
+               return WERR_NOMEM;
+       
+       regval_ctr_delvalue( &p2->data.keys[key_index].values, value );
+       
+       DEBUG(8,("delete_printer_data: Removed key => [%s], value => [%s]\n",
+               key, value ));
+       
+       return result;
+}
+
+/****************************************************************************
+ ***************************************************************************/
+WERROR add_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, char *key, char *value, 
+                           uint32 type, uint8 *data, int real_len )
+{
+       WERROR          result = WERR_OK;
+       int             key_index;
 
-       while (1) {
-               len += tdb_unpack(buf+len, buflen-len, "p", &p);
-               if (!p) break;
+       /* we must have names on non-zero length */
+       
+       if ( !key || !*key|| !value || !*value )
+               return WERR_INVALID_NAME;
+               
+       /* find the printer key first */
+       
+       key_index = lookup_printerkey( &p2->data, key );
+       if ( key_index == -1 )
+               key_index = add_new_printer_key( &p2->data, key );
+               
+       if ( key_index == -1 )
+               return WERR_NOMEM;
+       
+       regval_ctr_addvalue( &p2->data.keys[key_index].values, value,
+               type, data, real_len );
+       
+       DEBUG(8,("add_printer_data: Added key => [%s], value => [%s], size => [%d]\n",
+               key, value, real_len ));
+       
+       return result;
+}
+
+/****************************************************************************
+ ***************************************************************************/
+REGISTRY_VALUE* get_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, char *key, char *value )
+{
+       int             key_index;
+
+       if ( (key_index = lookup_printerkey( &p2->data, key )) == -1 )
+               return NULL;
 
+       DEBUG(8,("get_printer_data: Attempting to lookup key => [%s], value => [%s]\n",
+               key, value ));
+
+       return regval_ctr_getvalue( &p2->data.keys[key_index].values, value );
+}
+
+/****************************************************************************
+ Unpack a list of registry values frem the TDB
+ ***************************************************************************/
+static int unpack_values(NT_PRINTER_DATA *printer_data, char *buf, int buflen)
+{
+       int             len = 0;
+       uint32          type;
+       pstring         string, valuename, keyname;
+       char            *str;
+       int             size;
+       uint8           *data_p;
+       REGISTRY_VALUE  *regval_p;
+       int             key_index;
+       
+       /* add the "PrinterDriverData" key first for performance reasons */
+       
+       add_new_printer_key( printer_data, SPOOL_PRINTERDATA_KEY );
+
+       /* loop and unpack the rest of the registry values */
+       
+       while ( True ) 
+       {
+       
+               /* check to see if there are any more registry values */
+               
+               len += tdb_unpack(buf+len, buflen-len, "p", &regval_p);         
+               if ( !regval_p ) 
+                       break;
+
+               /* unpack the next regval */
+               
                len += tdb_unpack(buf+len, buflen-len, "fdB",
-                                 param.value,
-                                 &param.type,
-                                 &param.data_len,
-                                 &param.data);
-               param.next = *list;
-               *list = memdup(&param, sizeof(param));
+                                 string,
+                                 &type,
+                                 &size,
+                                 &data_p);
+       
+               /*
+                * break of the keyname from the value name.  
+                * Should only be one '\' in the string returned.
+                */     
+                
+               str = strchr( string, '\\');
+               
+               /* Put in "PrinterDriverData" is no key specified */
+               
+               if ( !str ) {
+                       pstrcpy( keyname, SPOOL_PRINTERDATA_KEY );
+                       pstrcpy( valuename, string );
+               }
+               else {
+                       *str = '\0';
+                       pstrcpy( keyname, string );
+                       pstrcpy( valuename, str+1 );
+               }
+                       
+               /* see if we need a new key */
+               
+               if ( (key_index=lookup_printerkey( printer_data, keyname )) == -1 )
+                       key_index = add_new_printer_key( printer_data, keyname );
+                       
+               if ( key_index == -1 ) {
+                       DEBUG(0,("unpack_values: Failed to allocate a new key [%s]!\n",
+                               keyname));
+                       break;
+               }
+               
+               /* add the new value */
+               
+               regval_ctr_addvalue( &printer_data->keys[key_index].values, valuename, type, data_p, size );
 
-               DEBUG(8,("specific: [%s], len: %d\n", param.value, param.data_len));
+               DEBUG(8,("specific: [%s\\%s], len: %d\n", keyname, valuename, size));
        }
 
        return len;
 }
 
+/****************************************************************************
+ ***************************************************************************/
+
 static void map_to_os2_driver(fstring drivername)
 {
        static BOOL initialised=False;
@@ -2659,10 +2837,10 @@ static WERROR get_a_printer_2(NT_PRINTER_INFO_LEVEL_2 **info_ptr, fstring sharen
                info.devmode = construct_nt_devicemode(printername);
        }
 
-       len += unpack_specifics(&info.specific,dbuf.dptr+len, dbuf.dsize-len);
+       len += unpack_values( &info.data, dbuf.dptr+len, dbuf.dsize-len );
 
        /* This will get the current RPC talloc context, but we should be
-       passing this as a parameter... fixme... JRA ! */
+          passing this as a parameter... fixme... JRA ! */
 
        nt_printing_getsec(get_talloc_ctx(), sharename, &info.secdesc_buf);
 
@@ -2849,24 +3027,19 @@ WERROR mod_a_printer(NT_PRINTER_INFO_LEVEL printer, uint32 level)
  Initialize printer devmode & data with previously saved driver init values.
 ****************************************************************************/
 
-static BOOL set_driver_init_2(NT_PRINTER_INFO_LEVEL_2 *info_ptr)
+static BOOL set_driver_init_2( NT_PRINTER_INFO_LEVEL_2 *info_ptr )
 {
        int                     len = 0;
        pstring                 key;
        TDB_DATA                kbuf, dbuf;
-       NT_PRINTER_PARAM        *current;
        NT_PRINTER_INFO_LEVEL_2 info;
 
        /*
-        * Delete any printer data 'specifics' already set. When called for driver
+        * Delete any printer data 'values' already set. When called for driver
         * replace, there will generally be some, but during an add printer, there
         * should not be any (if there are delete them).
         */
-       while ( (current=info_ptr->specific) != NULL ) {
-               info_ptr->specific=current->next;
-               SAFE_FREE(current->data);
-               SAFE_FREE(current);
-       }
+       delete_all_printer_data( info_ptr );
 
        ZERO_STRUCT(info);
 
@@ -2876,7 +3049,7 @@ static BOOL set_driver_init_2(NT_PRINTER_INFO_LEVEL_2 *info_ptr)
        kbuf.dsize = strlen(key)+1;
 
        dbuf = tdb_fetch(tdb_drivers, kbuf);
-    if (!dbuf.dptr) {
+       if (!dbuf.dptr) {
                /*
                 * When changing to a driver that has no init info in the tdb, remove
                 * the previous drivers init info and leave the new on blank.
@@ -2945,9 +3118,10 @@ static BOOL set_driver_init_2(NT_PRINTER_INFO_LEVEL_2 *info_ptr)
                        info_ptr->printername, info_ptr->drivername));
 
        /* 
-        * Add the printer data 'specifics' to the new printer
+        * Add the printer data 'values' to the new printer
         */
-       len += unpack_specifics(&info_ptr->specific,dbuf.dptr+len, dbuf.dsize-len);
+       len += unpack_values( &info_ptr->data, dbuf.dptr+len, dbuf.dsize-len );
+       
 
        SAFE_FREE(dbuf.dptr);
 
@@ -3005,7 +3179,7 @@ BOOL del_driver_init(char *drivername)
 }
 
 /****************************************************************************
- Pack up the DEVMODE and specifics for a printer into a 'driver init' entry 
+ Pack up the DEVMODE and values for a printer into a 'driver init' entry 
  in the tdb. Note: this is different from the driver entry and the printer
  entry. There should be a single driver init entry for each driver regardless
  of whether it was installed from NT or 2K. Technically, they should be
@@ -3026,7 +3200,7 @@ static uint32 update_driver_init_2(NT_PRINTER_INFO_LEVEL_2 *info)
        len = 0;
        len += pack_devicemode(info->devmode, buf+len, buflen-len);
 
-       len += pack_specifics(info->specific, buf+len, buflen-len);
+       len += pack_values( &info->data, buf+len, buflen-len );
 
        if (buflen != len) {
                char *tb;
@@ -3057,14 +3231,14 @@ done:
 
        SAFE_FREE(buf);
 
-       DEBUG(10,("update_driver_init_2: Saved printer [%s] init DEVMODE & specifics for driver [%s]\n",
+       DEBUG(10,("update_driver_init_2: Saved printer [%s] init DEVMODE & values for driver [%s]\n",
                 info->sharename, info->drivername));
 
        return ret;
 }
 
 /****************************************************************************
- Update (i.e. save) the driver init info (DEVMODE and specifics) for a printer
+ Update (i.e. save) the driver init info (DEVMODE and values) for a printer
 ****************************************************************************/
 
 uint32 update_driver_init(NT_PRINTER_INFO_LEVEL printer, uint32 level)
@@ -3088,154 +3262,6 @@ uint32 update_driver_init(NT_PRINTER_INFO_LEVEL printer, uint32 level)
        return result;
 }
 
-/****************************************************************************
- Convert the printer data value, a REG_BINARY array, into an initialization 
- DEVMODE. Note: the array must be parsed as if it was a DEVMODE in an rpc...
- got to keep the endians happy :).
-****************************************************************************/
-
-static BOOL convert_driver_init(NT_PRINTER_PARAM *param, TALLOC_CTX *ctx, NT_DEVICEMODE *nt_devmode)
-{
-       BOOL       result = False;
-       prs_struct ps;
-       DEVICEMODE devmode;
-
-       ZERO_STRUCT(devmode);
-
-       prs_init(&ps, 0, ctx, UNMARSHALL);
-       ps.data_p      = (char *)param->data;
-       ps.buffer_size = param->data_len;
-
-       if (spoolss_io_devmode("phantom DEVMODE", &ps, 0, &devmode))
-               result = convert_devicemode("", &devmode, &nt_devmode);
-       else
-               DEBUG(10,("convert_driver_init: error parsing DEVMODE\n"));
-
-       return result;
-}
-
-/****************************************************************************
- Set the DRIVER_INIT info in the tdb. Requires Win32 client code that:
-
- 1. Use the driver's config DLL to this UNC printername and:
-    a. Call DrvPrintEvent with PRINTER_EVENT_INITIALIZE
-    b. Call DrvConvertDevMode with CDM_DRIVER_DEFAULT to get default DEVMODE
- 2. Call SetPrinterData with the 'magic' key and the DEVMODE as data.
-
- The last step triggers saving the "driver initialization" information for
- this printer into the tdb. Later, new printers that use this driver will
- have this initialization information bound to them. This simulates the
- driver initialization, as if it had run on the Samba server (as it would
- have done on NT).
-
- The Win32 client side code requirement sucks! But until we can run arbitrary
- Win32 printer driver code on any Unix that Samba runs on, we are stuck with it.
- It would have been easier to use SetPrinter because all the UNMARSHALLING of
- the DEVMODE is done there, but 2K/XP clients do not set the DEVMODE... think
- about it and you will realize why.  JRR 010720
-****************************************************************************/
-
-static WERROR save_driver_init_2(NT_PRINTER_INFO_LEVEL *printer, NT_PRINTER_PARAM *param)
-{
-       WERROR        status       = WERR_OK;
-       TALLOC_CTX    *ctx         = NULL;
-       NT_DEVICEMODE *nt_devmode  = NULL;
-       NT_DEVICEMODE *tmp_devmode = printer->info_2->devmode;
-       
-       /*
-        * When the DEVMODE is already set on the printer, don't try to unpack it.
-        */
-
-       if (!printer->info_2->devmode && param->data_len) {
-               /*
-                * Set devmode on printer info, so entire printer initialization can be
-                * saved to tdb.
-                */
-
-               if ((ctx = talloc_init()) == NULL)
-                       return WERR_NOMEM;
-
-               if ((nt_devmode = (NT_DEVICEMODE*)malloc(sizeof(NT_DEVICEMODE))) == NULL) {
-                       status = WERR_NOMEM;
-                       goto done;
-               }
-       
-               ZERO_STRUCTP(nt_devmode);
-
-               /*
-                * The DEVMODE is held in the 'data' component of the param in raw binary.
-                * Convert it to to a devmode structure
-                */
-               if (!convert_driver_init(param, ctx, nt_devmode)) {
-                       DEBUG(10,("save_driver_init_2: error converting DEVMODE\n"));
-                       status = WERR_INVALID_PARAM;
-                       goto done;
-               }
-
-               printer->info_2->devmode = nt_devmode;
-       }
-
-       /*
-        * Pack up and add (or update) the DEVMODE and any current printer data to
-        * a 'driver init' element in the tdb
-        * 
-        */
-
-       if (update_driver_init(*printer, 2)!=0) {
-               DEBUG(10,("save_driver_init_2: error updating DEVMODE\n"));
-               status = WERR_NOMEM;
-               goto done;
-       }
-       
-       /*
-        * If driver initialization info was successfully saved, set the current 
-        * printer to match it. This allows initialization of the current printer 
-        * as well as the driver.
-        */
-       status = mod_a_printer(*printer, 2);
-       if (!W_ERROR_IS_OK(status)) {
-               DEBUG(10,("save_driver_init_2: error setting DEVMODE on printer [%s]\n",
-                                 printer->info_2->printername));
-       }
-       
-#if 0  /* JERRY */
-       srv_spoolss_sendnotify(p, handle);
-#endif
-
-  done:
-       talloc_destroy(ctx);
-       if (nt_devmode)
-               SAFE_FREE(nt_devmode->private);
-       SAFE_FREE(nt_devmode);
-       printer->info_2->devmode = tmp_devmode;
-
-       return status;
-}
-
-/****************************************************************************
- Update the driver init info (DEVMODE and specifics) for a printer
-****************************************************************************/
-
-WERROR save_driver_init(NT_PRINTER_INFO_LEVEL *printer, uint32 level, NT_PRINTER_PARAM *param)
-{
-       WERROR status = WERR_OK;
-       
-       switch (level)
-       {
-               case 2:
-               {
-                       status=save_driver_init_2(printer, param);
-                       break;
-               }
-               default:
-                       status=WERR_UNKNOWN_LEVEL;
-                       break;
-       }
-       
-       return status;
-}
-
 /****************************************************************************
  Get a NT_PRINTER_INFO_LEVEL struct. It returns malloced memory.
 ****************************************************************************/
@@ -3851,83 +3877,6 @@ WERROR delete_printer_driver( NT_PRINTER_DRIVER_INFO_LEVEL_3 *i, struct current_
        return delete_printer_driver_internal(i, user, version, delete_files );
 }
 
-
-/****************************************************************************
-****************************************************************************/
-
-BOOL get_specific_param_by_index(NT_PRINTER_INFO_LEVEL printer, uint32 level, uint32 param_index,
-                                 fstring value, uint8 **data, uint32 *type, uint32 *len)
-{
-       /* right now that's enough ! */
-       NT_PRINTER_PARAM *param;
-       int i=0;
-       
-       param=printer.info_2->specific;
-       
-       while (param != NULL && i < param_index) {
-               param=param->next;
-               i++;
-       }
-       
-       if (param == NULL)
-               return False;
-
-       /* exited because it exist */
-       *type=param->type;              
-       StrnCpy(value, param->value, sizeof(fstring)-1);
-       *data=(uint8 *)malloc(param->data_len*sizeof(uint8));
-       if(*data == NULL)
-               return False;
-       ZERO_STRUCTP(*data);
-       memcpy(*data, param->data, param->data_len);
-       *len=param->data_len;
-       return True;
-}
-
-/****************************************************************************
-****************************************************************************/
-BOOL get_specific_param(NT_PRINTER_INFO_LEVEL printer, uint32 level,
-                        fstring value, uint8 **data, uint32 *type, uint32 *len)
-{
-       /* right now that's enough ! */ 
-       NT_PRINTER_PARAM *param;
-       
-       DEBUG(10, ("get_specific_param\n"));
-       
-       param=printer.info_2->specific;
-               
-       while (param != NULL)
-       {
-#if 1 /* JRA - I think this should be case insensitive.... */
-               if ( strequal(value, param->value)
-#else
-               if ( !strcmp(value, param->value)
-#endif
-                   && strlen(value)==strlen(param->value))
-                       break;
-                       
-               param=param->next;
-       }
-       
-       if (param != NULL)
-       {
-        DEBUGADD(10, ("get_specific_param: found one param\n"));
-               /* exited because it exist */
-               *type=param->type;      
-               
-               *data=(uint8 *)malloc(param->data_len*sizeof(uint8));
-               if(*data == NULL)
-                       return False;
-               memcpy(*data, param->data, param->data_len);
-               *len=param->data_len;
-
-               DEBUGADD(10, ("get_specific_param: exit true\n"));
-               return (True);
-       }
-       DEBUGADD(10, ("get_specific_param: exit false\n"));
-       return (False);
-}
-
 /****************************************************************************
  Store a security desc for a printer.
 ****************************************************************************/
@@ -4363,76 +4312,3 @@ BOOL print_time_access_check(int snum)
        return ok;
 }
 
-#if 0  /* JERRY - not used */
-/****************************************************************************
- Attempt to write a default device.
-*****************************************************************************/
-
-WERROR printer_write_default_dev(int snum, const PRINTER_DEFAULT *printer_default)
-{
-       NT_PRINTER_INFO_LEVEL *printer = NULL;
-       WERROR result;
-
-       /*
-        * Don't bother if no default devicemode was sent.
-        */
-
-       if (printer_default->devmode_cont.devmode == NULL)
-               return WERR_OK;
-
-       result = get_a_printer(&printer, 2, lp_servicename(snum));
-       if (!W_ERROR_IS_OK(result)) return result;
-
-       /*
-        * Just ignore it if we already have a devmode.
-        */
-#if 0
-       if (printer->info_2->devmode != NULL)
-               goto done;
-#endif
-       /*
-        * We don't have a devicemode and we're trying to write
-        * one. Check we have the access needed.
-        */
-       DEBUG(5,("printer_write_default_dev: access: %x\n", printer_default->access_required));
-
-       if ( (printer_default->access_required & PRINTER_ACCESS_ADMINISTER) != 
-             PRINTER_ACCESS_ADMINISTER) {
-               DEBUG(5,("printer_write_default_dev: invalid request access to update: %x\n", printer_default->access_required));
-               result = WERR_ACCESS_DENIED;
-               goto done;
-       }
-
-       if (!print_access_check(NULL, snum, PRINTER_ACCESS_ADMINISTER)) {
-               DEBUG(5,("printer_write_default_dev: Access denied for printer %s\n",
-                       lp_servicename(snum) ));
-               result = WERR_ACCESS_DENIED;
-               /*result = NT_STATUS_NO_PROBLEMO;*/
-               goto done;
-       }
-
-       DEBUG(5,("printer_write_default_dev: updating, check OK.\n"));
-
-       /*
-        * Convert the on the wire devicemode format to the internal one.
-        */
-
-       if (!convert_devicemode(printer->info_2->printername,
-                               printer_default->devmode_cont.devmode,
-                               &printer->info_2->devmode)) {
-               result = WERR_NOMEM;
-               goto done;
-       }
-
-       /*
-        * Finally write back to the tdb.
-        */
-
-       result = mod_a_printer(*printer, 2);
-
-  done:
-
-       free_a_printer(&printer, 2);
-       return result;
-}
-#endif /* JERRY */
index c0788c1b7532ea65c1e49eddc8fdb8f383356a21..45c1f24001070d10e1eab1db0606613eccff0260 100644 (file)
@@ -188,6 +188,38 @@ void free_registry_value( REGISTRY_VALUE *val )
        return;
 }
 
+/**********************************************************************
+ *********************************************************************/
+
+uint8* regval_data_p( REGISTRY_VALUE *val )
+{
+       return val->data_p;
+}
+
+/**********************************************************************
+ *********************************************************************/
+
+int regval_size( REGISTRY_VALUE *val )
+{
+       return val->size;
+}
+
+/**********************************************************************
+ *********************************************************************/
+
+char* regval_name( REGISTRY_VALUE *val )
+{
+       return val->valuename;
+}
+
+/**********************************************************************
+ *********************************************************************/
+
+uint32 regval_type( REGISTRY_VALUE *val )
+{
+       return val->type;
+}
+
 /***********************************************************************
  Retreive a pointer to a specific value.  Caller shoud dup the structure
  since this memory may go away with a regval_ctr_destroy()
@@ -214,7 +246,7 @@ TALLOC_CTX* regval_ctr_getctx( REGVAL_CTR *val )
 }
 
 /***********************************************************************
- Add a new regostry value to the array
+ Add a new registry value to the array
  **********************************************************************/
 
 int regval_ctr_addvalue( REGVAL_CTR *ctr, char *name, uint16 type, 
@@ -237,7 +269,7 @@ int regval_ctr_addvalue( REGVAL_CTR *ctr, char *name, uint16 type,
                                ctr->values = ppreg;
                }
 
-               /* allocate a new valuie and store the pointer in the arrya */
+               /* allocate a new value and store the pointer in the arrya */
                
                ctr->values[ctr->num_values] = talloc( ctr->ctx, sizeof(REGISTRY_VALUE) );
 
@@ -253,6 +285,61 @@ int regval_ctr_addvalue( REGVAL_CTR *ctr, char *name, uint16 type,
        return ctr->num_values;
 }
 
+/***********************************************************************
+ Delete a single value from the registry container.
+ No need to free memory since it is talloc'd.
+ **********************************************************************/
+
+int regval_ctr_delvalue( REGVAL_CTR *ctr, char *name )
+{
+       int     i;
+       
+       /* search for the value */
+       
+       for ( i=0; i<ctr->num_values; i++ ) {
+               if ( strcmp( ctr->values[i]->valuename, name ) == 0)
+                       break;
+       }
+       
+       /* just return if we don't find it */
+       
+       if ( i == ctr->num_values )
+               return ctr->num_values;
+       
+       /* just shift everything down one */
+       
+       for ( /* use previous i */; i<(ctr->num_values-1); i++ )
+               memcpy( ctr->values[i], ctr->values[i+1], sizeof(REGISTRY_VALUE) );
+               
+       /* paranoia */
+       
+       ZERO_STRUCTP( ctr->values[i] );
+       
+       ctr->num_values--;
+       
+       return ctr->num_values;
+}
+
+/***********************************************************************
+ Delete a single value from the registry container.
+ No need to free memory since it is talloc'd.
+ **********************************************************************/
+
+REGISTRY_VALUE* regval_ctr_getvalue( REGVAL_CTR *ctr, char *name )
+{
+       int     i;
+       
+       /* search for the value */
+       
+       for ( i=0; i<ctr->num_values; i++ ) {
+               if ( strcmp( ctr->values[i]->valuename, name ) == 0)
+                       return ctr->values[i];
+               
+       }
+       
+       return NULL;
+}
+
 /***********************************************************************
  free memory held by a REGVAL_CTR structure
  **********************************************************************/
index 3fd3680489402705ee44bb03b9ac83da297dfa42..8f53fe9ea5c3834601f902ed03ca973a8e033e11 100644 (file)
@@ -492,7 +492,7 @@ static int print_subpath_printers( char *key, REGSUBKEY_CTR *subkeys )
                
                free_a_printer( &printer, 2 );
                
-               regsubkey_ctr_addkey( subkeys, "PrinterDriverData" );
+               regsubkey_ctr_addkey( subkeys, SPOOL_PRINTERDATA_KEY );
        }
        
        /* no other subkeys below here */
@@ -620,7 +620,7 @@ static int print_subpath_values_printers( char *key, REGVAL_CTR *val )
        
        /* here should be no more path components here */
        
-       if ( new_path || strcmp(base, "PrinterDriverData") )
+       if ( new_path || strcmp(base, SPOOL_PRINTERDATA_KEY) )
                goto done;
                
        /* now enumerate the PrinterDriverData key */
@@ -632,10 +632,12 @@ static int print_subpath_values_printers( char *key, REGVAL_CTR *val )
        
        /* iterate over all printer data and fill the regval container */
        
+#if 0  /* JERRY */
        for ( i=0; get_specific_param_by_index(*printer, 2, i, valuename, &data, &type, &data_len); i++ )
        {
                regval_ctr_addvalue( val, valuename, type, data, data_len );
        }
+#endif
                
        free_a_printer( &printer, 2 );
 
index 79760ff37ef13d2a0c811b980115276adef9f2ac..ac41a81a5a128f71a9b5e4ccabe06af7e6e3f01f 100644 (file)
@@ -6186,42 +6186,6 @@ BOOL spoolss_io_r_resetprinter(char *desc, SPOOL_R_RESETPRINTER *r_u, prs_struct
        return True;
 }
 
-/*******************************************************************
-********************************************************************/  
-BOOL convert_specific_param(NT_PRINTER_PARAM **param, const UNISTR2 *value,
-                               uint32 type, const uint8 *data, uint32 len)
-{
-       DEBUG(5,("converting a specific param struct\n"));
-
-       if (*param == NULL)
-       {
-               *param=(NT_PRINTER_PARAM *)malloc(sizeof(NT_PRINTER_PARAM));
-               if(*param == NULL)
-                       return False;
-               memset((char *)*param, '\0', sizeof(NT_PRINTER_PARAM));
-               DEBUGADD(6,("Allocated a new PARAM struct\n"));
-       }
-       unistr2_to_ascii((*param)->value, value, sizeof((*param)->value)-1);
-       (*param)->type = type;
-       
-       /* le champ data n'est pas NULL termine */
-       /* on stocke donc la longueur */
-       
-       (*param)->data_len=len;
-       
-       if (len) {
-               (*param)->data=(uint8 *)malloc(len * sizeof(uint8));
-               if((*param)->data == NULL)
-                       return False;
-               memcpy((*param)->data, data, len);
-       }
-               
-       DEBUGADD(6,("\tvalue:[%s], len:[%d]\n",(*param)->value, (*param)->data_len));
-       dump_data(10, (char *)(*param)->data, (*param)->data_len);
-
-       return True;
-}
-
 /*******************************************************************
 ********************************************************************/  
 
index d04aff8b150330b73fd6b4006a218fa8b1e2aab5..2aa11530f80032c8ef854d95aad451fd9bdec700 100644 (file)
@@ -1798,51 +1798,56 @@ static BOOL getprinterdata_printer(pipes_struct *p, TALLOC_CTX *ctx, POLICY_HND
                                uint8 **data, uint32 *needed, uint32 in_size )
 {
        NT_PRINTER_INFO_LEVEL *printer = NULL;
-       int snum=0;
-       uint8 *idata=NULL;
-       uint32 len;
-       Printer_entry *Printer = find_printer_index_by_hnd(p, handle);
+       int             snum=0; 
+       Printer_entry   *Printer = find_printer_index_by_hnd(p, handle);
+       REGISTRY_VALUE  *val;
+       int             size = 0;
        
        DEBUG(5,("getprinterdata_printer\n"));
 
-       if (!Printer) {
+       if ( !Printer ) {
                DEBUG(2,("getprinterdata_printer: Invalid handle (%s:%u:%u).\n", OUR_HANDLE(handle)));
                return False;
        }
 
-       if(!get_printer_snum(p, handle, &snum))
+       if ( !get_printer_snum(p, handle, &snum) )
                return False;
 
-       if (!W_ERROR_IS_OK(get_a_printer(&printer, 2, lp_servicename(snum))))
+       if ( !W_ERROR_IS_OK(get_a_printer(&printer, 2, lp_servicename(snum))) )
                return False;
 
-       if (!get_specific_param(*printer, 2, value, &idata, type, &len)) {
+       if ( !(val = get_printer_data( printer->info_2, SPOOL_PRINTERDATA_KEY, value)) )
+       {
                free_a_printer(&printer, 2);
                return False;
        }
+       
+       *type = regval_type( val );
 
-       free_a_printer(&printer, 2);
 
        DEBUG(5,("getprinterdata_printer:allocating %d\n", in_size));
 
-       if (in_size) {
-               if((*data  = (uint8 *)talloc(ctx, in_size *sizeof(uint8) )) == NULL) {
+       if (in_size) 
+       {
+               if ( (*data  = (uint8 *)talloc(ctx, in_size * sizeof(uint8))) == NULL )
                        return False;
-               }
 
-               memset(*data, 0, in_size *sizeof(uint8));
+               memset( *data, 0, in_size *sizeof(uint8) );
+               
                /* copy the min(in_size, len) */
-               memcpy(*data, idata, (len>in_size)?in_size:len *sizeof(uint8));
-       } else {
-               *data = NULL;
+               
+               size = regval_size( val );
+               memcpy( *data, regval_data_p(val), (size > in_size) ? in_size : size*sizeof(uint8) );
        }
+       else
+               *data = NULL;
 
-       *needed = len;
+       *needed = size;
        
        DEBUG(5,("getprinterdata_printer:copy done\n"));
                        
-       SAFE_FREE(idata);
        
+       free_a_printer(&printer, 2);
        return True;
 }      
 
@@ -1871,11 +1876,12 @@ WERROR _spoolss_getprinterdata(pipes_struct *p, SPOOL_Q_GETPRINTERDATA *q_u, SPO
         * JFM, 4/19/1999
         */
 
-       *out_size=in_size;
+       *out_size = in_size;
 
        /* in case of problem, return some default values */
-       *needed=0;
-       *type=0;
+       
+       *needed = 0;
+       *type   = 0;
        
        DEBUG(4,("_spoolss_getprinterdata\n"));
        
@@ -1889,13 +1895,16 @@ WERROR _spoolss_getprinterdata(pipes_struct *p, SPOOL_Q_GETPRINTERDATA *q_u, SPO
        unistr2_to_ascii(value, valuename, sizeof(value)-1);
        
        if (Printer->printer_type == PRINTER_HANDLE_IS_PRINTSERVER)
-               found=getprinterdata_printer_server(p->mem_ctx, value, type, data, needed, *out_size);
+               found = getprinterdata_printer_server(p->mem_ctx, value, type, data, needed, *out_size);
        else
-               found= getprinterdata_printer(p, p->mem_ctx, handle, value, type, data, needed, *out_size);
+               found = getprinterdata_printer(p, p->mem_ctx, handle, value, type, data, needed, *out_size);
 
-       if (found==False) {
+       if ( !found ) 
+       {
                DEBUG(5, ("value not found, allocating %d\n", *out_size));
+               
                /* reply this param doesn't exist */
+               
                if (*out_size) {
                        if((*data=(uint8 *)talloc_zero(p->mem_ctx, *out_size*sizeof(uint8))) == NULL)
                                return WERR_NOMEM;
@@ -5219,254 +5228,6 @@ static BOOL add_printer_hook(NT_PRINTER_INFO_LEVEL *printer)
        return True;
 }
 
-#if 0  /* JERRY */
-
-/* Return true if two devicemodes are equal */
-
-#define DEVMODE_CHECK_INT(field) \
-    if (d1->field != d2->field) { \
-        DEBUG(10, ("nt_devicemode_equal(): " #field " not equal (%d != %d)\n", \
-            d1->field, d2->field)); \
-        return False; \
-    }
-
-/************************************************************************
- Handy, but currently unused functions
- ***********************************************************************/
-
-static BOOL nt_devicemode_equal(NT_DEVICEMODE *d1, NT_DEVICEMODE *d2)
-{
-       if (!d1 && !d2) goto equal;  /* if both are NULL they are equal */
-
-       if (!d1 ^ !d2) {
-               DEBUG(10, ("nt_devicemode_equal(): pointers not equal\n"));
-               return False; /* if either is exclusively NULL are not equal */
-       }
-
-       if (!strequal(d1->devicename, d2->devicename)) {
-               DEBUG(10, ("nt_devicemode_equal(): device not equal (%s != %s)\n", d1->devicename, d2->devicename));
-               return False;
-       }
-
-       if (!strequal(d1->formname, d2->formname)) {
-               DEBUG(10, ("nt_devicemode_equal(): formname not equal (%s != %s)\n", d1->formname, d2->formname));
-               return False;
-       }
-
-       DEVMODE_CHECK_INT(specversion);
-       DEVMODE_CHECK_INT(driverversion);
-       DEVMODE_CHECK_INT(driverextra);
-       DEVMODE_CHECK_INT(orientation);
-       DEVMODE_CHECK_INT(papersize);
-       DEVMODE_CHECK_INT(paperlength);
-       DEVMODE_CHECK_INT(paperwidth);
-       DEVMODE_CHECK_INT(scale);
-       DEVMODE_CHECK_INT(copies);
-       DEVMODE_CHECK_INT(defaultsource);
-       DEVMODE_CHECK_INT(printquality);
-       DEVMODE_CHECK_INT(color);
-       DEVMODE_CHECK_INT(duplex);
-       DEVMODE_CHECK_INT(yresolution);
-       DEVMODE_CHECK_INT(ttoption);
-       DEVMODE_CHECK_INT(collate);
-       DEVMODE_CHECK_INT(logpixels);
-
-       DEVMODE_CHECK_INT(fields);
-       DEVMODE_CHECK_INT(bitsperpel);
-       DEVMODE_CHECK_INT(pelswidth);
-       DEVMODE_CHECK_INT(pelsheight);
-       DEVMODE_CHECK_INT(displayflags);
-       DEVMODE_CHECK_INT(displayfrequency);
-       DEVMODE_CHECK_INT(icmmethod);
-       DEVMODE_CHECK_INT(icmintent);
-       DEVMODE_CHECK_INT(mediatype);
-       DEVMODE_CHECK_INT(dithertype);
-       DEVMODE_CHECK_INT(reserved1);
-       DEVMODE_CHECK_INT(reserved2);
-       DEVMODE_CHECK_INT(panningwidth);
-       DEVMODE_CHECK_INT(panningheight);
-
-       /* compare the private data if it exists */
-       if (!d1->driverextra && !d2->driverextra) goto equal;
-
-
-       DEVMODE_CHECK_INT(driverextra);
-
-       if (memcmp(d1->private, d2->private, d1->driverextra)) {
-               DEBUG(10, ("nt_devicemode_equal(): private data not equal\n"));
-               return False;
-       }
-
- equal:
-       DEBUG(10, ("nt_devicemode_equal(): devicemodes identical\n"));
-       return True;
-}
-
-/* Return true if two NT_PRINTER_PARAM structures are equal */
-
-static BOOL nt_printer_param_equal(NT_PRINTER_PARAM *p1,
-                                  NT_PRINTER_PARAM *p2)
-{
-       if (!p1 && !p2) goto equal;
-
-       if ((!p1 && p2) || (p1 && !p2)) {
-               DEBUG(10, ("nt_printer_param_equal(): pointers differ\n"));
-               return False;
-       }
-
-       /* Compare lists of printer parameters */
-
-       while (p1) {
-               BOOL found = False;
-               NT_PRINTER_PARAM *q = p1;
-
-               /* Find the parameter in the second structure */
-
-               while(q) {
-
-                       if (strequal(p1->value, q->value)) {
-
-                               if (p1->type != q->type) {
-                                       DEBUG(10, ("nt_printer_param_equal():"
-                                                  "types for %s differ (%d != %d)\n",
-                                                  p1->value, p1->type,
-                                                  q->type));
-                                       break;
-                               }
-
-                               if (p1->data_len != q->data_len) {
-                                       DEBUG(10, ("nt_printer_param_equal():"
-                                                  "len for %s differs (%d != %d)\n",
-                                                  p1->value, p1->data_len,
-                                                  q->data_len));
-                                       break;
-                               }
-
-                               if (memcmp(p1->data, q->data, p1->data_len) == 0) {
-                                       found = True;
-                               } else {
-                                       DEBUG(10, ("nt_printer_param_equal():"
-                                                  "data for %s differs\n", p1->value));
-                               }
-
-                               break;
-                       }
-
-                       q = q->next;
-               }
-
-               if (!found) {
-                       DEBUG(10, ("nt_printer_param_equal(): param %s "
-                                  "does not exist\n", p1->value));
-                       return False;
-               }
-
-               p1 = p1->next;
-       }
-
-       equal:
-
-       DEBUG(10, ("nt_printer_param_equal(): printer params identical\n"));
-       return True;
-}
-
-/********************************************************************
- * Called by update_printer when trying to work out whether to
- * actually update printer info.
- ********************************************************************/
-
-#define PI_CHECK_INT(field) \
-    if (pi1->field != pi2->field) { \
-        DEBUG(10, ("nt_printer_info_level_equal(): " #field " not equal (%d != %d)\n", \
-            pi1->field, pi2->field)); \
-        return False; \
-    }
-
-#define PI_CHECK_STR(field) \
-    if (!strequal(pi1->field, pi2->field)) { \
-        DEBUG(10, ("nt_printer_info_level_equal(): " #field " not equal (%s != %s)\n", \
-            pi1->field, pi2->field)); \
-        return False; \
-    }
-
-static BOOL nt_printer_info_level_equal(NT_PRINTER_INFO_LEVEL *p1,
-                                       NT_PRINTER_INFO_LEVEL *p2)
-{
-       NT_PRINTER_INFO_LEVEL_2 *pi1, *pi2;
-
-       /* Trivial conditions */
-
-       if ((!p1 && !p2) || (!p1->info_2 && !p2->info_2)) {
-               goto equal;
-       }
-
-       if ((!p1 && p2) || (p1 && !p2) ||
-           (!p1->info_2 && p2->info_2) ||
-           (p1->info_2 && !p2->info_2)) {
-               DEBUG(10, ("nt_printer_info_level_equal(): info levels "
-                          "differ\n"));
-               return False;
-       }
-
-       /* Compare two nt_printer_info_level structures.  Don't compare
-          status or cjobs as they seem to have something to do with the
-          printer queue. */
-
-       pi1 = p1->info_2;
-       pi2 = p2->info_2;
-
-       /* Don't check the attributes as we stomp on the value in
-          check_printer_ok() anyway. */
-
-#if 0
-       PI_CHECK_INT(attributes);
-#endif
-
-       PI_CHECK_INT(priority);
-       PI_CHECK_INT(default_priority);
-       PI_CHECK_INT(starttime);
-       PI_CHECK_INT(untiltime);
-       PI_CHECK_INT(averageppm);
-
-       /* Yuck - don't check the printername or servername as the
-          mod_a_printer() code plays games with them.  You can't
-          change the printername or the sharename through this interface
-          in Samba. */
-
-       PI_CHECK_STR(sharename);
-       PI_CHECK_STR(portname);
-       PI_CHECK_STR(drivername);
-       PI_CHECK_STR(comment);
-       PI_CHECK_STR(location);
-
-       if (!nt_devicemode_equal(pi1->devmode, pi2->devmode)) {
-               return False;
-       }
-
-       PI_CHECK_STR(sepfile);
-       PI_CHECK_STR(printprocessor);
-       PI_CHECK_STR(datatype);
-       PI_CHECK_STR(parameters);
-
-       if (!nt_printer_param_equal(pi1->specific, pi2->specific)) {
-               return False;
-       }
-
-       if (!sec_desc_equal(pi1->secdesc_buf->sec, pi2->secdesc_buf->sec)) {
-               return False;
-       }
-
-       PI_CHECK_INT(changeid);
-       PI_CHECK_INT(c_setprinter);
-       PI_CHECK_INT(setuptime);
-
- equal:
-       DEBUG(10, ("nt_printer_info_level_equal(): infos are identical\n"));
-       return True;
-}
-
-#endif
-
 /********************************************************************
  * Called by spoolss_api_setprinter
  * when updating a printer description.
@@ -7121,38 +6882,38 @@ WERROR _spoolss_getprinterdriverdirectory(pipes_struct *p, SPOOL_Q_GETPRINTERDRI
 WERROR _spoolss_enumprinterdata(pipes_struct *p, SPOOL_Q_ENUMPRINTERDATA *q_u, SPOOL_R_ENUMPRINTERDATA *r_u)
 {
        POLICY_HND *handle = &q_u->handle;
-       uint32 idx = q_u->index;
-       uint32 in_value_len = q_u->valuesize;
-       uint32 in_data_len = q_u->datasize;
-       uint32 *out_max_value_len = &r_u->valuesize;
-       uint16 **out_value = &r_u->value;
-       uint32 *out_value_len = &r_u->realvaluesize;
-       uint32 *out_type = &r_u->type;
+       uint32 idx               = q_u->index;
+       uint32 in_value_len      = q_u->valuesize;
+       uint32 in_data_len       = q_u->datasize;
+       uint32 *out_max_value_len= &r_u->valuesize;
+       uint16 **out_value       = &r_u->value;
+       uint32 *out_value_len    = &r_u->realvaluesize;
+       uint32 *out_type         = &r_u->type;
        uint32 *out_max_data_len = &r_u->datasize;
-       uint8  **data_out = &r_u->data;
-       uint32 *out_data_len = &r_u->realdatasize;
+       uint8  **data_out        = &r_u->data;
+       uint32 *out_data_len     = &r_u->realdatasize;
 
        NT_PRINTER_INFO_LEVEL *printer = NULL;
        
-       fstring value;
+       uint32          param_index;
+       uint32          biggest_valuesize;
+       uint32          biggest_datasize;
+       uint32          data_len;
+       Printer_entry   *Printer = find_printer_index_by_hnd(p, handle);
+       int             snum;
+       WERROR          result;
+       REGISTRY_VALUE  *val;
+       NT_PRINTER_DATA *p_data;
+       int             i, key_index, num_values;
+       int             name_length;
        
-       uint32 param_index;
-       uint32 biggest_valuesize;
-       uint32 biggest_datasize;
-       uint32 data_len;
-       Printer_entry *Printer = find_printer_index_by_hnd(p, handle);
-       int snum;
-       uint8 *data=NULL;
-       uint32 type;
-       WERROR result;
-
-       ZERO_STRUCT(printer);
+       ZERO_STRUCT( printer );
        
-       *out_type=0;
+       *out_type = 0;
 
-       *out_max_data_len=0;
-       *data_out=NULL;
-       *out_data_len=0;
+       *out_max_data_len = 0;
+       *data_out         = NULL;
+       *out_data_len     = 0;
 
        DEBUG(5,("spoolss_enumprinterdata\n"));
 
@@ -7167,103 +6928,133 @@ WERROR _spoolss_enumprinterdata(pipes_struct *p, SPOOL_Q_ENUMPRINTERDATA *q_u, S
        result = get_a_printer(&printer, 2, lp_servicename(snum));
        if (!W_ERROR_IS_OK(result))
                return result;
+               
+       p_data = &printer->info_2->data;        
+       key_index = lookup_printerkey( p_data, SPOOL_PRINTERDATA_KEY );
+
+       result = WERR_OK;
 
        /*
         * The NT machine wants to know the biggest size of value and data
         *
         * cf: MSDN EnumPrinterData remark section
         */
-       if ( (in_value_len==0) && (in_data_len==0) ) {
+        
+       if ( !in_value_len && !in_data_len ) 
+       {
                DEBUGADD(6,("Activating NT mega-hack to find sizes\n"));
 
-               SAFE_FREE(data);
-
-               param_index=0;
-               biggest_valuesize=0;
-               biggest_datasize=0;
+               param_index       = 0;
+               biggest_valuesize = 0;
+               biggest_datasize  = 0;
+                               
+               num_values = regval_ctr_numvals( &p_data->keys[key_index].values );
                
-               while (get_specific_param_by_index(*printer, 2, param_index, value, &data, &type, &data_len)) {
-                       if (strlen(value) > biggest_valuesize) biggest_valuesize=strlen(value);
-                       if (data_len > biggest_datasize) biggest_datasize=data_len;
-
-                       DEBUG(6,("current values: [%d], [%d]\n", biggest_valuesize, biggest_datasize));
-
-                       SAFE_FREE(data);
-                       param_index++;
+               for ( i=0; i<num_values; i++ )
+               {
+                       val = regval_ctr_specific_value( &p_data->keys[key_index].values, i );
+                       
+                       name_length = strlen(val->valuename);
+                       if ( strlen(val->valuename) > biggest_valuesize ) 
+                               biggest_valuesize = name_length;
+                               
+                       if ( val->size > biggest_datasize )
+                               biggest_datasize = val->size;
+                               
+                       DEBUG(6,("current values: [%d], [%d]\n", biggest_valuesize, 
+                               biggest_datasize));
                }
 
-               /* the value is an UNICODE string but realvaluesize is the length in bytes including the leading 0 */
-               *out_value_len=2*(1+biggest_valuesize);
-               *out_data_len=biggest_datasize;
+               /* the value is an UNICODE string but real_value_size is the length 
+                  in bytes including the trailing 0 */
+                  
+               *out_value_len = 2 * (1+biggest_valuesize);
+               *out_data_len  = biggest_datasize;
 
                DEBUG(6,("final values: [%d], [%d]\n", *out_value_len, *out_data_len));
 
-               free_a_printer(&printer, 2);
-               return WERR_OK;
+               goto done;
        }
        
        /*
         * the value len is wrong in NT sp3
         * that's the number of bytes not the number of unicode chars
         */
+        
+       val = regval_ctr_specific_value( &p_data->keys[key_index].values, idx );
 
-       if (!get_specific_param_by_index(*printer, 2, idx, value, &data, &type, &data_len)) {
-
-               SAFE_FREE(data);
-               free_a_printer(&printer, 2);
+       if ( !val ) 
+       {
 
                /* out_value should default to "" or else NT4 has
                   problems unmarshalling the response */
 
-               *out_max_value_len=(in_value_len/sizeof(uint16));
-               if((*out_value=(uint16 *)talloc_zero(p->mem_ctx, in_value_len*sizeof(uint8))) == NULL)
-                       return WERR_NOMEM;
+               *out_max_value_len = (in_value_len/sizeof(uint16));
+               
+               if ( (*out_value=(uint16 *)talloc_zero(p->mem_ctx, in_value_len*sizeof(uint8))) == NULL ) 
+               {
+                       result = WERR_NOMEM;
+                       goto done;
+               }
 
                *out_value_len = (uint32)rpcstr_push((char *)*out_value, "", in_value_len, 0);
 
                /* the data is counted in bytes */
+               
                *out_max_data_len = in_data_len;
-               *out_data_len = in_data_len;
-               if((*data_out=(uint8 *)talloc_zero(p->mem_ctx, in_data_len*sizeof(uint8))) == NULL)
-                       return WERR_NOMEM;
+               *out_data_len     = in_data_len;
+               
+               /* only allocate when given a non-zero data_len */
+               
+               if ( in_data_len && ((*data_out=(uint8 *)talloc_zero(p->mem_ctx, in_data_len*sizeof(uint8))) == NULL) )
+               {
+                       result = WERR_NOMEM;
+                       goto done;
+               }
 
-               return WERR_NO_MORE_ITEMS;
+               result = WERR_NO_MORE_ITEMS;
        }
-
-       free_a_printer(&printer, 2);
-
-       /*
-        * the value is:
-        * - counted in bytes in the request
-        * - counted in UNICODE chars in the max reply
-        * - counted in bytes in the real size
-        *
-        * take a pause *before* coding not *during* coding
-        */
+       else 
+       {
+               /*
+                * the value is:
+                * - counted in bytes in the request
+                * - counted in UNICODE chars in the max reply
+                * - counted in bytes in the real size
+                *
+                * take a pause *before* coding not *during* coding
+                */
        
-       *out_max_value_len=(in_value_len/sizeof(uint16));
-       if((*out_value=(uint16 *)talloc_zero(p->mem_ctx,in_value_len*sizeof(uint8))) == NULL) {
-               SAFE_FREE(data);
-               return WERR_NOMEM;
-       }
+               /* name */
+               *out_max_value_len = ( in_value_len / sizeof(uint16) );
+               if ( (*out_value = (uint16 *)talloc_zero(p->mem_ctx, in_value_len*sizeof(uint8))) == NULL ) 
+               {
+                       result = WERR_NOMEM;
+                       goto done;
+               }
        
-       *out_value_len = (uint32)rpcstr_push((char *)*out_value,value, in_value_len, 0);
+               *out_value_len = (uint32)rpcstr_push((char *)*out_value, regval_name(val), in_value_len, 0);
+
+               /* type */
+               
+               *out_type = regval_type( val );
 
-       *out_type=type;
+               /* data - counted in bytes */
 
-       /* the data is counted in bytes */
-       *out_max_data_len=in_data_len;
-       if((*data_out=(uint8 *)talloc_zero(p->mem_ctx, in_data_len*sizeof(uint8))) == NULL) {
-               SAFE_FREE(data);
-               return WERR_NOMEM;
+               *out_max_data_len = in_data_len;
+               if ( (*data_out = (uint8 *)talloc_zero(p->mem_ctx, in_data_len*sizeof(uint8))) == NULL) 
+               {
+                       result = WERR_NOMEM;
+                       goto done;
+               }
+               data_len = (size_t)regval_size(val);
+               memcpy( *data_out, regval_data_p(val), data_len );
+               *out_data_len = data_len;
        }
-       
-       memcpy(*data_out, data, (size_t)data_len);
-       *out_data_len=data_len;
 
-       SAFE_FREE(data);
-       
-       return WERR_OK;
+done:
+       free_a_printer(&printer, 2);
+       return result;
 }
 
 /****************************************************************************
@@ -7271,17 +7062,17 @@ WERROR _spoolss_enumprinterdata(pipes_struct *p, SPOOL_Q_ENUMPRINTERDATA *q_u, S
 
 WERROR _spoolss_setprinterdata( pipes_struct *p, SPOOL_Q_SETPRINTERDATA *q_u, SPOOL_R_SETPRINTERDATA *r_u)
 {
-       POLICY_HND *handle = &q_u->handle;
-       UNISTR2 *value = &q_u->value;
-       uint32 type = q_u->type;
-       uint8 *data = q_u->data;
-       uint32 real_len = q_u->real_len;
+       POLICY_HND              *handle = &q_u->handle;
+       UNISTR2                 *value = &q_u->value;
+       uint32                  type = q_u->type;
+       uint8                   *data = q_u->data;
+       uint32                  real_len = q_u->real_len;
 
-       NT_PRINTER_INFO_LEVEL *printer = NULL;
-       NT_PRINTER_PARAM *param = NULL, old_param;
-       int snum=0;
-       WERROR status = WERR_OK;
-       Printer_entry *Printer=find_printer_index_by_hnd(p, handle);
+       NT_PRINTER_INFO_LEVEL   *printer = NULL;
+       int                     snum=0;
+       WERROR                  status = WERR_OK;
+       Printer_entry           *Printer=find_printer_index_by_hnd(p, handle);
+       fstring                 valuename;
        
        DEBUG(5,("spoolss_setprinterdata\n"));
 
@@ -7293,8 +7084,6 @@ WERROR _spoolss_setprinterdata( pipes_struct *p, SPOOL_Q_SETPRINTERDATA *q_u, SP
        if (!get_printer_snum(p,handle, &snum))
                return WERR_BADFID;
 
-       ZERO_STRUCT(old_param);
-
        /* 
         * Access check : NT returns "access denied" if you make a 
         * SetPrinterData call without the necessary privildge.
@@ -7309,40 +7098,22 @@ WERROR _spoolss_setprinterdata( pipes_struct *p, SPOOL_Q_SETPRINTERDATA *q_u, SP
                goto done;
        }
 
-       /* Check if we are making any changes or not.  Return true if
-          nothing is actually changing.  This is not needed anymore but
-          has been left in as an optimization to keep from from
-          writing to disk as often  --jerry  */
-
        status = get_a_printer(&printer, 2, lp_servicename(snum));
        if (!W_ERROR_IS_OK(status))
                return status;
 
-       convert_specific_param(&param, value , type, data, real_len);
+       /* save the registry data */
+       
+       unistr2_to_ascii( valuename, value, sizeof(valuename)-1 );
+       delete_printer_data( printer->info_2, SPOOL_PRINTERDATA_KEY, valuename );
+       add_printer_data( printer->info_2, SPOOL_PRINTERDATA_KEY, valuename, type, data, real_len );
 
-       unlink_specific_param_if_exist(printer->info_2, param);
+       /* write the **entire** printer out to disk.... :-( */  
        
-       /*
-        * When client side code sets a magic printer data key, detect it and save
-        * the current printer data and the magic key's data (its the DEVMODE) for
-        * future printer/driver initializations.
-        */
-       if (param->type==3 && !strcmp( param->value, PHANTOM_DEVMODE_KEY)) {
-               /*
-                * Set devmode and printer initialization info
-                */
-               status = save_driver_init(printer, 2, param);
-       }
-       else {
-               add_a_specific_param(printer->info_2, &param);
-               status = mod_a_printer(*printer, 2);
-       }
+       status = mod_a_printer(*printer, 2);
 
- done:
+done:
        free_a_printer(&printer, 2);
-       if (param)
-               free_nt_printer_param(&param);
-       SAFE_FREE(old_param.data);
 
        return status;
 }
@@ -7352,9 +7123,9 @@ WERROR _spoolss_setprinterdata( pipes_struct *p, SPOOL_Q_SETPRINTERDATA *q_u, SP
 
 WERROR _spoolss_resetprinter(pipes_struct *p, SPOOL_Q_RESETPRINTER *q_u, SPOOL_R_RESETPRINTER *r_u)
 {
-       POLICY_HND *handle = &q_u->handle;
-       Printer_entry *Printer=find_printer_index_by_hnd(p, handle);
-       int snum;
+       POLICY_HND      *handle = &q_u->handle;
+       Printer_entry   *Printer=find_printer_index_by_hnd(p, handle);
+       int             snum;
        
        DEBUG(5,("_spoolss_resetprinter\n"));
 
@@ -7378,16 +7149,19 @@ WERROR _spoolss_resetprinter(pipes_struct *p, SPOOL_Q_RESETPRINTER *q_u, SPOOL_R
 }
 
 
+/****************************************************************************
+****************************************************************************/
+
 WERROR _spoolss_deleteprinterdata(pipes_struct *p, SPOOL_Q_DELETEPRINTERDATA *q_u, SPOOL_R_DELETEPRINTERDATA *r_u)
 {
-       POLICY_HND *handle = &q_u->handle;
-       UNISTR2 *value = &q_u->valuename;
+       POLICY_HND      *handle = &q_u->handle;
+       UNISTR2         *value = &q_u->valuename;
 
-       NT_PRINTER_INFO_LEVEL *printer = NULL;
-       NT_PRINTER_PARAM param;
-       int snum=0;
-       WERROR status = WERR_OK;
-       Printer_entry *Printer=find_printer_index_by_hnd(p, handle);
+       NT_PRINTER_INFO_LEVEL   *printer = NULL;
+       int             snum=0;
+       WERROR          status = WERR_OK;
+       Printer_entry   *Printer=find_printer_index_by_hnd(p, handle);
+       pstring         valuename;
        
        DEBUG(5,("spoolss_deleteprinterdata\n"));
        
@@ -7408,15 +7182,14 @@ WERROR _spoolss_deleteprinterdata(pipes_struct *p, SPOOL_Q_DELETEPRINTERDATA *q_
        if (!W_ERROR_IS_OK(status))
                return status;
 
-       ZERO_STRUCTP(&param);
-       unistr2_to_ascii(param.value, value, sizeof(param.value)-1);
+       unistr2_to_ascii( valuename, value, sizeof(valuename)-1 );
 
-       if(!unlink_specific_param_if_exist(printer->info_2, &param))
-               status = WERR_INVALID_PARAM;
-       else
+       status = delete_printer_data( printer->info_2, SPOOL_PRINTERDATA_KEY, valuename );
+       if ( NT_STATUS_IS_OK(status) )
                status = mod_a_printer(*printer, 2);
 
        free_a_printer(&printer, 2);
+
        return status;
 }
 
@@ -7426,7 +7199,6 @@ WERROR _spoolss_deleteprinterdata(pipes_struct *p, SPOOL_Q_DELETEPRINTERDATA *q_
 WERROR _spoolss_addform( pipes_struct *p, SPOOL_Q_ADDFORM *q_u, SPOOL_R_ADDFORM *r_u)
 {
        POLICY_HND *handle = &q_u->handle;
-/*     uint32 level = q_u->level; - notused. */
        FORM *form = &q_u->form;
        nt_forms_struct tmpForm;
        int snum;
@@ -8045,9 +7817,10 @@ WERROR _spoolss_getprinterdataex(pipes_struct *p, SPOOL_Q_GETPRINTERDATAEX *q_u,
                 * (a) DsDriver
                 * (b) DsSpooler
                 * (c) PnPData
+                * (d) DsUser
                 */
           
-               if (strcmp(key, "PrinterDriverData") != 0)
+               if (strcmp(key, SPOOL_PRINTERDATA_KEY) != 0)
                        return WERR_BADFILE;
 
                DEBUG(10, ("_spoolss_getprinterdataex: pass me to getprinterdata\n"));
@@ -8093,7 +7866,7 @@ WERROR _spoolss_setprinterdataex(pipes_struct *p, SPOOL_Q_SETPRINTERDATAEX *q_u,
 
         unistr2_to_ascii(key, &q_u->key, sizeof(key) - 1);
 
-        if (strcmp(key, "PrinterDriverData") != 0)
+        if (strcmp(key, SPOOL_PRINTERDATA_KEY) != 0)
                return WERR_INVALID_PARAM;
                
        ZERO_STRUCT(q_u_local); 
@@ -8128,7 +7901,7 @@ WERROR _spoolss_deleteprinterdataex(pipes_struct *p, SPOOL_Q_DELETEPRINTERDATAEX
 
         unistr2_to_ascii(key, &q_u->keyname, sizeof(key) - 1);
 
-        if (strcmp(key, "PrinterDriverData") != 0)
+        if (strcmp(key, SPOOL_PRINTERDATA_KEY) != 0)
                return WERR_INVALID_PARAM;
        
        memcpy(&q_u_local.handle, &q_u->handle, sizeof(POLICY_HND));
@@ -8153,7 +7926,7 @@ WERROR _spoolss_enumprinterkey(pipes_struct *p, SPOOL_Q_ENUMPRINTERKEY *q_u, SPO
        uint16  enumkeys[ENUMERATED_KEY_SIZE+1];
        char*   ptr = NULL;
        int     i;
-       char    *PrinterKey = "PrinterDriverData";
+       char    *PrinterKey = SPOOL_PRINTERDATA_KEY;
 
        DEBUG(4,("_spoolss_enumprinterkey\n"));
 
@@ -8222,7 +7995,7 @@ WERROR _spoolss_deleteprinterkey(pipes_struct *p, SPOOL_Q_DELETEPRINTERKEY *q_u,
        
         unistr2_to_ascii(key, &q_u->keyname, sizeof(key) - 1);
 
-        if (strcmp(key, "PrinterDriverData") != 0)
+        if (strcmp(key, SPOOL_PRINTERDATA_KEY) != 0)
                return WERR_INVALID_PARAM;
                
        /* 
@@ -8246,14 +8019,16 @@ WERROR _spoolss_enumprinterdataex(pipes_struct *p, SPOOL_Q_ENUMPRINTERDATAEX *q_
                        needed;
        NT_PRINTER_INFO_LEVEL   *printer = NULL;
        PRINTER_ENUM_VALUES     *enum_values = NULL;
-       fstring         key, value;
+       NT_PRINTER_DATA         *p_data;
+       fstring         key;
        Printer_entry   *Printer = find_printer_index_by_hnd(p, handle);
        int             snum;
-       uint32          param_index, 
-                       data_len,
-                       type;
        WERROR          result;
-       uint8           *data=NULL;
+       int             key_index;
+       int             i;
+       REGISTRY_VALUE  *val;
+       char            *value_name;
+       int             data_len;
        
 
        DEBUG(4,("_spoolss_enumprinterdataex\n"));
@@ -8264,20 +8039,8 @@ WERROR _spoolss_enumprinterdataex(pipes_struct *p, SPOOL_Q_ENUMPRINTERDATAEX *q_
        }
 
                
-        /* 
-        * The only key we support is "PrinterDriverData". This should return 
-        > an array of all the key/value pairs returned by EnumPrinterDataSee 
-        * _spoolss_getprinterdataex() for details    --jerry
-        */
-   
-       unistr2_to_ascii(key, &q_u->key, sizeof(key) - 1);
-       if (strcmp(key, "PrinterDriverData") != 0)
-       {
-               DEBUG(10,("_spoolss_enumprinterdataex: Unknown keyname [%s]\n", key));
-               return WERR_INVALID_PARAM;
-       }
-
-
+       /* first get the printer off of disk */
+       
        if (!get_printer_snum(p,handle, &snum))
                return WERR_BADFID;
        
@@ -8285,61 +8048,76 @@ WERROR _spoolss_enumprinterdataex(pipes_struct *p, SPOOL_Q_ENUMPRINTERDATAEX *q_
        result = get_a_printer(&printer, 2, lp_servicename(snum));
        if (!W_ERROR_IS_OK(result))
                return result;
-
        
-       /* 
-        * loop through all params and build the array to pass 
-        * back to the  client 
-        */
+       /* now look for a match on the key name */
+       
+       p_data = &printer->info_2->data;
+       
+       unistr2_to_ascii(key, &q_u->key, sizeof(key) - 1);
+       if ( (key_index = lookup_printerkey( p_data, key)) == -1  )
+       {
+               DEBUG(10,("_spoolss_enumprinterdataex: Unknown keyname [%s]\n", key));
+               result = WERR_INVALID_PARAM;
+               goto done;
+       }
+       
        result = WERR_OK;
-       param_index             = 0;
-       needed                  = 0;
-       num_entries             = 0;
+       needed = 0;
        
-       while (get_specific_param_by_index(*printer, 2, param_index, value, &data, &type, &data_len)) 
+       /* allocate the memory for the array of pointers -- if necessary */
+       
+       num_entries = regval_ctr_numvals( &p_data->keys[key_index].values );
+       if ( num_entries )
        {
-               PRINTER_ENUM_VALUES     *ptr;
-
-               DEBUG(10,("retrieved value number [%d] [%s]\n", num_entries, value));
-
-               if ((ptr=talloc_realloc(p->mem_ctx, enum_values, (num_entries+1) * sizeof(PRINTER_ENUM_VALUES))) == NULL)
+               if ( (enum_values=talloc(p->mem_ctx, num_entries*sizeof(PRINTER_ENUM_VALUES))) == NULL )
                {
-                       DEBUG(0,("talloc_realloc failed to allocate more memory!\n"));
+                       DEBUG(0,("_spoolss_enumprinterdataex: talloc() failed to allocate memory for [%d] bytes!\n",
+                               num_entries*sizeof(PRINTER_ENUM_VALUES)));
                        result = WERR_NOMEM;
                        goto done;
                }
-               enum_values = ptr;
+
+               memset( enum_values, 0x0, num_entries*sizeof(PRINTER_ENUM_VALUES) );
+       }
+               
+       /* 
+        * loop through all params and build the array to pass 
+        * back to the  client 
+        */
+        
+       for ( i=0; i<num_entries; i++ )
+       {
+               /* lookup the registry value */
                
-               ZERO_STRUCTP( &enum_values[num_entries] );
+               val = regval_ctr_specific_value( &p_data->keys[key_index].values, i );
+               DEBUG(10,("retrieved value number [%d] [%s]\n", i, regval_name(val) ));
 
                /* copy the data */
                
-               init_unistr(&enum_values[num_entries].valuename, value);
-               enum_values[num_entries].value_len = (strlen(value)+1) * 2;
-               enum_values[num_entries].type      = type;
+               value_name = regval_name( val );
+               init_unistr( &enum_values[i].valuename, value_name );
+               enum_values[i].value_len = (strlen(value_name)+1) * 2;
+               enum_values[i].type      = regval_type( val );
                
-               if ( data_len )
-               {
-                       if ( !(enum_values[num_entries].data = talloc_zero(p->mem_ctx, data_len)) ) {
-                               DEBUG(0,("talloc_realloc failed to allocate more memory [data_len=%d] for data!\n", data_len ));
+               data_len = regval_size( val );
+               if ( data_len ) {
+                       if ( !(enum_values[i].data = talloc_memdup(p->mem_ctx, regval_data_p(val), data_len)) ) 
+                       {
+                               DEBUG(0,("talloc_memdup failed to allocate memory [data_len=%d] for data!\n", 
+                                       data_len ));
                                result = WERR_NOMEM;
                                goto done;
                        }
-                       memcpy(enum_values[num_entries].data, data, data_len);
                }
-
-               enum_values[num_entries].data_len = data_len;
+               enum_values[i].data_len = data_len;
 
                /* keep track of the size of the array in bytes */
                
                needed += spoolss_size_printer_enum_values(&enum_values[num_entries]);
-               
-               num_entries++;
-               param_index++;
        }
        
-       r_u->needed             = needed;
-       r_u->returned           = num_entries;
+       r_u->needed     = needed;
+       r_u->returned   = num_entries;
 
        if (needed > in_size) {
                result = WERR_MORE_DATA;