Doxygen janitor: add note that strequal is in fact case-insensitive.
[samba.git] / source3 / rpc_server / srv_spoolss_nt.c
index 6953ec366313ca47b3ae509fbed3e6edae4e4ece..4006d0c08e929967e207e090fef7d53d5d7046c1 100644 (file)
@@ -5,7 +5,7 @@
  *  Copyright (C) Luke Kenneth Casson Leighton 1996-2000,
  *  Copyright (C) Jean François Micouleau      1998-2000,
  *  Copyright (C) Jeremy Allison               2001-2002,
- *  Copyright (C) Gerald Carter                       2000-2002,
+ *  Copyright (C) Gerald Carter                       2000-2003,
  *  Copyright (C) Tim Potter                   2001-2002.
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -30,7 +30,6 @@
 
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_RPC_SRV
-/* #define EMULATE_WIN2K_HACK  1 */
 
 #ifndef MAX_OPEN_PRINTER_EXS
 #define MAX_OPEN_PRINTER_EXS 50
 
 #define MAGIC_DISPLAY_FREQUENCY 0xfade2bad
 #define PHANTOM_DEVMODE_KEY "_p_f_a_n_t_0_m_"
-#define PRINTER_HANDLE_IS_PRINTER      0
-#define PRINTER_HANDLE_IS_PRINTSERVER  1
+
 
 /* Table to map the driver version */
 /* to OS */
