Sync 3.0 branch with HEAD
authorJelmer Vernooij <jelmer@samba.org>
Sat, 17 Aug 2002 16:31:24 +0000 (16:31 +0000)
committerJelmer Vernooij <jelmer@samba.org>
Sat, 17 Aug 2002 16:31:24 +0000 (16:31 +0000)
(This used to be commit eac75549c398f208484ae735d5a5931fed6d0e99)

source3/printing/load.c
source3/printing/notify.c
source3/printing/nt_printing.c

index ed967fb0a7c64ca8a320e2ca5018163cd86166b4..cd90cbb6f33edfe7059c5ad39079376dab1a204b 100644 (file)
@@ -38,7 +38,7 @@ auto-load some homes and printer services
 ***************************************************************************/
 static void add_auto_printers(void)
 {
-       char *p;
+       const char *p;
        int printers;
        char *str = strdup(lp_auto_services());
 
@@ -47,9 +47,9 @@ static void add_auto_printers(void)
        printers = lp_servicenumber(PRINTERS_NAME);
 
        if (printers < 0) {
-        SAFE_FREE(str);
-        return;
-    }
+               SAFE_FREE(str);
+               return;
+       }
        
        for (p=strtok(str,LIST_SEP);p;p=strtok(NULL,LIST_SEP)) {
                if (lp_servicenumber(p) >= 0) continue;
index 21e28d0ca715a17af92c15a24bafe70468415b1e..925d49a21d6abaf4db43ae3fbff36f673cad341f 100644 (file)
@@ -3,6 +3,7 @@
    Version 2.2
    printing backend routines
    Copyright (C) Tim Potter, 2002
+   Copyright (C) Gerald Carter,         2002
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -65,18 +66,17 @@ again:
 
        /* Send message */
 
-       tdb = tdb_open_log(lock_path("connections.tdb"), 0, TDB_DEFAULT, O_RDONLY, 0);
+       tdb = conn_tdb_ctx();
 
        if (!tdb) {
                DEBUG(3, ("Failed to open connections database in send_spoolss_notify2_msg\n"));
-               return;
+               goto done;
        }
+       
+       message_send_all(tdb, MSG_PRINTER_NOTIFY2, buf, buflen, False, NULL);
 
-       message_send_all(tdb, MSG_PRINTER_NOTIFY2, buf,
-                        buflen, False, NULL);
-
+done:
        SAFE_FREE(buf);
-       tdb_close(tdb);
 }
 
 static void send_notify_field_values(const char *printer_name, uint32 type,
@@ -129,7 +129,7 @@ void notify_printer_status_byname(const char *printer_name, uint32 status)
 
 void notify_printer_status(int snum, uint32 status)
 {
-       const char *printer_name = PRINTERNAME(snum);
+       const char *printer_name = SERVICE(snum); 
 
        if (printer_name)
                notify_printer_status_byname(printer_name, status);
@@ -147,14 +147,14 @@ void notify_job_status_byname(const char *printer_name, uint32 jobid, uint32 sta
 
 void notify_job_status(int snum, uint32 jobid, uint32 status)
 {
-       const char *printer_name = PRINTERNAME(snum);
+       const char *printer_name = SERVICE(snum);
 
        notify_job_status_byname(printer_name, jobid, status, 0);
 }
 
 void notify_job_total_bytes(int snum, uint32 jobid, uint32 size)
 {
-       const char *printer_name = PRINTERNAME(snum);
+       const char *printer_name = SERVICE(snum);
 
        /* Job id stored in id field, status in value1 */
 
@@ -165,7 +165,7 @@ void notify_job_total_bytes(int snum, uint32 jobid, uint32 size)
 
 void notify_job_total_pages(int snum, uint32 jobid, uint32 pages)
 {
-       const char *printer_name = PRINTERNAME(snum);
+       const char *printer_name = SERVICE(snum);
 
        /* Job id stored in id field, status in value1 */
 
@@ -176,7 +176,7 @@ void notify_job_total_pages(int snum, uint32 jobid, uint32 pages)
 
 void notify_job_username(int snum, uint32 jobid, char *name)
 {
-       const char *printer_name = PRINTERNAME(snum);
+       const char *printer_name = SERVICE(snum);
 
        send_notify_field_buffer(
                printer_name, JOB_NOTIFY_TYPE, JOB_NOTIFY_USER_NAME,
@@ -185,7 +185,7 @@ void notify_job_username(int snum, uint32 jobid, char *name)
 
 void notify_job_name(int snum, uint32 jobid, char *name)
 {
-       const char *printer_name = PRINTERNAME(snum);
+       const char *printer_name = SERVICE(snum);
 
        send_notify_field_buffer(
                printer_name, JOB_NOTIFY_TYPE, JOB_NOTIFY_DOCUMENT,
@@ -194,37 +194,54 @@ void notify_job_name(int snum, uint32 jobid, char *name)
 
 void notify_job_submitted(int snum, uint32 jobid, time_t submitted)
 {
-       const char *printer_name = PRINTERNAME(snum);
+       const char *printer_name = SERVICE(snum);
 
        send_notify_field_buffer(
                printer_name, JOB_NOTIFY_TYPE, JOB_NOTIFY_SUBMITTED,
                jobid, sizeof(submitted), (char *)&submitted);
 }
 
-void notify_printer_delete(char *printer_name)
+void notify_printer_driver(int snum, char *driver_name)
 {
-}
+       const char *printer_name = SERVICE(snum);
 
-void notify_printer_add(char *printer_name)
-{
+       send_notify_field_buffer(
+               printer_name, PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_DRIVER_NAME,
+               snum, strlen(driver_name) + 1, driver_name);
 }
 
-void notify_printer_driver(int num, char *driver_name)
+void notify_printer_comment(int snum, char *comment)
 {
-}
+       const char *printer_name = SERVICE(snum);
 
-void notify_printer_comment(int num, char *comment)
-{
+       send_notify_field_buffer(
+               printer_name, PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_COMMENT,
+               snum, strlen(comment) + 1, comment);
 }
 
-void notify_printer_sharename(int num, char *share_name)
+void notify_printer_sharename(int snum, char *share_name)
 {
+       const char *printer_name = SERVICE(snum);
+
+       send_notify_field_buffer(
+               printer_name, PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_SHARE_NAME,
+               snum, strlen(share_name) + 1, share_name);
 }
 
-void notify_printer_port(int num, char *port_name)
+void notify_printer_port(int snum, char *port_name)
 {
+       const char *printer_name = SERVICE(snum);
+
+       send_notify_field_buffer(
+               printer_name, PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_PORT_NAME,
+               snum, strlen(port_name) + 1, port_name);
 }
 
-void notify_printer_location(int num, char *location)
+void notify_printer_location(int snum, char *location)
 {
+       const char *printer_name = SERVICE(snum);
+
+       send_notify_field_buffer(
+               printer_name, PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_LOCATION,
+               snum, strlen(location) + 1, location);
 }
index ff08b99eb0fbe996d8b01848c09a673abf1d23e9..3b85fce0200beba4cdf70d5f0ed767c28ff8dea9 100644 (file)
@@ -319,7 +319,17 @@ BOOL nt_printing_init(void)
         * register callback to handle updating printers as new
         * drivers are installed
         */
-       message_register(MSG_PRINTER_DRVUPGRADE, do_drv_upgrade_printer);
+
+       message_register( MSG_PRINTER_DRVUPGRADE, do_drv_upgrade_printer );
+
+       /*
+        * register callback to handle updating printer data
+        * when a driver is initialized
+        */
+
+       message_register( MSG_PRINTERDATA_INIT_RESET, reset_all_printerdata );
+
+
        return True;
 }
 
@@ -435,25 +445,29 @@ int get_ntforms(nt_forms_struct **list)
 
        for (kbuf = tdb_firstkey(tdb_forms);
             kbuf.dptr;
-            newkey = tdb_nextkey(tdb_forms, kbuf), safe_free(kbuf.dptr), kbuf=newkey) {
-               if (strncmp(kbuf.dptr, FORMS_PREFIX, strlen(FORMS_PREFIX)) != 0) continue;
+            newkey = tdb_nextkey(tdb_forms, kbuf), safe_free(kbuf.dptr), kbuf=newkey) 
+       {
+               if (strncmp(kbuf.dptr, FORMS_PREFIX, strlen(FORMS_PREFIX)) != 0) 
+                       continue;
                
                dbuf = tdb_fetch(tdb_forms, kbuf);
-               if (!dbuf.dptr) continue;
+               if (!dbuf.dptr) 
+                       continue;
 
                fstrcpy(form.name, kbuf.dptr+strlen(FORMS_PREFIX));
                ret = tdb_unpack(dbuf.dptr, dbuf.dsize, "dddddddd",
                                 &i, &form.flag, &form.width, &form.length, &form.left,
                                 &form.top, &form.right, &form.bottom);
                SAFE_FREE(dbuf.dptr);
-               if (ret != dbuf.dsize) continue;
+               if (ret != dbuf.dsize) 
+                       continue;
 
                tl = Realloc(*list, sizeof(nt_forms_struct)*(n+1));
                if (!tl) {
                        DEBUG(0,("get_ntforms: Realloc fail.\n"));
                        return 0;
                }
-        *list = tl;
+               *list = tl;
                (*list)[n] = form;
                n++;
        }
@@ -998,7 +1012,7 @@ static int file_version_is_newer(connection_struct *conn, fstring new_file,
        }
        close_file(fsp, True);
 
-       if (use_version) {
+       if (use_version && (new_major != old_major || new_minor != old_minor)) {
                /* Compare versions and choose the larger version number */
                if (new_major > old_major ||
                        (new_major == old_major && new_minor > old_minor)) {
@@ -1218,8 +1232,7 @@ static WERROR clean_up_driver_struct_level_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *dri
        
 /****************************************************************************
 ****************************************************************************/
-static WERROR clean_up_driver_struct_level_6(NT_PRINTER_DRIVER_INFO_LEVEL_6 *driver,
-                                                                                        struct current_user *user)
+static WERROR clean_up_driver_struct_level_6(NT_PRINTER_DRIVER_INFO_LEVEL_6 *driver, struct current_user *user)
 {
        fstring architecture;
        fstring new_name;
@@ -1274,8 +1287,7 @@ static WERROR clean_up_driver_struct_level_6(NT_PRINTER_DRIVER_INFO_LEVEL_6 *dri
         *      NT 4: cversion=2
         *      NT2K: cversion=3
         */
-       if ((driver->version = get_correct_cversion(architecture,
-                                                                       driver->driverpath, user, &err)) == -1)
+       if ((driver->version = get_correct_cversion(architecture, driver->driverpath, user, &err)) == -1)
                return err;
 
        return WERR_OK;
@@ -1747,7 +1759,8 @@ static WERROR get_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 **info_ptr,
                          driver.defaultdatatype);
 
        i=0;
-       while (len < dbuf.dsize) {
+       while (len < dbuf.dsize) 
+       {
                fstring *tddfs;
 
                tddfs = (fstring *)Realloc(driver.dependentfiles,
@@ -1762,13 +1775,15 @@ static WERROR get_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 **info_ptr,
                                  &driver.dependentfiles[i]);
                i++;
        }
+       
        if (driver.dependentfiles != NULL)
                fstrcpy(driver.dependentfiles[i], "");
 
        SAFE_FREE(dbuf.dptr);
 
-       if (len != dbuf.dsize) {
-                       SAFE_FREE(driver.dependentfiles);
+       if (len != dbuf.dsize) 
+       {
+               SAFE_FREE(driver.dependentfiles);
 
                return get_a_printer_driver_3_default(info_ptr, drivername, arch);
        }
@@ -1950,22 +1965,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;
 }
@@ -2059,7 +2104,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;
@@ -2098,89 +2143,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.
 ****************************************************************************/
@@ -2282,7 +2244,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);
 }
 
@@ -2292,23 +2254,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 );
 }
 
 
@@ -2388,32 +2356,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;
+}
 
-       *list = NULL;
+/****************************************************************************
+ 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;
 
-       while (1) {
-               len += tdb_unpack(buf+len, buflen-len, "p", &p);
-               if (!p) break;
+       DEBUG(12,("lookup_printerkey: Looking for [%s]\n", name));
 
+       /* 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;
+
+       /* 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));
-
-               DEBUG(8,("specific: [%s], len: %d\n", param.value, param.data_len));
+                                 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\\%s], len: %d\n", keyname, valuename, size));
        }
 
        return len;
 }
 
+/****************************************************************************
+ ***************************************************************************/
+
 static void map_to_os2_driver(fstring drivername)
 {
        static BOOL initialised=False;
@@ -2647,10 +2840,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);
 
@@ -2837,34 +3030,31 @@ 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;
 
+
+       ZERO_STRUCT(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);
-       }
-
-       ZERO_STRUCT(info);
-
+        
+       delete_all_printer_data( info_ptr );
+       
        slprintf(key, sizeof(key)-1, "%s%s", DRIVER_INIT_PREFIX, info_ptr->drivername);
 
        kbuf.dptr = key;
        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.
@@ -2872,16 +3062,18 @@ static BOOL set_driver_init_2(NT_PRINTER_INFO_LEVEL_2 *info_ptr)
                free_nt_devicemode(&info_ptr->devmode);
                return False;
        }
-
+       
        /*
         * Get the saved DEVMODE..
         */
+        
        len += unpack_devicemode(&info.devmode,dbuf.dptr+len, dbuf.dsize-len);
 
        /*
         * The saved DEVMODE contains the devicename from the printer used during
         * the initialization save. Change it to reflect the new printer.
         */
+        
        ZERO_STRUCT(info.devmode->devicename);
        fstrcpy(info.devmode->devicename, info_ptr->printername);
 
@@ -2897,45 +3089,20 @@ static BOOL set_driver_init_2(NT_PRINTER_INFO_LEVEL_2 *info_ptr)
         * --jerry
         */
 
-#if 1  /* JERRY */
 
-       /* 
-        *      Bind the saved DEVMODE to the new the printer.
-        */
+       /* Bind the saved DEVMODE to the new the printer */
+        
        free_nt_devicemode(&info_ptr->devmode);
        info_ptr->devmode = info.devmode;
-#else
-       /* copy the entire devmode if we currently don't have one */
-
-       if (!info_ptr->devmode) {
-               DEBUG(10,("set_driver_init_2: Current Devmode is NULL.  Copying entire Device Mode\n"));
-               info_ptr->devmode = info.devmode;
-       }
-       else {
-               /* only set the necessary fields */
 
-               DEBUG(10,("set_driver_init_2: Setting driverversion [0x%x] and private data [0x%x]\n",
-                       info.devmode->driverversion, info.devmode->driverextra));
-
-               info_ptr->devmode->driverversion = info.devmode->driverversion;
-
-               SAFE_FREE(info_ptr->devmode->private);
-               info_ptr->devmode->private = NULL;
-
-               if (info.devmode->driverversion)
-                       info_ptr->devmode->private = memdup(info.devmode->private, info.devmode->driverversion);
-
-               free_nt_devicemode(&info.devmode);
-       }
-#endif
 
        DEBUG(10,("set_driver_init_2: Set printer [%s] init DEVMODE for driver [%s]\n",
                        info_ptr->printername, info_ptr->drivername));
 
-       /* 
-        * Add the printer data 'specifics' to the new printer
-        */
-       len += unpack_specifics(&info_ptr->specific,dbuf.dptr+len, dbuf.dsize-len);
+       /* Add the printer data 'values' to the new printer */
+        
+       len += unpack_values( &info_ptr->data, dbuf.dptr+len, dbuf.dsize-len );
+       
 
        SAFE_FREE(dbuf.dptr);
 
@@ -2956,7 +3123,7 @@ BOOL set_driver_init(NT_PRINTER_INFO_LEVEL *printer, uint32 level)
        switch (level)
        {
                case 2:
-                       result=set_driver_init_2(printer->info_2);
+                       result = set_driver_init_2(printer->info_2);
                        break;
                        
                default:
@@ -2993,7 +3160,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
@@ -3014,7 +3181,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;
@@ -3045,14 +3212,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)
@@ -3076,154 +3243,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.
 ****************************************************************************/
@@ -3752,7 +3771,7 @@ static WERROR delete_printer_driver_internal( NT_PRINTER_DRIVER_INFO_LEVEL_3 *i,
 {
        pstring         key;
        fstring         arch;
-       TDB_DATA        kbuf;
+       TDB_DATA        kbuf, dbuf;
        NT_PRINTER_DRIVER_INFO_LEVEL    ctr;
 
        /* delete the tdb data first */
@@ -3770,8 +3789,20 @@ static WERROR delete_printer_driver_internal( NT_PRINTER_DRIVER_INFO_LEVEL_3 *i,
        kbuf.dptr=key;
        kbuf.dsize=strlen(key)+1;
 
+       /* check if the driver actually exists for this environment */
+       
+       dbuf = tdb_fetch( tdb_drivers, kbuf );
+       if ( !dbuf.dptr ) {
+               DEBUG(8,("delete_printer_driver_internal: Driver unknown [%s]\n", key));
+               return WERR_UNKNOWN_PRINTER_DRIVER;
+       }
+               
+       SAFE_FREE( dbuf.dptr );
+       
+       /* ok... the driver exists so the delete should return success */
+               
        if (tdb_delete(tdb_drivers, kbuf) == -1) {
-               DEBUG (0,("delete_printer_driver: fail to delete %s!\n", key));
+               DEBUG (0,("delete_printer_driver_internal: fail to delete %s!\n", key));
                return WERR_ACCESS_DENIED;
        }
 
@@ -3784,8 +3815,8 @@ static WERROR delete_printer_driver_internal( NT_PRINTER_DRIVER_INFO_LEVEL_3 *i,
        if ( delete_files )
                delete_driver_files( i, user );
 
-       DEBUG(5,("delete_printer_driver: [%s] driver delete successful.\n",
-               i->name));
+
+       DEBUG(5,("delete_printer_driver_internal: driver delete successful [%s]\n", key));
 
        return WERR_OK;
 }
@@ -3798,99 +3829,33 @@ static WERROR delete_printer_driver_internal( NT_PRINTER_DRIVER_INFO_LEVEL_3 *i,
 WERROR delete_printer_driver( NT_PRINTER_DRIVER_INFO_LEVEL_3 *i, struct current_user *user,
                               uint32 version, BOOL delete_files )
 {
-       int ver;
        WERROR err;
 
-       /* see if we should delete all versions of this driver */
+       /*
+        * see if we should delete all versions of this driver 
+        * (DRIVER_ANY_VERSION uis only set for "Windows NT x86")
+        */
 
-       if ( version == DRIVER_ANY_VERSION ) {
-               for ( ver=0; ver<DRIVER_MAX_VERSION; ver++ ) {
-                       err = delete_printer_driver_internal(i, user, ver, delete_files );
-                       if ( !W_ERROR_IS_OK(err) )
+       if ( version == DRIVER_ANY_VERSION ) 
+       {
+               /* Windows NT 4.0 */
+               
+               err = delete_printer_driver_internal(i, user, 2, delete_files );
+               if ( !W_ERROR_IS_OK(err) && (W_ERROR_V(err) != ERRunknownprinterdriver ) )
+                       return err;
+                       
+               /* Windows 2000/XP  */
+               
+               err = delete_printer_driver_internal(i, user, 3, delete_files );
+               if ( !W_ERROR_IS_OK(err) && (W_ERROR_V(err) != ERRunknownprinterdriver ) )
                                return err;
-               }
-       }
-       else
-               delete_printer_driver_internal(i, user, version, delete_files );
 
        return WERR_OK;
-}
-
-
-/****************************************************************************
-****************************************************************************/
-
-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;
-       }
+       /* just delete what they asked for */
        
-       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);
+       return delete_printer_driver_internal(i, user, version, delete_files );
 }
 
 /****************************************************************************
@@ -4328,76 +4293,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 */