-char * drv_ver_to_os[] = {
+static const char * drv_ver_to_os[] = {
        "WIN9X",   /* driver version/cversion 0 */
        "",        /* unused ? */
        "WINNT",   /* driver version/cversion 2 */
@@ -51,48 +49,11 @@ char * drv_ver_to_os[] = {
 };
 
 struct table_node {
-       char    *long_archi;
-       char    *short_archi;
+       const char    *long_archi;
+       const char    *short_archi;
        int     version;
 };
 
-
-/* structure to store the printer handles */
-/* and a reference to what it's pointing to */
-/* and the notify info asked about */
-/* that's the central struct */
-typedef struct _Printer{
-       struct _Printer *prev, *next;
-       BOOL document_started;
-       BOOL page_started;
-       uint32 jobid; /* jobid in printing backend */
-       BOOL printer_type;
-       union {
-               fstring handlename;
-               fstring printerservername;
-       } dev;
-       uint32 type;
-       uint32 access_granted;
-       struct {
-               uint32 flags;
-               uint32 options;
-               fstring localmachine;
-               uint32 printerlocal;
-               SPOOL_NOTIFY_OPTION *option;
-               POLICY_HND client_hnd;
-               uint32 client_connected;
-               uint32 change;
-       } notify;
-       struct {
-               fstring machine;
-               fstring user;
-       } client;
-       
-       /* devmode sent in the OpenPrinter() call */
-       NT_DEVICEMODE   *nt_devmode;
-       
-} Printer_entry;
-
 static Printer_entry *printers_list;
 
 typedef struct _counter_printer_0 {
@@ -178,10 +139,18 @@ static void free_spool_notify_option(SPOOL_NOTIFY_OPTION **pp)
  Disconnect from the client
 ****************************************************************************/
 
-static void srv_spoolss_replycloseprinter(POLICY_HND *handle)
+static void srv_spoolss_replycloseprinter(int snum, POLICY_HND *handle)
 {
        WERROR result;
 
+       /* 
+        * Tell the specific printing tdb we no longer want messages for this printer
+        * by deregistering our PID.
+        */
+
+       if (!print_notify_deregister_pid(snum))
+               DEBUG(0,("print_notify_register_pid: Failed to register our pid for printer %s\n", lp_const_servicename(snum) ));
+
        /* weird if the test succeds !!! */
        if (smb_connections==0) {
                DEBUG(0,("srv_spoolss_replycloseprinter:Trying to close non-existant notify backchannel !\n"));
@@ -218,8 +187,19 @@ static void free_printer_entry(void *ptr)
 {
        Printer_entry *Printer = (Printer_entry *)ptr;
 
-       if (Printer->notify.client_connected==True)
-               srv_spoolss_replycloseprinter(&Printer->notify.client_hnd);
+       if (Printer->notify.client_connected==True) {
+               int snum = -1;
+
+               if ( Printer->printer_type == PRINTER_HANDLE_IS_PRINTSERVER) {
+                       snum = -1;
+                       srv_spoolss_replycloseprinter(snum, &Printer->notify.client_hnd);
+               } else if (Printer->printer_type == PRINTER_HANDLE_IS_PRINTER) {
+                       snum = print_queue_snum(Printer->dev.handlename);
+                       if (snum != -1)
+                               srv_spoolss_replycloseprinter(snum,
+                                               &Printer->notify.client_hnd);
+               }
+       }
 
        Printer->notify.flags=0;
        Printer->notify.options=0;
@@ -230,6 +210,9 @@ static void free_printer_entry(void *ptr)
        Printer->notify.client_connected=False;
        
        free_nt_devicemode( &Printer->nt_devmode );
+       free_a_printer( &Printer->printer_info, 2 );
+       
+       talloc_destroy( Printer->ctx );
 
        /* Remove from the internal list. */
        DLIST_REMOVE(printers_list, Printer);
@@ -241,7 +224,7 @@ static void free_printer_entry(void *ptr)
  Functions to duplicate a SPOOL_NOTIFY_OPTION struct stored in Printer_entry.
 ****************************************************************************/
 
-SPOOL_NOTIFY_OPTION *dup_spool_notify_option(SPOOL_NOTIFY_OPTION *sp)
+static SPOOL_NOTIFY_OPTION *dup_spool_notify_option(SPOOL_NOTIFY_OPTION *sp)
 {
        SPOOL_NOTIFY_OPTION *new_sp = NULL;
 
@@ -282,6 +265,29 @@ static Printer_entry *find_printer_index_by_hnd(pipes_struct *p, POLICY_HND *hnd
        return find_printer;
 }
 
+/****************************************************************************
+  find printer index by handle
+****************************************************************************/
+
+void invalidate_printer_hnd_cache( char *printername )
+{
+       Printer_entry *p;
+       
+       DEBUG(10,("invalidate_printer_hnd_cache: printer [%s]\n", printername));
+
+       for ( p=printers_list; p; p=p->next )
+       {
+               if ( p->printer_type==PRINTER_HANDLE_IS_PRINTER 
+                       && StrCaseCmp(p->dev.handlename, printername)==0)
+               {
+                       DEBUG(10,("invalidating printer_info cache for handl:\n"));
+                       free_a_printer( &p->printer_info, 2 );
+                       p->printer_info = NULL;
+               }
+       }
+
+       return;
+}
 /****************************************************************************
  Close printer index by handle.
 ****************************************************************************/
@@ -313,11 +319,19 @@ static WERROR delete_printer_handle(pipes_struct *p, POLICY_HND *hnd)
                return WERR_BADFID;
        }
 
-       if (del_a_printer(Printer->dev.handlename) != 0) {
-               DEBUG(3,("Error deleting printer %s\n", Printer->dev.handlename));
-               return WERR_BADFID;
+       /* 
+        * It turns out that Windows allows delete printer on a handle
+        * opened by an admin user, then used on a pipe handle created
+        * by an anonymous user..... but they're working on security.... riiight !
+        * JRA.
+        */
+
+       if (Printer->access_granted != PRINTER_ACCESS_ADMINISTER) {
+               DEBUG(3, ("delete_printer_handle: denied by handle\n"));
+               return WERR_ACCESS_DENIED;
        }
 
+#if 0
        /* Check calling user has permission to delete printer.  Note that
           since we set the snum parameter to -1 only administrators can
           delete the printer.  This stops people with the Full Control
@@ -327,6 +341,12 @@ static WERROR delete_printer_handle(pipes_struct *p, POLICY_HND *hnd)
                DEBUG(3, ("printer delete denied by security descriptor\n"));
                return WERR_ACCESS_DENIED;
        }
+#endif
+
+       if (del_a_printer(Printer->dev.handlename) != 0) {
+               DEBUG(3,("Error deleting printer %s\n", Printer->dev.handlename));
+               return WERR_BADFID;
+       }
 
        if (*lp_deleteprinter_cmd()) {
 
@@ -349,10 +369,10 @@ static WERROR delete_printer_handle(pipes_struct *p, POLICY_HND *hnd)
                /* Send SIGHUP to process group... is there a better way? */
                kill(0, SIGHUP);
 
-               if ( ( i = lp_servicenumber( Printer->dev.handlename ) ) >= 0 ) {
-                       lp_killservice( i );
-                       return WERR_OK;
-               } else
+               /* go ahead and re-read the services immediately */
+               reload_services( False );
+
+               if ( ( i = lp_servicenumber( Printer->dev.handlename ) ) < 0 )
                        return WERR_ACCESS_DENIED;
        }
 
@@ -499,6 +519,11 @@ static BOOL open_printer_hnd(pipes_struct *p, POLICY_HND *hnd, char *name, uint3
 
        ZERO_STRUCTP(new_printer);
        
+       if ( !(new_printer->ctx = talloc_init("Printer Entry [0x%x]", (uint32)hnd)) ) {
+               DEBUG(0,("open_printer_hnd: talloc_init() failed!\n"));
+               return False;
+       }
+       
        new_printer->notify.option=NULL;
                                
        /* Add to the internal list. */
@@ -580,7 +605,7 @@ static BOOL is_monitoring_event(Printer_entry *p, uint16 notify_type,
 
        /* 
         * Flags should always be zero when the change notify
-        * is registered by the cliebnt's spooler.  A user Win32 app
+        * is registered by the client's spooler.  A user Win32 app
         * might use the flags though instead of the NOTIFY_OPTION_INFO 
         * --jerry
         */
@@ -662,7 +687,7 @@ static void notify_system_time(struct spoolss_notify_msg *msg,
                return;
        }
 
-       if (!make_systemtime(&systime, localtime((time_t *)msg->notify.data))) {
+       if (!make_systemtime(&systime, gmtime((time_t *)msg->notify.data))) {
                DEBUG(5, ("notify_system_time: unable to make systemtime\n"));
                return;
        }
@@ -671,16 +696,15 @@ static void notify_system_time(struct spoolss_notify_msg *msg,
                return;
 
        data->notify_data.data.length = prs_offset(&ps);
-       data->notify_data.data.string =
-               talloc(mem_ctx, prs_offset(&ps));
+       data->notify_data.data.string = talloc(mem_ctx, prs_offset(&ps));
 
-       memcpy(data->notify_data.data.string, prs_data_p(&ps), prs_offset(&ps));
+       prs_copy_all_data_out((char *)data->notify_data.data.string, &ps);
 
        prs_mem_free(&ps);
 }
 
 struct notify2_message_table {
-       char *name;
+       const char *name;
        void (*fn)(struct spoolss_notify_msg *msg,
                   SPOOL_NOTIFY_INFO_DATA *data, TALLOC_CTX *mem_ctx);
 };
@@ -744,7 +768,7 @@ static void notify_msg_ctr_init( SPOOLSS_NOTIFY_MSG_CTR *ctr )
        if ( !ctr )
                return;
 
-       ctr->ctx = talloc_init();
+       ctr->ctx = talloc_init("notify_msg_ctr_init %p", ctr);
                
        return;
 }
@@ -827,8 +851,7 @@ static int notify_msg_ctr_addmsg( SPOOLSS_NOTIFY_MSG_CTR *ctr, SPOOLSS_NOTIFY_MS
        
        /* add a new group? */
        
-       if ( i == ctr->num_groups )
-       {
+       if ( i == ctr->num_groups ) {
                ctr->num_groups++;
 
                if ( !(groups = talloc_realloc( ctr->ctx, ctr->msg_groups, sizeof(SPOOLSS_NOTIFY_MSG_GROUP)*ctr->num_groups)) ) {
@@ -895,12 +918,11 @@ static void send_notify2_changes( SPOOLSS_NOTIFY_MSG_CTR *ctr, uint32 idx )
        
        /* loop over all printers */
        
-       for (p = printers_list; p; p = p->next) 
-       {
+       for (p = printers_list; p; p = p->next) {
                SPOOL_NOTIFY_INFO_DATA *data;
                uint32  data_len = 0;
                uint32  id;
-               int     i;
+               int     i, event_index;
 
                /* Is there notification on this handle? */
 
@@ -923,67 +945,63 @@ static void send_notify2_changes( SPOOLSS_NOTIFY_MSG_CTR *ctr, uint32 idx )
                data = talloc( mem_ctx, msg_group->num_msgs*sizeof(SPOOL_NOTIFY_INFO_DATA) );
                ZERO_STRUCTP(data);
                
+               event_index = 0;
+               
                /* build the array of change notifications */
                
-               for ( i=0; i<msg_group->num_msgs; i++ )
-               {
+               for ( i=0; i<msg_group->num_msgs; i++ ) {
                        SPOOLSS_NOTIFY_MSG      *msg = &messages[i];
                        
-               /* Are we monitoring this event? */
+                       /* Are we monitoring this event? */
 
-               if (!is_monitoring_event(p, msg->type, msg->field))
-                       continue;
+                       if (!is_monitoring_event(p, msg->type, msg->field))
+                               continue;
 
                        
-               DEBUG(10,("process_notify2_message: Sending message type [%x] field [%x] for printer [%s]\n",
-                       msg->type, msg->field, p->dev.handlename));
+                       DEBUG(10,("process_notify2_message: Sending message type [%x] field [%x] for printer [%s]\n",
+                               msg->type, msg->field, p->dev.handlename));
 
-               /* 
-                * if the is a printer notification handle and not a job notification 
-                * type, then set the id to 0.  Other wise just use what was specified
-                * in the message.  
-                *
-                * When registering change notification on a print server handle 
-                * we always need to send back the id (snum) matching the printer
-                * for which the change took place.  For change notify registered
-                * on a printer handle, this does not matter and the id should be 0.
-                *
-                * --jerry
-                */
+                       /* 
+                        * if the is a printer notification handle and not a job notification 
+                        * type, then set the id to 0.  Other wise just use what was specified
+                        * in the message.  
+                        *
+                        * When registering change notification on a print server handle 
+                        * we always need to send back the id (snum) matching the printer
+                        * for which the change took place.  For change notify registered
+                        * on a printer handle, this does not matter and the id should be 0.
+                        *
+                        * --jerry
+                        */
 
-               if ( ( p->printer_type == PRINTER_HANDLE_IS_PRINTER ) && ( msg->type == PRINTER_NOTIFY_TYPE ) )
-                       id = 0;
-               else
-               id = msg->id;
+                       if ( ( p->printer_type == PRINTER_HANDLE_IS_PRINTER ) && ( msg->type == PRINTER_NOTIFY_TYPE ) )
+                               id = 0;
+                       else
+                               id = msg->id;
 
 
-               /* Convert unix jobid to smb jobid */
+                       /* Convert unix jobid to smb jobid */
 
-                       if (msg->flags & SPOOLSS_NOTIFY_MSG_UNIX_JOBID) 
-                       {
-                       id = sysjob_to_jobid(msg->id);
+                       if (msg->flags & SPOOLSS_NOTIFY_MSG_UNIX_JOBID) {
+                               id = sysjob_to_jobid(msg->id);
 
-                       if (id == -1) {
-                               DEBUG(3, ("no such unix jobid %d\n", msg->id));
-                               goto done;
+                               if (id == -1) {
+                                       DEBUG(3, ("no such unix jobid %d\n", msg->id));
+                                       goto done;
+                               }
                        }
-               }
 
                        construct_info_data( &data[data_len], msg->type, msg->field, id );
 
-               switch(msg->type) {
-               case PRINTER_NOTIFY_TYPE:
-                               if ( !printer_notify_table[msg->field].fn )
-                               goto done;
+                       switch(msg->type) {
+                       case PRINTER_NOTIFY_TYPE:
+                               if ( printer_notify_table[msg->field].fn )
                                        printer_notify_table[msg->field].fn(msg, &data[data_len], mem_ctx);
-                               
-                       break;
+                               break;
                        
-               case JOB_NOTIFY_TYPE:
-                               if ( !job_notify_table[msg->field].fn )
-                               goto done;
+                       case JOB_NOTIFY_TYPE:
+                               if ( job_notify_table[msg->field].fn )
                                        job_notify_table[msg->field].fn(msg, &data[data_len], mem_ctx);
-
                                break;
 
                        default:
@@ -1009,7 +1027,7 @@ done:
 static BOOL notify2_unpack_msg( SPOOLSS_NOTIFY_MSG *msg, void *buf, size_t len )
 {
 
-       int offset = 0;
+       size_t offset = 0;
 
        /* Unpack message */
 
@@ -1172,7 +1190,7 @@ void do_drv_upgrade_printer(int msg_type, pid_t src, void *buf, size_t len)
                        WERROR result;
                        NT_PRINTER_INFO_LEVEL *printer = NULL;
                        
-                       result = get_a_printer(&printer, 2, lp_servicename(snum));
+                       result = get_a_printer(NULL, &printer, 2, lp_const_servicename(snum));
                        if (!W_ERROR_IS_OK(result))
                                continue;
                                
@@ -1196,6 +1214,32 @@ void do_drv_upgrade_printer(int msg_type, pid_t src, void *buf, size_t len)
        /* all done */  
 }
 
+/********************************************************************
+ Update the cahce for all printq's with a registered client 
+ connection
+ ********************************************************************/
+
+void update_monitored_printq_cache( void )
+{
+       Printer_entry *printer = printers_list;
+       int snum;
+       
+       /* loop through all printers and update the cache where 
+          client_connected == True */
+       while ( printer ) 
+       {
+               if ( (printer->printer_type == PRINTER_HANDLE_IS_PRINTER) 
+                       && printer->notify.client_connected ) 
+               {
+                       snum = print_queue_snum(printer->dev.handlename);
+                       print_queue_status( snum, NULL, NULL );
+               }
+               
+               printer = printer->next;
+       }
+       
+       return;
+}
 /********************************************************************
  Send a message to ourself about new driver being installed
  so we can upgrade the information for each printer bound to this
@@ -1242,7 +1286,7 @@ void reset_all_printerdata(int msg_type, pid_t src, void *buf, size_t len)
                        WERROR result;
                        NT_PRINTER_INFO_LEVEL *printer = NULL;
                        
-                       result = get_a_printer( &printer, 2, lp_servicename(snum) );
+                       result = get_a_printer( NULL, &printer, 2, lp_const_servicename(snum) );
                        if ( !W_ERROR_IS_OK(result) )
                                continue;
                                
@@ -1259,6 +1303,12 @@ void reset_all_printerdata(int msg_type, pid_t src, void *buf, size_t len)
                                        DEBUG(5,("reset_all_printerdata: Error resetting printer data for printer [%s], driver [%s]!\n",
                                                printer->info_2->printername, printer->info_2->drivername));
                                }       
+                               
+                               result = mod_a_printer( *printer, 2 );
+                               if ( !W_ERROR_IS_OK(result) ) {
+                                       DEBUG(3,("reset_all_printerdata: mod_a_printer() failed!  (%s)\n", 
+                                               get_dos_error_msg(result)));
+                               }
                        }
                        
                        free_a_printer( &printer, 2 );
@@ -1542,7 +1592,7 @@ Can't find printer handle we created for printer %s\n", name ));
                        /* if the user is not root and not a printer admin, then fail */
                        
                        if ( user.uid != 0
-                            && !user_in_list(uidtoname(user.uid), lp_printer_admin(snum)) )
+                            && !user_in_list(uidtoname(user.uid), lp_printer_admin(snum), user.groups, user.ngroups) )
                        {
                                close_printer_handle(p, handle);
                                return WERR_ACCESS_DENIED;
@@ -1589,7 +1639,7 @@ Can't find printer handle we created for printer %s\n", name ));
 
                /* check smb.conf parameters and the the sec_desc */
                
-               if (!user_ok(uidtoname(user.uid), snum) || !print_access_check(&user, snum, printer_default->access_required)) {
+               if (!user_ok(uidtoname(user.uid), snum, user.groups, user.ngroups) || !print_access_check(&user, snum, printer_default->access_required)) {
                        DEBUG(3, ("access DENIED for printer open\n"));
                        close_printer_handle(p, handle);
                        return WERR_ACCESS_DENIED;
@@ -1625,6 +1675,12 @@ Can't find printer handle we created for printer %s\n", name ));
                        &Printer->nt_devmode );
         }
 
+       /* HACK ALERT!!! Sleep for 1/3 of a second to try trigger a LAN/WAN 
+          optimization in Windows 2000 clients  --jerry */
+
+       if ( RA_WIN2K == get_remote_arch() )
+               usleep( 384000 );
+
        return WERR_OK;
 }
 
@@ -1670,7 +1726,7 @@ static BOOL convert_printer_driver_info(const SPOOL_PRINTER_DRIVER_INFO_LEVEL *u
        return result;
 }
 
-BOOL convert_devicemode(char *printername, const DEVICEMODE *devmode,
+BOOL convert_devicemode(const char *printername, const DEVICEMODE *devmode,
                                NT_DEVICEMODE **pp_nt_devmode)
 {
        NT_DEVICEMODE *nt_devmode = *pp_nt_devmode;
@@ -1879,6 +1935,12 @@ WERROR _spoolss_deleteprinterdriver(pipes_struct *p, SPOOL_Q_DELETEPRINTERDRIVER
                                goto done;
                        }
                }
+               /* otherwise it was a failure */
+               else {
+                       status = WERR_UNKNOWN_PRINTER_DRIVER;
+                       goto done;
+               }
+               
        }
        
        if (printer_driver_in_use(info.info_3)) {
@@ -2041,7 +2103,7 @@ done:
  ***************************************************************************/
 
 static WERROR get_printer_dataex( TALLOC_CTX *ctx, NT_PRINTER_INFO_LEVEL *printer, 
-                                  char *key, char *value, uint32 *type, uint8 **data, 
+                                  const char *key, const char *value, uint32 *type, uint8 **data, 
                                  uint32 *needed, uint32 in_size  )
 {
        REGISTRY_VALUE          *val;
@@ -2060,8 +2122,16 @@ static WERROR get_printer_dataex( TALLOC_CTX *ctx, NT_PRINTER_INFO_LEVEL *printe
        
        if ( in_size ) {
                data_len = (size > in_size) ? in_size : size*sizeof(uint8);
-               if ( (*data  = (uint8 *)talloc_memdup(ctx, regval_data_p(val), data_len)) == NULL )
-                       return WERR_NOMEM;
+               
+               /* special case for 0 length values */
+               if ( data_len ) {
+                       if ( (*data  = (uint8 *)talloc_memdup(ctx, regval_data_p(val), data_len)) == NULL )
+                               return WERR_NOMEM;
+               }
+               else {
+                       if ( (*data  = (uint8 *)talloc_zero(ctx, in_size)) == NULL )
+                               return WERR_NOMEM;
+               }
        }
        else
                *data = NULL;
@@ -2077,25 +2147,21 @@ static WERROR get_printer_dataex( TALLOC_CTX *ctx, NT_PRINTER_INFO_LEVEL *printe
  Internal routine for removing printerdata
  ***************************************************************************/
 
-static WERROR delete_printer_dataex( NT_PRINTER_INFO_LEVEL *printer, char *key, char *value )
+static WERROR delete_printer_dataex( NT_PRINTER_INFO_LEVEL *printer, const char *key, const char *value )
 {
-       delete_printer_data( printer->info_2, key, value );
-       
-       return mod_a_printer(*printer, 2);
+       return delete_printer_data( printer->info_2, key, value );
 }
 
 /****************************************************************************
  Internal routine for storing printerdata
  ***************************************************************************/
 
-static WERROR set_printer_dataex( NT_PRINTER_INFO_LEVEL *printer, char *key, char *value, 
+static WERROR set_printer_dataex( NT_PRINTER_INFO_LEVEL *printer, const char *key, const char *value, 
                                   uint32 type, uint8 *data, int real_len  )
 {
        delete_printer_data( printer->info_2, key, value );
        
-       add_printer_data( printer->info_2, key, value, type, data, real_len );
-       
-       return mod_a_printer(*printer, 2);
+       return add_printer_data( printer->info_2, key, value, type, data, real_len );
 }
 
 /********************************************************************
@@ -2108,7 +2174,7 @@ static WERROR getprinterdata_printer_server(TALLOC_CTX *ctx, fstring value, uint
        
        DEBUG(8,("getprinterdata_printer_server:%s\n", value));
                
-       if (!strcmp(value, "W3SvcInstalled")) {
+       if (!StrCaseCmp(value, "W3SvcInstalled")) {
                *type = 0x4;
                if((*data = (uint8 *)talloc_zero(ctx, 4*sizeof(uint8) )) == NULL)
                        return WERR_NOMEM;
@@ -2116,7 +2182,7 @@ static WERROR getprinterdata_printer_server(TALLOC_CTX *ctx, fstring value, uint
                return WERR_OK;
        }
 
-       if (!strcmp(value, "BeepEnabled")) {
+       if (!StrCaseCmp(value, "BeepEnabled")) {
                *type = 0x4;
                if((*data = (uint8 *)talloc(ctx, 4*sizeof(uint8) )) == NULL)
                        return WERR_NOMEM;
@@ -2125,7 +2191,7 @@ static WERROR getprinterdata_printer_server(TALLOC_CTX *ctx, fstring value, uint
                return WERR_OK;
        }
 
-       if (!strcmp(value, "EventLog")) {
+       if (!StrCaseCmp(value, "EventLog")) {
                *type = 0x4;
                if((*data = (uint8 *)talloc(ctx, 4*sizeof(uint8) )) == NULL)
                        return WERR_NOMEM;
@@ -2135,7 +2201,7 @@ static WERROR getprinterdata_printer_server(TALLOC_CTX *ctx, fstring value, uint
                return WERR_OK;
        }
 
-       if (!strcmp(value, "NetPopup")) {
+       if (!StrCaseCmp(value, "NetPopup")) {
                *type = 0x4;
                if((*data = (uint8 *)talloc(ctx, 4*sizeof(uint8) )) == NULL)
                        return WERR_NOMEM;
@@ -2144,20 +2210,20 @@ static WERROR getprinterdata_printer_server(TALLOC_CTX *ctx, fstring value, uint
                return WERR_OK;
        }
 
-       if (!strcmp(value, "MajorVersion")) {
+       if (!StrCaseCmp(value, "MajorVersion")) {
                *type = 0x4;
                if((*data = (uint8 *)talloc(ctx, 4*sizeof(uint8) )) == NULL)
                        return WERR_NOMEM;
-#ifndef EMULATE_WIN2K_HACK /* JERRY */
-               SIVAL(*data, 0, 2);
-#else
+#ifdef HAVE_ADS
                SIVAL(*data, 0, 3);
+#else
+               SIVAL(*data, 0, 2);
 #endif
                *needed = 0x4;
                return WERR_OK;
        }
 
-       if (!strcmp(value, "DefaultSpoolDirectory")) {
+       if (!StrCaseCmp(value, "DefaultSpoolDirectory")) {
                fstring string;
 
                fstrcpy(string, string_truncate(lp_serverstring(), MAX_SERVER_STRING_LENGTH));
@@ -2175,7 +2241,7 @@ static WERROR getprinterdata_printer_server(TALLOC_CTX *ctx, fstring value, uint
                return WERR_OK;
        }
 
-       if (!strcmp(value, "Architecture")) {                   
+       if (!StrCaseCmp(value, "Architecture")) {                       
                pstring string="Windows NT x86";
                *type = 0x1;                    
                *needed = 2*(strlen(string)+1); 
@@ -2188,8 +2254,35 @@ static WERROR getprinterdata_printer_server(TALLOC_CTX *ctx, fstring value, uint
                }                       
                return WERR_OK;
        }
-       
-       return WERR_INVALID_PARAM;
+
+       if (!StrCaseCmp(value, "DsPresent")) {
+               *type = 0x4;
+               if((*data = (uint8 *)talloc(ctx, 4*sizeof(uint8) )) == NULL)
+                       return WERR_NOMEM;
+               SIVAL(*data, 0, 0x01);
+               *needed = 0x4;
+               return WERR_OK;
+       }
+
+       if (!StrCaseCmp(value, "DNSMachineName")) {                     
+               pstring hostname;
+               
+               if (!get_myfullname(hostname))
+                       return WERR_BADFILE;
+               *type = 0x1;                    
+               *needed = 2*(strlen(hostname)+1);       
+               if((*data  = (uint8 *)talloc(ctx, ((*needed > in_size) ? *needed:in_size) *sizeof(uint8))) == NULL)
+                       return WERR_NOMEM;
+               memset(*data, 0, (*needed > in_size) ? *needed:in_size);
+               for (i=0; i<strlen(hostname); i++) {
+                       (*data)[2*i]=hostname[i];
+                       (*data)[2*i+1]='\0';
+               }                       
+               return WERR_OK;
+       }
+
+
+       return WERR_BADFILE;
 }
 
 /********************************************************************
@@ -2244,11 +2337,24 @@ WERROR _spoolss_getprinterdata(pipes_struct *p, SPOOL_Q_GETPRINTERDATA *q_u, SPO
                        goto done;
                }
 
-               status = get_a_printer(&printer, 2, lp_servicename(snum));
+               status = get_a_printer(Printer, &printer, 2, lp_servicename(snum));
                if ( !W_ERROR_IS_OK(status) )
                        goto done;
-                       
-               status = get_printer_dataex( p->mem_ctx, printer, SPOOL_PRINTERDATA_KEY, value, type, data, needed, *out_size );
+
+               /* XP sends this and wants to change id value from the PRINTER_INFO_0 */
+
+               if ( strequal(value, "ChangeId") ) {
+                       *type = REG_DWORD;
+                       *needed = sizeof(uint32);
+                       if ( (*data = (uint8*)talloc(p->mem_ctx, sizeof(uint32))) == NULL) {
+                               status = WERR_NOMEM;
+                               goto done;
+                       }
+                       **data = printer->info_2->changeid;
+                       status = WERR_OK;
+               }
+               else
+                       status = get_printer_dataex( p->mem_ctx, printer, SPOOL_PRINTERDATA_KEY, value, type, data, needed, *out_size );
        }
 
        if (*needed > *out_size)
@@ -2257,7 +2363,7 @@ WERROR _spoolss_getprinterdata(pipes_struct *p, SPOOL_Q_GETPRINTERDATA *q_u, SPO
 done:
        if ( !W_ERROR_IS_OK(status) ) 
        {
-               DEBUG(5, ("error: allocating %d\n", *out_size));
+               DEBUG(5, ("error %d: allocating %d\n", W_ERROR_V(status),*out_size));
                
                /* reply this param doesn't exist */
                
@@ -2285,10 +2391,8 @@ done:
  Connect to the client machine.
 **********************************************************/
 
-static BOOL spoolss_connect_to_client(struct cli_state *the_cli, char *remote_machine)
+static BOOL spoolss_connect_to_client(struct cli_state *the_cli, const char *remote_machine)
 {
-       extern pstring global_myname;
-
        ZERO_STRUCTP(the_cli);
        if(cli_initialise(the_cli) == NULL) {
                DEBUG(0,("connect_to_client: unable to initialize client connection.\n"));
@@ -2313,7 +2417,7 @@ static BOOL spoolss_connect_to_client(struct cli_state *the_cli, char *remote_ma
                return False;
        }
   
-       if (!attempt_netbios_session_request(the_cli, global_myname, remote_machine, &the_cli->dest_ip)) {
+       if (!attempt_netbios_session_request(the_cli, global_myname(), remote_machine, &the_cli->dest_ip)) {
                DEBUG(0,("connect_to_client: machine %s rejected the NetBIOS session request.\n", 
                        remote_machine));
                cli_shutdown(the_cli);
@@ -2361,7 +2465,7 @@ static BOOL spoolss_connect_to_client(struct cli_state *the_cli, char *remote_ma
         * Now start the NT Domain stuff :-).
         */
 
-       if(cli_nt_session_open(the_cli, PIPE_SPOOLSS) == False) {
+       if(cli_nt_session_open(the_cli, PI_SPOOLSS) == False) {
                DEBUG(0,("connect_to_client: unable to open the domain client session to machine %s. Error was : %s.\n", remote_machine, cli_errstr(the_cli)));
                cli_nt_session_close(the_cli);
                cli_ulogoff(the_cli);
@@ -2376,7 +2480,7 @@ static BOOL spoolss_connect_to_client(struct cli_state *the_cli, char *remote_ma
  Connect to the client.
 ****************************************************************************/
 
-static BOOL srv_spoolss_replyopenprinter(char *printer, uint32 localprinter, uint32 type, POLICY_HND *handle)
+static BOOL srv_spoolss_replyopenprinter(int snum, const char *printer, uint32 localprinter, uint32 type, POLICY_HND *handle)
 {
        WERROR result;
 
@@ -2398,6 +2502,14 @@ static BOOL srv_spoolss_replyopenprinter(char *printer, uint32 localprinter, uin
                register_message_flags( True, FLAG_MSG_PRINTING );
        }
 
+       /* 
+        * Tell the specific printing tdb we want messages for this printer
+        * by registering our PID.
+        */
+
+       if (!print_notify_register_pid(snum))
+               DEBUG(0,("print_notify_register_pid: Failed to register our pid for printer %s\n", printer ));
+
        smb_connections++;
 
        result = cli_spoolss_reply_open_printer(&notify_cli, notify_cli.mem_ctx, printer, localprinter, 
@@ -2428,6 +2540,7 @@ WERROR _spoolss_rffpcnex(pipes_struct *p, SPOOL_Q_RFFPCNEX *q_u, SPOOL_R_RFFPCNE
        uint32 options = q_u->options;
        UNISTR2 *localmachine = &q_u->localmachine;
        uint32 printerlocal = q_u->printerlocal;
+       int snum = -1;
        SPOOL_NOTIFY_OPTION *option = q_u->option;
 
        /* store the notify value in the printer struct */
@@ -2453,7 +2566,13 @@ WERROR _spoolss_rffpcnex(pipes_struct *p, SPOOL_Q_RFFPCNEX *q_u, SPOOL_R_RFFPCNE
 
        /* Connect to the client machine and send a ReplyOpenPrinter */
 
-       if(!srv_spoolss_replyopenprinter(Printer->notify.localmachine,
+       if ( Printer->printer_type == PRINTER_HANDLE_IS_PRINTSERVER)
+               snum = -1;
+       else if ( (Printer->printer_type == PRINTER_HANDLE_IS_PRINTER) &&
+                       !get_printer_snum(p, handle, &snum) )
+               return WERR_BADFID;
+
+       if(!srv_spoolss_replyopenprinter(snum, Printer->notify.localmachine,
                                        Printer->notify.printerlocal, 1,
                                        &Printer->notify.client_hnd))
                return WERR_SERVER_UNAVAILABLE;
@@ -2997,7 +3116,7 @@ static void spoolss_notify_job_status_string(int snum,
         * Now we're returning job status codes we just return a "" here. JRA.
         */
 
-       char *p = "";
+       const char *p = "";
        pstring temp;
        uint32 len;
 
@@ -3150,7 +3269,7 @@ struct s_notify_info_data_table
 {
        uint16 type;
        uint16 field;
-       char *name;
+       const char *name;
        uint32 size;
        void (*fn) (int snum, SPOOL_NOTIFY_INFO_DATA *data,
                    print_queue_struct *queue,
@@ -3161,7 +3280,7 @@ struct s_notify_info_data_table
    whether the notification data is a pointer to a variable sized
    buffer, a one value uint32 or a two value uint32. */
 
-struct s_notify_info_data_table notify_info_data_table[] =
+static const struct s_notify_info_data_table notify_info_data_table[] =
 {
 { PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_SERVER_NAME,         "PRINTER_NOTIFY_SERVER_NAME",         NOTIFY_STRING,   spoolss_notify_server_name },
 { PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_PRINTER_NAME,        "PRINTER_NOTIFY_PRINTER_NAME",        NOTIFY_STRING,   spoolss_notify_printer_name },
@@ -3312,7 +3431,7 @@ void construct_info_data(SPOOL_NOTIFY_INFO_DATA *info_data, uint16 type, uint16
  *
  ********************************************************************/
 
-static BOOL construct_notify_printer_info(SPOOL_NOTIFY_INFO *info, int
+static BOOL construct_notify_printer_info(Printer_entry *print_hnd, SPOOL_NOTIFY_INFO *info, int
                                          snum, SPOOL_NOTIFY_OPTION_TYPE
                                          *option_type, uint32 id,
                                          TALLOC_CTX *mem_ctx) 
@@ -3331,11 +3450,10 @@ static BOOL construct_notify_printer_info(SPOOL_NOTIFY_INFO *info, int
                (option_type->type==PRINTER_NOTIFY_TYPE?"PRINTER_NOTIFY_TYPE":"JOB_NOTIFY_TYPE"),
                option_type->count, lp_servicename(snum)));
        
-       if (!W_ERROR_IS_OK(get_a_printer(&printer, 2, lp_servicename(snum))))
+       if (!W_ERROR_IS_OK(get_a_printer(print_hnd, &printer, 2, lp_const_servicename(snum))))
                return False;
 
-       for(field_num=0; field_num<option_type->count; field_num++) 
-       {
+       for(field_num=0; field_num<option_type->count; field_num++) {
                field = option_type->fields[field_num];
                
                DEBUG(4,("construct_notify_printer_info: notify [%d]: type [%x], field [%x]\n", field_num, type, field));
@@ -3343,12 +3461,10 @@ static BOOL construct_notify_printer_info(SPOOL_NOTIFY_INFO *info, int
                if (!search_notify(type, field, &j) )
                        continue;
 
-               if((tid=(SPOOL_NOTIFY_INFO_DATA *)Realloc(info->data, (info->count+1)*sizeof(SPOOL_NOTIFY_INFO_DATA))) == NULL) 
-               {
+               if((tid=(SPOOL_NOTIFY_INFO_DATA *)Realloc(info->data, (info->count+1)*sizeof(SPOOL_NOTIFY_INFO_DATA))) == NULL) {
                        DEBUG(2,("construct_notify_printer_info: failed to enlarge buffer info->data!\n"));
                        return False;
-               }
-               else 
+               } else 
                        info->data = tid;
 
                current_data = &info->data[info->count];
@@ -3480,7 +3596,7 @@ static WERROR printserver_notify_info(pipes_struct *p, POLICY_HND *hnd,
                for (snum=0; snum<n_services; snum++)
                {
                        if ( lp_browseable(snum) && lp_snum_ok(snum) && lp_print_ok(snum) )
-                               construct_notify_printer_info ( info, snum, option_type, snum, mem_ctx );
+                               construct_notify_printer_info ( Printer, info, snum, option_type, snum, mem_ctx );
                }
        }
                        
@@ -3540,7 +3656,7 @@ static WERROR printer_notify_info(pipes_struct *p, POLICY_HND *hnd, SPOOL_NOTIFY
                
                switch ( option_type->type ) {
                case PRINTER_NOTIFY_TYPE:
-                       if(construct_notify_printer_info(info, snum, 
+                       if(construct_notify_printer_info(Printer, info, snum, 
                                                         option_type, id,
                                                         mem_ctx))  
                                id--;
@@ -3551,8 +3667,7 @@ static WERROR printer_notify_info(pipes_struct *p, POLICY_HND *hnd, SPOOL_NOTIFY
 
                        count = print_queue_status(snum, &queue, &status);
 
-                       if (!W_ERROR_IS_OK(get_a_printer(&printer, 2, 
-                                                        lp_servicename(snum))))
+                       if (!W_ERROR_IS_OK(get_a_printer(Printer, &printer, 2, lp_const_servicename(snum))))
                                goto done;
 
                        for (j=0; j<count; j++) {
@@ -3622,6 +3737,8 @@ WERROR _spoolss_rfnpcnex( pipes_struct *p, SPOOL_Q_RFNPCNEX *q_u, SPOOL_R_RFNPCN
        /* We need to keep track of the change value to send back in 
            RRPCN replies otherwise our updates are ignored. */
 
+       Printer->notify.fnpcn = True;
+
        if (Printer->notify.client_connected) {
                DEBUG(10,("_spoolss_rfnpcnex: Saving change value in request [%x]\n", q_u->change));
                Printer->notify.change = q_u->change;
@@ -3639,7 +3756,9 @@ WERROR _spoolss_rfnpcnex( pipes_struct *p, SPOOL_Q_RFNPCNEX *q_u, SPOOL_R_RFNPCN
                        break;
        }
        
- done:
+       Printer->notify.fnpcn = False;
+       
+done:
        return result;
 }
 
@@ -3648,7 +3767,7 @@ WERROR _spoolss_rfnpcnex( pipes_struct *p, SPOOL_Q_RFNPCNEX *q_u, SPOOL_R_RFNPCN
  * fill a printer_info_0 struct
  ********************************************************************/
 
-static BOOL construct_printer_info_0(PRINTER_INFO_0 *printer, int snum)
+static BOOL construct_printer_info_0(Printer_entry *print_hnd, PRINTER_INFO_0 *printer, int snum)
 {
        pstring chaine;
        int count;
@@ -3659,7 +3778,7 @@ static BOOL construct_printer_info_0(PRINTER_INFO_0 *printer, int snum)
        time_t setuptime;
        print_status_struct status;
        
-       if (!W_ERROR_IS_OK(get_a_printer(&ntprinter, 2, lp_servicename(snum))))
+       if (!W_ERROR_IS_OK(get_a_printer(print_hnd, &ntprinter, 2, lp_const_servicename(snum))))
                return False;
 
        count = print_queue_length(snum, &status);
@@ -3718,12 +3837,12 @@ static BOOL construct_printer_info_0(PRINTER_INFO_0 *printer, int snum)
 
        printer->global_counter = global_counter;
        printer->total_pages = 0;
-#ifndef EMULATE_WIN2K_HACK     /* JERRY */
-       printer->major_version = 0x0004;        /* NT 4 */
-       printer->build_version = 0x0565;        /* build 1381 */
-#else
+#ifdef HAVE_ADS
        printer->major_version = 0x0005;        /* NT 5 */
        printer->build_version = 0x0893;        /* build 2195 */
+#else
+       printer->major_version = 0x0004;        /* NT 4 */
+       printer->build_version = 0x0565;        /* build 1381 */
 #endif
        printer->unknown7 = 0x1;
        printer->unknown8 = 0x0;
@@ -3757,13 +3876,13 @@ static BOOL construct_printer_info_0(PRINTER_INFO_0 *printer, int snum)
  * construct_printer_info_1
  * fill a printer_info_1 struct
  ********************************************************************/
-static BOOL construct_printer_info_1(uint32 flags, PRINTER_INFO_1 *printer, int snum)
+static BOOL construct_printer_info_1(Printer_entry *print_hnd, uint32 flags, PRINTER_INFO_1 *printer, int snum)
 {
        pstring chaine;
        pstring chaine2;
        NT_PRINTER_INFO_LEVEL *ntprinter = NULL;
 
-       if (!W_ERROR_IS_OK(get_a_printer(&ntprinter, 2, lp_servicename(snum))))
+       if (!W_ERROR_IS_OK(get_a_printer(print_hnd, &ntprinter, 2, lp_const_servicename(snum))))
                return False;
 
        printer->flags=flags;
@@ -3862,7 +3981,7 @@ DEVICEMODE *construct_dev_mode(int snum)
        
        DEBUGADD(8,("getting printer characteristics\n"));
 
-       if (!W_ERROR_IS_OK(get_a_printer(&printer, 2, lp_servicename(snum)))) 
+       if (!W_ERROR_IS_OK(get_a_printer(NULL, &printer, 2, lp_const_servicename(snum)))) 
                return NULL;
 
        if ( !printer->info_2->devmode ) {
@@ -3895,14 +4014,14 @@ done:
  * fill a printer_info_2 struct
  ********************************************************************/
 
-static BOOL construct_printer_info_2(PRINTER_INFO_2 *printer, int snum)
+static BOOL construct_printer_info_2(Printer_entry *print_hnd, PRINTER_INFO_2 *printer, int snum)
 {
        int count;
        NT_PRINTER_INFO_LEVEL *ntprinter = NULL;
 
        print_status_struct status;
 
-       if (!W_ERROR_IS_OK(get_a_printer(&ntprinter, 2, lp_servicename(snum))))
+       if (!W_ERROR_IS_OK(get_a_printer(print_hnd, &ntprinter, 2, lp_const_servicename(snum))))
                return False;
                
        count = print_queue_length(snum, &status);
@@ -3958,12 +4077,12 @@ static BOOL construct_printer_info_2(PRINTER_INFO_2 *printer, int snum)
  * fill a printer_info_3 struct
  ********************************************************************/
 
-static BOOL construct_printer_info_3(PRINTER_INFO_3 **pp_printer, int snum)
+static BOOL construct_printer_info_3(Printer_entry *print_hnd, PRINTER_INFO_3 **pp_printer, int snum)
 {
        NT_PRINTER_INFO_LEVEL *ntprinter = NULL;
        PRINTER_INFO_3 *printer = NULL;
 
-       if (!W_ERROR_IS_OK(get_a_printer(&ntprinter, 2, lp_servicename(snum))))
+       if (!W_ERROR_IS_OK(get_a_printer(print_hnd, &ntprinter, 2, lp_const_servicename(snum))))
                return False;
 
        *pp_printer = NULL;
@@ -4013,11 +4132,11 @@ static BOOL construct_printer_info_3(PRINTER_INFO_3 **pp_printer, int snum)
  * fill a printer_info_4 struct
  ********************************************************************/
 
-static BOOL construct_printer_info_4(PRINTER_INFO_4 *printer, int snum)
+static BOOL construct_printer_info_4(Printer_entry *print_hnd, PRINTER_INFO_4 *printer, int snum)
 {
        NT_PRINTER_INFO_LEVEL *ntprinter = NULL;
 
-       if (!W_ERROR_IS_OK(get_a_printer(&ntprinter, 2, lp_servicename(snum))))
+       if (!W_ERROR_IS_OK(get_a_printer(print_hnd, &ntprinter, 2, lp_const_servicename(snum))))
                return False;
                
        init_unistr(&printer->printername, ntprinter->info_2->printername);                             /* printername*/
@@ -4033,20 +4152,47 @@ static BOOL construct_printer_info_4(PRINTER_INFO_4 *printer, int snum)
  * fill a printer_info_5 struct
  ********************************************************************/
 
-static BOOL construct_printer_info_5(PRINTER_INFO_5 *printer, int snum)
+static BOOL construct_printer_info_5(Printer_entry *print_hnd, PRINTER_INFO_5 *printer, int snum)
 {
        NT_PRINTER_INFO_LEVEL *ntprinter = NULL;
 
-       if (!W_ERROR_IS_OK(get_a_printer(&ntprinter, 2, lp_servicename(snum))))
+       if (!W_ERROR_IS_OK(get_a_printer(print_hnd, &ntprinter, 2, lp_const_servicename(snum))))
                return False;
                
-       init_unistr(&printer->printername, ntprinter->info_2->printername);                             /* printername*/
-       init_unistr(&printer->portname, ntprinter->info_2->portname); /* portname */
+       init_unistr(&printer->printername, ntprinter->info_2->printername);
+       init_unistr(&printer->portname, ntprinter->info_2->portname); 
        printer->attributes = ntprinter->info_2->attributes;
-       printer->device_not_selected_timeout = 0x3a98;
-       printer->transmission_retry_timeout = 0xafc8;
+
+       /* these two are not used by NT+ according to MSDN */
+
+       printer->device_not_selected_timeout = 0x0;  /* have seen 0x3a98 */
+       printer->transmission_retry_timeout  = 0x0;  /* have seen 0xafc8 */
 
        free_a_printer(&ntprinter, 2);
+
+       return True;
+}
+
+/********************************************************************
+ * construct_printer_info_7
+ * fill a printer_info_7 struct
+ ********************************************************************/
+
+static BOOL construct_printer_info_7(Printer_entry *print_hnd, PRINTER_INFO_7 *printer, int snum)
+{
+       char *guid_str = NULL;
+       GUID guid;
+       
+       if (is_printer_published(print_hnd, snum, &guid)) {
+               asprintf(&guid_str, "{%s}", uuid_string_static(guid));
+               strupper(guid_str);
+               init_unistr(&printer->guid, guid_str);
+               printer->action = SPOOL_DS_PUBLISH;
+       } else {
+               init_unistr(&printer->guid, "");
+               printer->action = SPOOL_DS_UNPUBLISH;
+       }
+
        return True;
 }
 
@@ -4068,7 +4214,7 @@ static WERROR enum_all_printers_info_1(uint32 flags, NEW_BUFFER *buffer, uint32
                if (lp_browseable(snum) && lp_snum_ok(snum) && lp_print_ok(snum) ) {
                        DEBUG(4,("Found a printer in smb.conf: %s[%x]\n", lp_servicename(snum), snum));
 
-                       if (construct_printer_info_1(flags, &current_prt, snum)) {
+                       if (construct_printer_info_1(NULL, flags, &current_prt, snum)) {
                                if((tp=Realloc(printers, (*returned +1)*sizeof(PRINTER_INFO_1))) == NULL) {
                                        DEBUG(2,("enum_all_printers_info_1: failed to enlarge printers buffer!\n"));
                                        SAFE_FREE(printers);
@@ -4237,7 +4383,7 @@ static WERROR enum_all_printers_info_2(NEW_BUFFER *buffer, uint32 offered, uint3
                if (lp_browseable(snum) && lp_snum_ok(snum) && lp_print_ok(snum) ) {
                        DEBUG(4,("Found a printer in smb.conf: %s[%x]\n", lp_servicename(snum), snum));
                                
-                       if (construct_printer_info_2(&current_prt, snum)) {
+                       if (construct_printer_info_2(NULL, &current_prt, snum)) {
                                if((tp=Realloc(printers, (*returned +1)*sizeof(PRINTER_INFO_2))) == NULL) {
                                        DEBUG(2,("enum_all_printers_info_2: failed to enlarge printers buffer!\n"));
                                        SAFE_FREE(printers);
@@ -4408,14 +4554,14 @@ WERROR _spoolss_enumprinters( pipes_struct *p, SPOOL_Q_ENUMPRINTERS *q_u, SPOOL_
 /****************************************************************************
 ****************************************************************************/
 
-static WERROR getprinter_level_0(int snum, NEW_BUFFER *buffer, uint32 offered, uint32 *needed)
+static WERROR getprinter_level_0(Printer_entry *print_hnd, int snum, NEW_BUFFER *buffer, uint32 offered, uint32 *needed)
 {
        PRINTER_INFO_0 *printer=NULL;
 
        if((printer=(PRINTER_INFO_0*)malloc(sizeof(PRINTER_INFO_0))) == NULL)
                return WERR_NOMEM;
 
-       construct_printer_info_0(printer, snum);
+       construct_printer_info_0(print_hnd, printer, snum);
        
        /* check the required size. */  
        *needed += spoolss_size_printer_info_0(printer);
@@ -4441,14 +4587,14 @@ static WERROR getprinter_level_0(int snum, NEW_BUFFER *buffer, uint32 offered, u
 /****************************************************************************
 ****************************************************************************/
 
-static WERROR getprinter_level_1(int snum, NEW_BUFFER *buffer, uint32 offered, uint32 *needed)
+static WERROR getprinter_level_1(Printer_entry *print_hnd, int snum, NEW_BUFFER *buffer, uint32 offered, uint32 *needed)
 {
        PRINTER_INFO_1 *printer=NULL;
 
        if((printer=(PRINTER_INFO_1*)malloc(sizeof(PRINTER_INFO_1))) == NULL)
                return WERR_NOMEM;
 
-       construct_printer_info_1(PRINTER_ENUM_ICON8, printer, snum);
+       construct_printer_info_1(print_hnd, PRINTER_ENUM_ICON8, printer, snum);
        
        /* check the required size. */  
        *needed += spoolss_size_printer_info_1(printer);
@@ -4474,14 +4620,14 @@ static WERROR getprinter_level_1(int snum, NEW_BUFFER *buffer, uint32 offered, u
 /****************************************************************************
 ****************************************************************************/
 
-static WERROR getprinter_level_2(int snum, NEW_BUFFER *buffer, uint32 offered, uint32 *needed)
+static WERROR getprinter_level_2(Printer_entry *print_hnd, int snum, NEW_BUFFER *buffer, uint32 offered, uint32 *needed)
 {
        PRINTER_INFO_2 *printer=NULL;
 
        if((printer=(PRINTER_INFO_2*)malloc(sizeof(PRINTER_INFO_2)))==NULL)
                return WERR_NOMEM;
        
-       construct_printer_info_2(printer, snum);
+       construct_printer_info_2(print_hnd, printer, snum);
        
        /* check the required size. */  
        *needed += spoolss_size_printer_info_2(printer);
@@ -4510,11 +4656,11 @@ static WERROR getprinter_level_2(int snum, NEW_BUFFER *buffer, uint32 offered, u
 /****************************************************************************
 ****************************************************************************/
 
-static WERROR getprinter_level_3(int snum, NEW_BUFFER *buffer, uint32 offered, uint32 *needed)
+static WERROR getprinter_level_3(Printer_entry *print_hnd, int snum, NEW_BUFFER *buffer, uint32 offered, uint32 *needed)
 {
        PRINTER_INFO_3 *printer=NULL;
 
-       if (!construct_printer_info_3(&printer, snum))
+       if (!construct_printer_info_3(print_hnd, &printer, snum))
                return WERR_NOMEM;
        
        /* check the required size. */  
@@ -4541,14 +4687,14 @@ static WERROR getprinter_level_3(int snum, NEW_BUFFER *buffer, uint32 offered, u
 /****************************************************************************
 ****************************************************************************/
 
-static WERROR getprinter_level_4(int snum, NEW_BUFFER *buffer, uint32 offered, uint32 *needed)
+static WERROR getprinter_level_4(Printer_entry *print_hnd, int snum, NEW_BUFFER *buffer, uint32 offered, uint32 *needed)
 {
        PRINTER_INFO_4 *printer=NULL;
 
        if((printer=(PRINTER_INFO_4*)malloc(sizeof(PRINTER_INFO_4)))==NULL)
                return WERR_NOMEM;
 
-       if (!construct_printer_info_4(printer, snum))
+       if (!construct_printer_info_4(print_hnd, printer, snum))
                return WERR_NOMEM;
        
        /* check the required size. */  
@@ -4575,14 +4721,14 @@ static WERROR getprinter_level_4(int snum, NEW_BUFFER *buffer, uint32 offered, u
 /****************************************************************************
 ****************************************************************************/
 
-static WERROR getprinter_level_5(int snum, NEW_BUFFER *buffer, uint32 offered, uint32 *needed)
+static WERROR getprinter_level_5(Printer_entry *print_hnd, int snum, NEW_BUFFER *buffer, uint32 offered, uint32 *needed)
 {
        PRINTER_INFO_5 *printer=NULL;
 
        if((printer=(PRINTER_INFO_5*)malloc(sizeof(PRINTER_INFO_5)))==NULL)
                return WERR_NOMEM;
 
-       if (!construct_printer_info_5(printer, snum))
+       if (!construct_printer_info_5(print_hnd, printer, snum))
                return WERR_NOMEM;
        
        /* check the required size. */  
@@ -4606,6 +4752,37 @@ static WERROR getprinter_level_5(int snum, NEW_BUFFER *buffer, uint32 offered, u
        return WERR_OK; 
 }
 
+static WERROR getprinter_level_7(Printer_entry *print_hnd, int snum, NEW_BUFFER *buffer, uint32 offered, uint32 *needed)
+{
+       PRINTER_INFO_7 *printer=NULL;
+
+       if((printer=(PRINTER_INFO_7*)malloc(sizeof(PRINTER_INFO_7)))==NULL)
+               return WERR_NOMEM;
+
+       if (!construct_printer_info_7(print_hnd, printer, snum))
+               return WERR_NOMEM;
+       
+       /* check the required size. */  
+       *needed += spoolss_size_printer_info_7(printer);
+
+       if (!alloc_buffer_size(buffer, *needed)) {
+               free_printer_info_7(printer);
+               return WERR_INSUFFICIENT_BUFFER;
+       }
+
+       /* fill the buffer with the structures */
+       smb_io_printer_info_7("", buffer, printer, 0);  
+       
+       /* clear memory */
+       free_printer_info_7(printer);
+       
+       if (*needed > offered) {
+               return WERR_INSUFFICIENT_BUFFER;
+       }
+
+       return WERR_OK; 
+}
+
 /****************************************************************************
 ****************************************************************************/
 
@@ -4616,6 +4793,7 @@ WERROR _spoolss_getprinter(pipes_struct *p, SPOOL_Q_GETPRINTER *q_u, SPOOL_R_GET
        NEW_BUFFER *buffer = NULL;
        uint32 offered = q_u->offered;
        uint32 *needed = &r_u->needed;
+       Printer_entry *Printer=find_printer_index_by_hnd(p, handle);
 
        int snum;
 
@@ -4630,17 +4808,19 @@ WERROR _spoolss_getprinter(pipes_struct *p, SPOOL_Q_GETPRINTER *q_u, SPOOL_R_GET
 
        switch (level) {
        case 0:
-               return getprinter_level_0(snum, buffer, offered, needed);
+               return getprinter_level_0(Printer, snum, buffer, offered, needed);
        case 1:
-               return getprinter_level_1(snum, buffer, offered, needed);
+               return getprinter_level_1(Printer, snum, buffer, offered, needed);
        case 2:         
-               return getprinter_level_2(snum, buffer, offered, needed);
+               return getprinter_level_2(Printer, snum, buffer, offered, needed);
        case 3:         
-               return getprinter_level_3(snum, buffer, offered, needed);
+               return getprinter_level_3(Printer, snum, buffer, offered, needed);
        case 4:         
-               return getprinter_level_4(snum, buffer, offered, needed);
+               return getprinter_level_4(Printer, snum, buffer, offered, needed);
        case 5:         
-               return getprinter_level_5(snum, buffer, offered, needed);
+               return getprinter_level_5(Printer, snum, buffer, offered, needed);
+       case 7:
+               return getprinter_level_7(Printer, snum, buffer, offered, needed);
        }
        return WERR_UNKNOWN_LEVEL;
 }      
@@ -4665,7 +4845,7 @@ static WERROR construct_printer_driver_info_1(DRIVER_INFO_1 *info, int snum, fst
 
        ZERO_STRUCT(driver);
 
-       if (!W_ERROR_IS_OK(get_a_printer(&printer, 2, lp_servicename(snum))))
+       if (!W_ERROR_IS_OK(get_a_printer(NULL, &printer, 2, lp_const_servicename(snum))))
                return WERR_INVALID_PRINTER_NAME;
 
        if (!W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername, architecture, version)))
@@ -4725,7 +4905,7 @@ static WERROR construct_printer_driver_info_2(DRIVER_INFO_2 *info, int snum, fst
        ZERO_STRUCT(printer);
        ZERO_STRUCT(driver);
 
-       if (!W_ERROR_IS_OK(get_a_printer(&printer, 2, lp_servicename(snum))))
+       if (!W_ERROR_IS_OK(get_a_printer(NULL, &printer, 2, lp_const_servicename(snum))))
                return WERR_INVALID_PRINTER_NAME;
 
        if (!W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername, architecture, version)))
@@ -4744,11 +4924,11 @@ static WERROR construct_printer_driver_info_2(DRIVER_INFO_2 *info, int snum, fst
  * convert an array of ascii string to a UNICODE string
  ********************************************************************/
 
-static uint32 init_unistr_array(uint16 **uni_array, fstring *char_array, char *servername)
+static uint32 init_unistr_array(uint16 **uni_array, fstring *char_array, const char *servername)
 {
        int i=0;
        int j=0;
-       char *v;
+       const char *v;
        pstring line;
        uint16 *tuary;
 
@@ -4775,8 +4955,10 @@ static uint32 init_unistr_array(uint16 **uni_array, fstring *char_array, char *s
                        pstrcpy( line, v );
                        
                DEBUGADD(6,("%d:%s:%d\n", i, line, strlen(line)));
+
+               /* add one extra unit16 for the second terminating NULL */
                
-               if ( (tuary=Realloc(*uni_array, (j+strlen(line)+2)*sizeof(uint16))) == NULL ) {
+               if ( (tuary=Realloc(*uni_array, (j+1+strlen(line)+2)*sizeof(uint16))) == NULL ) {
                        DEBUG(2,("init_unistr_array: Realloc error\n" ));
                        return 0;
                } else
@@ -4790,6 +4972,9 @@ static uint32 init_unistr_array(uint16 **uni_array, fstring *char_array, char *s
        }
        
        if (*uni_array) {
+               /* special case for ""; we need to add both NULL's here */
+               if (!j)
+                       (*uni_array)[j++]=0x0000;       
                (*uni_array)[j]=0x0000;
        }
        
@@ -4859,7 +5044,7 @@ static WERROR construct_printer_driver_info_3(DRIVER_INFO_3 *info, int snum, fst
        WERROR status;
        ZERO_STRUCT(driver);
 
-       status=get_a_printer(&printer, 2, lp_servicename(snum) );
+       status=get_a_printer(NULL, &printer, 2, lp_const_servicename(snum) );
        DEBUG(8,("construct_printer_driver_info_3: status: %s\n", dos_errstr(status)));
        if (!W_ERROR_IS_OK(status))
                return WERR_INVALID_PRINTER_NAME;
@@ -4984,7 +5169,7 @@ static WERROR construct_printer_driver_info_6(DRIVER_INFO_6 *info, int snum,
        
        ZERO_STRUCT(driver);
 
-       status=get_a_printer(&printer, 2, lp_servicename(snum) );
+       status=get_a_printer(NULL, &printer, 2, lp_const_servicename(snum) );
        
        DEBUG(8,("construct_printer_driver_info_6: status: %s\n", dos_errstr(status)));
        
@@ -5019,6 +5204,7 @@ static WERROR construct_printer_driver_info_6(DRIVER_INFO_6 *info, int snum,
        fill_printer_driver_info_6(info, driver, servername);
 
        free_a_printer(&printer,2);
+       free_a_printer_driver(driver, 3);
 
        return WERR_OK;
 }
@@ -5211,7 +5397,7 @@ WERROR _spoolss_getprinterdriver2(pipes_struct *p, SPOOL_Q_GETPRINTERDRIVER2 *q_
        *servermajorversion = 0;
        *serverminorversion = 0;
 
-       pstrcpy(servername, get_called_name());
+       fstrcpy(servername, get_called_name());
        unistr2_to_ascii(architecture, uni_arch, sizeof(architecture)-1);
 
        if (!get_printer_snum(p, handle, &snum))
@@ -5573,7 +5759,8 @@ static BOOL check_printer_ok(NT_PRINTER_INFO_LEVEL_2 *info, int snum)
        fstrcpy(info->sharename, lp_servicename(snum));
        slprintf(info->printername, sizeof(info->printername)-1, "\\\\%s\\%s",
                 get_called_name(), info->sharename);
-       info->attributes = PRINTER_ATTRIBUTE_SHARED | PRINTER_ATTRIBUTE_NETWORK;
+       info->attributes = PRINTER_ATTRIBUTE_SAMBA;
+       
        
        return True;
 }
@@ -5587,23 +5774,17 @@ static BOOL add_printer_hook(NT_PRINTER_INFO_LEVEL *printer)
        char *cmd = lp_addprinter_cmd();
        char **qlines;
        pstring command;
-       pstring driverlocation;
        int numlines;
        int ret;
        int fd;
        fstring remote_machine = "%m";
 
-       /* build driver path... only 9X architecture is needed for legacy reasons */
-       slprintf(driverlocation, sizeof(driverlocation)-1, "\\\\%s\\print$\\WIN40\\0",
-                       get_called_name());
-       /* change \ to \\ for the shell */
-       all_string_sub(driverlocation,"\\","\\\\",sizeof(pstring));
        standard_sub_basic(current_user_info.smb_name, remote_machine,sizeof(remote_machine));
        
        slprintf(command, sizeof(command)-1, "%s \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"",
                        cmd, printer->info_2->printername, printer->info_2->sharename,
                        printer->info_2->portname, printer->info_2->drivername,
-                       printer->info_2->location, driverlocation, remote_machine);
+                       printer->info_2->location, printer->info_2->comment, remote_machine);
 
        DEBUG(10,("Running [%s]\n", command));
        ret = smbrun(command, &fd);
@@ -5628,7 +5809,9 @@ static BOOL add_printer_hook(NT_PRINTER_INFO_LEVEL *printer)
 
                /* Send SIGHUP to process group... is there a better way? */
                kill(0, SIGHUP);
-               add_all_printers();
+               
+               /* reload our services immediately */
+               reload_services( False );
        }
 
        file_lines_free(qlines);
@@ -5648,18 +5831,13 @@ static WERROR update_printer(pipes_struct *p, POLICY_HND *handle, uint32 level,
        NT_PRINTER_INFO_LEVEL *printer = NULL, *old_printer = NULL;
        Printer_entry *Printer = find_printer_index_by_hnd(p, handle);
        WERROR result;
+       UNISTR2 buffer;
+       fstring asc_buffer;
 
        DEBUG(8,("update_printer\n"));
 
        result = WERR_OK;
 
-       if (level!=2) {
-               DEBUG(0,("update_printer: Send a mail to samba@samba.org\n"));
-               DEBUGADD(0,("with the following message: update_printer: level!=2\n"));
-               result = WERR_UNKNOWN_LEVEL;
-               goto done;
-       }
-
        if (!Printer) {
                result = WERR_BADFID;
                goto done;
@@ -5670,8 +5848,8 @@ static WERROR update_printer(pipes_struct *p, POLICY_HND *handle, uint32 level,
                goto done;
        }
 
-       if (!W_ERROR_IS_OK(get_a_printer(&printer, 2, lp_servicename(snum))) ||
-           (!W_ERROR_IS_OK(get_a_printer(&old_printer, 2, lp_servicename(snum))))) {
+       if (!W_ERROR_IS_OK(get_a_printer(Printer, &printer, 2, lp_const_servicename(snum))) ||
+           (!W_ERROR_IS_OK(get_a_printer(Printer, &old_printer, 2, lp_const_servicename(snum))))) {
                result = WERR_BADFID;
                goto done;
        }
@@ -5717,12 +5895,25 @@ static WERROR update_printer(pipes_struct *p, POLICY_HND *handle, uint32 level,
        }
 
        /* Call addprinter hook */
-
-       if (*lp_addprinter_cmd()) {
+       /* Check changes to see if this is really needed */
+       
+       if ( *lp_addprinter_cmd() 
+               && (!strequal(printer->info_2->drivername, old_printer->info_2->drivername)
+                       || !strequal(printer->info_2->comment, old_printer->info_2->comment)
+                       || !strequal(printer->info_2->portname, old_printer->info_2->portname)
+                       || !strequal(printer->info_2->location, old_printer->info_2->location)) )
+       {
                if ( !add_printer_hook(printer) ) {
                        result = WERR_ACCESS_DENIED;
                        goto done;
                }
+
+               /* 
+                * make sure we actually reload the services after 
+                * this as smb.conf could have a new section in it 
+                * .... shouldn't .... but could
+                */
+               reload_services(False); 
        }
        
        /*
@@ -5744,23 +5935,63 @@ static WERROR update_printer(pipes_struct *p, POLICY_HND *handle, uint32 level,
                notify_printer_driver(snum, printer->info_2->drivername);
        }
 
-       /* Update printer info */
-       result = mod_a_printer(*printer, 2);
+       /* 
+        * flag which changes actually occured.  This is a small subset of 
+        * all the possible changes.  We also have to update things in the 
+        * DsSpooler key.
+        */
 
-       /* flag which changes actually occured.  This is a small subset of
-          all the possible changes                                         */
+       if (!strequal(printer->info_2->comment, old_printer->info_2->comment)) {
+               init_unistr2( &buffer, printer->info_2->comment, strlen(printer->info_2->comment)+1 );
+               set_printer_dataex( printer, SPOOL_DSSPOOLER_KEY, "description",
+                       REG_SZ, (uint8*)buffer.buffer, buffer.uni_str_len*2 );
 
-       if (!strequal(printer->info_2->comment, old_printer->info_2->comment))
                notify_printer_comment(snum, printer->info_2->comment);
+       }
+
+       if (!strequal(printer->info_2->sharename, old_printer->info_2->sharename)) {
+               init_unistr2( &buffer, printer->info_2->sharename, strlen(printer->info_2->sharename)+1 );
+               set_printer_dataex( printer, SPOOL_DSSPOOLER_KEY, "printerName",
+                       REG_SZ, (uint8*)buffer.buffer, buffer.uni_str_len*2 );
+               set_printer_dataex( printer, SPOOL_DSSPOOLER_KEY, "shareName",
+                       REG_SZ, (uint8*)buffer.buffer, buffer.uni_str_len*2 );
 
-       if (!strequal(printer->info_2->sharename, old_printer->info_2->sharename))
                notify_printer_sharename(snum, printer->info_2->sharename);
+       }
+
+       if (!strequal(printer->info_2->portname, old_printer->info_2->portname)) {
+               init_unistr2( &buffer, printer->info_2->portname, strlen(printer->info_2->portname)+1 );
+               set_printer_dataex( printer, SPOOL_DSSPOOLER_KEY, "portName",
+                       REG_SZ, (uint8*)buffer.buffer, buffer.uni_str_len*2 );
 
-       if (!strequal(printer->info_2->portname, old_printer->info_2->portname))
                notify_printer_port(snum, printer->info_2->portname);
+       }
+
+       if (!strequal(printer->info_2->location, old_printer->info_2->location)) {
+               init_unistr2( &buffer, printer->info_2->location, strlen(printer->info_2->location)+1 );
+               set_printer_dataex( printer, SPOOL_DSSPOOLER_KEY, "location",
+                       REG_SZ, (uint8*)buffer.buffer, buffer.uni_str_len*2 );
 
-       if (!strequal(printer->info_2->location, old_printer->info_2->location))
                notify_printer_location(snum, printer->info_2->location);
+       }
+       
+       /* here we need to update some more DsSpooler keys */
+       /* uNCName, serverName, shortServerName */
+       
+       init_unistr2( &buffer, global_myname(), strlen(global_myname())+1 );
+       set_printer_dataex( printer, SPOOL_DSSPOOLER_KEY, "serverName",
+               REG_SZ, (uint8*)buffer.buffer, buffer.uni_str_len*2 );
+       set_printer_dataex( printer, SPOOL_DSSPOOLER_KEY, "shortServerName",
+               REG_SZ, (uint8*)buffer.buffer, buffer.uni_str_len*2 );
+
+       slprintf( asc_buffer, sizeof(asc_buffer)-1, "\\\\%s\\%s",
+                 global_myname(), printer->info_2->sharename );
+       init_unistr2( &buffer, asc_buffer, strlen(asc_buffer)+1 );
+       set_printer_dataex( printer, SPOOL_DSSPOOLER_KEY, "uNCName",
+               REG_SZ, (uint8*)buffer.buffer, buffer.uni_str_len*2 );
+
+       /* Update printer info */
+       result = mod_a_printer(*printer, 2);
 
 done:
        free_a_printer(&printer, 2);
@@ -5770,6 +6001,34 @@ done:
        return result;
 }
 
+/****************************************************************************
+****************************************************************************/
+static WERROR publish_or_unpublish_printer(pipes_struct *p, POLICY_HND *handle,
+                                  const SPOOL_PRINTER_INFO_LEVEL *info)
+{
+#ifdef HAVE_ADS
+       SPOOL_PRINTER_INFO_LEVEL_7 *info7 = info->info_7;
+       int snum;
+       Printer_entry *Printer = find_printer_index_by_hnd(p, handle);
+       WERROR result;
+
+       DEBUG(5,("publish_or_unpublish_printer, action = %d\n",info7->action));
+
+       result = WERR_OK;
+
+       if (!Printer)
+               return WERR_BADFID;
+
+       if (!get_printer_snum(p, handle, &snum))
+               return WERR_BADFID;
+       
+       nt_printer_publish(Printer, snum, info7->action);
+       
+       return WERR_OK;
+#else
+       return WERR_UNKNOWN_LEVEL;
+#endif
+}
 /****************************************************************************
 ****************************************************************************/
 
@@ -5798,6 +6057,8 @@ WERROR _spoolss_setprinter(pipes_struct *p, SPOOL_Q_SETPRINTER *q_u, SPOOL_R_SET
                case 3:
                        return update_printer_sec(handle, level, info, p,
                                                  secdesc_ctr);
+               case 7:
+                       return publish_or_unpublish_printer(p, handle, info);
                default:
                        return WERR_UNKNOWN_LEVEL;
        }
@@ -5809,7 +6070,6 @@ WERROR _spoolss_setprinter(pipes_struct *p, SPOOL_Q_SETPRINTER *q_u, SPOOL_R_SET
 WERROR _spoolss_fcpn(pipes_struct *p, SPOOL_Q_FCPN *q_u, SPOOL_R_FCPN *r_u)
 {
        POLICY_HND *handle = &q_u->handle;
-
        Printer_entry *Printer= find_printer_index_by_hnd(p, handle);
        
        if (!Printer) {
@@ -5817,8 +6077,17 @@ WERROR _spoolss_fcpn(pipes_struct *p, SPOOL_Q_FCPN *q_u, SPOOL_R_FCPN *r_u)
                return WERR_BADFID;
        }
 
-       if (Printer->notify.client_connected==True)
-               srv_spoolss_replycloseprinter(&Printer->notify.client_hnd);
+       if (Printer->notify.client_connected==True) {
+               int snum = -1;
+
+               if ( Printer->printer_type == PRINTER_HANDLE_IS_PRINTSERVER)
+                       snum = -1;
+               else if ( (Printer->printer_type == PRINTER_HANDLE_IS_PRINTER) &&
+                               !get_printer_snum(p, handle, &snum) )
+                       return WERR_BADFID;
+
+               srv_spoolss_replycloseprinter(snum, &Printer->notify.client_hnd);
+       }
 
        Printer->notify.flags=0;
        Printer->notify.options=0;
@@ -5884,7 +6153,6 @@ static BOOL fill_job_info_2(JOB_INFO_2 *job_info, print_queue_struct *queue,
                            DEVICEMODE *devmode)
 {
        pstring temp_name;
-       pstring chaine;
        struct tm *t;
 
        t=gmtime(&queue->time);
@@ -5892,9 +6160,7 @@ static BOOL fill_job_info_2(JOB_INFO_2 *job_info, print_queue_struct *queue,
 
        job_info->jobid=queue->job;
        
-       slprintf(chaine, sizeof(chaine)-1, "\\\\%s\\%s", get_called_name(), ntprinter->info_2->printername);
-
-       init_unistr(&job_info->printername, chaine);
+       init_unistr(&job_info->printername, ntprinter->info_2->printername);
        
        init_unistr(&job_info->machinename, temp_name);
        init_unistr(&job_info->username, queue->fs_user);
@@ -5992,17 +6258,15 @@ static WERROR enumjobs_level2(print_queue_struct *queue, int snum,
                goto done;
        }
 
-       result = get_a_printer(&ntprinter, 2, lp_servicename(snum));
+       result = get_a_printer(NULL, &ntprinter, 2, lp_servicename(snum));
        if (!W_ERROR_IS_OK(result)) {
                *returned = 0;
                goto done;
        }
                
-       if (!(devmode = construct_dev_mode(snum))) {
-               *returned = 0;
-               result = WERR_NOMEM;
-               goto done;
-       }
+       /* this should not be a failure condition if the devmode is NULL */
+       
+       devmode = construct_dev_mode(snum);
 
        for (i=0; i<*returned; i++)
                fill_job_info_2(&(info[i]), &queue[i], i, snum, ntprinter,
@@ -6635,7 +6899,7 @@ WERROR _spoolss_getform(pipes_struct *p, SPOOL_Q_GETFORM *q_u, SPOOL_R_GETFORM *
 /****************************************************************************
 ****************************************************************************/
 
-static void fill_port_1(PORT_INFO_1 *port, char *name)
+static void fill_port_1(PORT_INFO_1 *port, const char *name)
 {
        init_unistr(&port->port_name, name);
 }
@@ -6643,7 +6907,7 @@ static void fill_port_1(PORT_INFO_1 *port, char *name)
 /****************************************************************************
 ****************************************************************************/
 
-static void fill_port_2(PORT_INFO_2 *port, char *name)
+static void fill_port_2(PORT_INFO_2 *port, const char *name)
 {
        init_unistr(&port->port_name, name);
        init_unistr(&port->monitor_name, "Local Monitor");
@@ -6908,15 +7172,17 @@ static WERROR spoolss_addprinterex_level_2( pipes_struct *p, const UNISTR2 *uni_
                return WERR_PRINTER_ALREADY_EXISTS;
        }
 
-       if (*lp_addprinter_cmd() )
+       if (*lp_addprinter_cmd() ) {
                if ( !add_printer_hook(printer) ) {
                        free_a_printer(&printer,2);
                        return WERR_ACCESS_DENIED;
        }
+       }
 
        slprintf(name, sizeof(name)-1, "\\\\%s\\%s", get_called_name(),
              printer->info_2->sharename);
 
+       
        if ((snum = print_queue_snum(printer->info_2->sharename)) == -1) {
                free_a_printer(&printer,2);
                return WERR_ACCESS_DENIED;
@@ -7296,7 +7562,7 @@ WERROR _spoolss_enumprinterdata(pipes_struct *p, SPOOL_Q_ENUMPRINTERDATA *q_u, S
        if (!get_printer_snum(p,handle, &snum))
                return WERR_BADFID;
        
-       result = get_a_printer(&printer, 2, lp_servicename(snum));
+       result = get_a_printer(Printer, &printer, 2, lp_const_servicename(snum));
        if (!W_ERROR_IS_OK(result))
                return result;
                
@@ -7360,9 +7626,9 @@ WERROR _spoolss_enumprinterdata(pipes_struct *p, SPOOL_Q_ENUMPRINTERDATA *q_u, S
                /* out_value should default to "" or else NT4 has
                   problems unmarshalling the response */
 
-               *out_max_value_len = (in_value_len/sizeof(uint16));
+               *out_max_value_len=(in_value_len/sizeof(uint16));
                
-               if ( (*out_value=(uint16 *)talloc_zero(p->mem_ctx, in_value_len*sizeof(uint8))) == NULL ) 
+               if((*out_value=(uint16 *)talloc_zero(p->mem_ctx, in_value_len*sizeof(uint8))) == NULL)
                {
                        result = WERR_NOMEM;
                        goto done;
@@ -7397,7 +7663,7 @@ WERROR _spoolss_enumprinterdata(pipes_struct *p, SPOOL_Q_ENUMPRINTERDATA *q_u, S
                 */
        
                /* name */
-               *out_max_value_len = ( in_value_len / sizeof(uint16) );
+               *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;
@@ -7470,7 +7736,7 @@ WERROR _spoolss_setprinterdata( pipes_struct *p, SPOOL_Q_SETPRINTERDATA *q_u, SP
                goto done;
        }
 
-       status = get_a_printer(&printer, 2, lp_servicename(snum));
+       status = get_a_printer(Printer, &printer, 2, lp_const_servicename(snum));
        if (!W_ERROR_IS_OK(status))
                return status;
 
@@ -7562,7 +7828,7 @@ WERROR _spoolss_deleteprinterdata(pipes_struct *p, SPOOL_Q_DELETEPRINTERDATA *q_
                return WERR_ACCESS_DENIED;
        }
 
-       status = get_a_printer(&printer, 2, lp_servicename(snum));
+       status = get_a_printer(Printer, &printer, 2, lp_const_servicename(snum));
        if (!W_ERROR_IS_OK(status))
                return status;
 
@@ -7606,7 +7872,7 @@ WERROR _spoolss_addform( pipes_struct *p, SPOOL_Q_ADDFORM *q_u, SPOOL_R_ADDFORM
                if (!get_printer_snum(p,handle, &snum))
                        return WERR_BADFID;
         
-               status = get_a_printer(&printer, 2, lp_servicename(snum));
+               status = get_a_printer(Printer, &printer, 2, lp_const_servicename(snum));
                if (!W_ERROR_IS_OK(status))
                        goto done;
        }
@@ -7677,7 +7943,7 @@ WERROR _spoolss_deleteform( pipes_struct *p, SPOOL_Q_DELETEFORM *q_u, SPOOL_R_DE
                if (!get_printer_snum(p,handle, &snum))
                        return WERR_BADFID;
         
-               status = get_a_printer(&printer, 2, lp_servicename(snum));
+               status = get_a_printer(Printer, &printer, 2, lp_const_servicename(snum));
                if (!W_ERROR_IS_OK(status))
                        goto done;
        }
@@ -7745,7 +8011,7 @@ WERROR _spoolss_setform(pipes_struct *p, SPOOL_Q_SETFORM *q_u, SPOOL_R_SETFORM *
                if (!get_printer_snum(p,handle, &snum))
                        return WERR_BADFID;
         
-               status = get_a_printer(&printer, 2, lp_servicename(snum));
+               status = get_a_printer(Printer, &printer, 2, lp_const_servicename(snum));
                if (!W_ERROR_IS_OK(status))
                        goto done;
        }
@@ -8095,13 +8361,14 @@ static WERROR getjob_level_2(print_queue_struct *queue, int count, int snum, uin
                goto done;
        }
        
-       ret = get_a_printer(&ntprinter, 2, lp_servicename(snum));
+       ret = get_a_printer(NULL, &ntprinter, 2, lp_const_servicename(snum));
        if (!W_ERROR_IS_OK(ret))
                goto done;
        
        /* 
         * if the print job does not have a DEVMODE associated with it, 
-        * just use the one for the printer 
+        * just use the one for the printer. A NULL devicemode is not
+        *  a failure condition
         */
         
        if ( !(nt_devmode=print_job_devmode( snum, jobid )) )
@@ -8113,11 +8380,6 @@ static WERROR getjob_level_2(print_queue_struct *queue, int count, int snum, uin
                }
        }
        
-       if ( !devmode ) {
-               ret = WERR_NOMEM;
-               goto done;
-       }
-
        fill_job_info_2(info_2, &(queue[i-1]), i, snum, ntprinter, devmode);
        
        *needed += spoolss_size_job_info_2(info_2);
@@ -8252,7 +8514,7 @@ WERROR _spoolss_getprinterdataex(pipes_struct *p, SPOOL_Q_GETPRINTERDATAEX *q_u,
        if ( !get_printer_snum(p,handle, &snum) )
                return WERR_BADFID;
 
-       status = get_a_printer(&printer, 2, lp_servicename(snum));
+       status = get_a_printer(Printer, &printer, 2, lp_servicename(snum));
        if ( !W_ERROR_IS_OK(status) )
                goto done;
 
@@ -8347,7 +8609,7 @@ WERROR _spoolss_setprinterdataex(pipes_struct *p, SPOOL_Q_SETPRINTERDATAEX *q_u,
                return WERR_ACCESS_DENIED;
        }
 
-       status = get_a_printer(&printer, 2, lp_servicename(snum));
+       status = get_a_printer(Printer, &printer, 2, lp_servicename(snum));
        if (!W_ERROR_IS_OK(status))
                return status;
 
@@ -8366,11 +8628,10 @@ WERROR _spoolss_setprinterdataex(pipes_struct *p, SPOOL_Q_SETPRINTERDATAEX *q_u,
        
        status = set_printer_dataex( printer, keyname, valuename, type, data, real_len ); 
        
-       /* save the OID if one was specified and the previous set call succeeded */
-       
-       if ( W_ERROR_IS_OK(status) && oid_string )
+       if ( W_ERROR_IS_OK(status) )
        {
-
+               /* save the OID if one was specified */
+               if ( oid_string ) {
                fstrcat( keyname, "\\" );
                fstrcat( keyname, SPOOL_OID_KEY );
                
@@ -8385,6 +8646,9 @@ WERROR _spoolss_setprinterdataex(pipes_struct *p, SPOOL_Q_SETPRINTERDATAEX *q_u,
                                    REG_SZ, (void*)oid_string, strlen(oid_string)+1 );          
        }
        
+               status = mod_a_printer(*printer, 2);
+       }
+               
        free_a_printer(&printer, 2);
 
        return status;
@@ -8422,7 +8686,7 @@ WERROR _spoolss_deleteprinterdataex(pipes_struct *p, SPOOL_Q_DELETEPRINTERDATAEX
                return WERR_ACCESS_DENIED;
        }
 
-       status = get_a_printer(&printer, 2, lp_servicename(snum));
+       status = get_a_printer(Printer, &printer, 2, lp_const_servicename(snum));
        if (!W_ERROR_IS_OK(status))
                return status;
 
@@ -8466,7 +8730,7 @@ WERROR _spoolss_enumprinterkey(pipes_struct *p, SPOOL_Q_ENUMPRINTERKEY *q_u, SPO
        if ( !get_printer_snum(p,handle, &snum) )
                return WERR_BADFID;
 
-       status = get_a_printer(&printer, 2, lp_servicename(snum));
+       status = get_a_printer(Printer, &printer, 2, lp_const_servicename(snum));
        if (!W_ERROR_IS_OK(status))
                return status;
                
@@ -8541,7 +8805,7 @@ WERROR _spoolss_deleteprinterkey(pipes_struct *p, SPOOL_Q_DELETEPRINTERKEY *q_u,
                return WERR_ACCESS_DENIED;
        }
 
-       status = get_a_printer(&printer, 2, lp_servicename(snum));
+       status = get_a_printer(Printer, &printer, 2, lp_const_servicename(snum));
        if (!W_ERROR_IS_OK(status))
                return status;
        
@@ -8587,17 +8851,30 @@ WERROR _spoolss_enumprinterdataex(pipes_struct *p, SPOOL_Q_ENUMPRINTERDATAEX *q_
        DEBUG(4,("_spoolss_enumprinterdataex\n"));
 
        if (!Printer) {
-               DEBUG(2,("_spoolss_enumprinterdata: Invalid handle (%s:%u:%u1<).\n", OUR_HANDLE(handle)));
+               DEBUG(2,("_spoolss_enumprinterdataex: Invalid handle (%s:%u:%u1<).\n", OUR_HANDLE(handle)));
                return WERR_BADFID;
        }
 
-       /* first get the printer off of disk */
+       /* 
+        * first check for a keyname of NULL or "".  Win2k seems to send 
+        * this a lot and we should send back WERR_INVALID_PARAM
+        * no need to spend time looking up the printer in this case.
+        * --jerry
+        */
+        
+       unistr2_to_ascii(key, &q_u->key, sizeof(key) - 1);
+       if ( !strlen(key) ) {
+               result = WERR_INVALID_PARAM;
+               goto done;
+       }
+
+       /* get the printer off of disk */
        
        if (!get_printer_snum(p,handle, &snum))
                return WERR_BADFID;
        
        ZERO_STRUCT(printer);
-       result = get_a_printer(&printer, 2, lp_servicename(snum));
+       result = get_a_printer(Printer, &printer, 2, lp_const_servicename(snum));
        if (!W_ERROR_IS_OK(result))
                return result;
        
@@ -8687,6 +8964,7 @@ WERROR _spoolss_enumprinterdataex(pipes_struct *p, SPOOL_Q_ENUMPRINTERDATAEX *q_
        
                
 done:  
+       if ( printer )
        free_a_printer(&printer, 2);
 
        return result;
@@ -8760,6 +9038,7 @@ WERROR _spoolss_getprintprocessordirectory(pipes_struct *p, SPOOL_Q_GETPRINTPROC
        case 1:
                result = getprintprocessordirectory_level_1
                  (&q_u->name, &q_u->environment, buffer, offered, needed);
+               break;
        default:
                result = WERR_UNKNOWN_LEVEL;
        }