port latest changes from SAMBA_3_0 tree
[samba.git] / source3 / rpc_server / srv_spoolss_nt.c
index 6953ec366313ca47b3ae509fbed3e6edae4e4ece..8237298ebb7ad92b3e26fa8550951c2ff12867ad 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 */
        "WIN2K",   /* driver version/cversion 3 */
 };
 
+static const char *get_drv_ver_to_os(int ver)
+{
+       if (ver < 0 || ver > 3)
+               return "";
+       return drv_ver_to_os[ver];
+}
+
 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 +146,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 +194,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 +217,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 +231,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 +272,56 @@ static Printer_entry *find_printer_index_by_hnd(pipes_struct *p, POLICY_HND *hnd
        return find_printer;
 }
 
+/****************************************************************************
+ look for a printer object cached on an open printer handle
+****************************************************************************/
+
+WERROR find_printer_in_print_hnd_cache( TALLOC_CTX *ctx, NT_PRINTER_INFO_LEVEL_2 **info2, 
+                                        const char *printername )
+{
+       Printer_entry *p;
+       
+       DEBUG(10,("find_printer_in_print_hnd_cache: printer [%s]\n", printername));
+
+       for ( p=printers_list; p; p=p->next )
+       {
+               if ( p->printer_type==PRINTER_HANDLE_IS_PRINTER 
+                       && p->printer_info
+                       && StrCaseCmp(p->dev.handlename, printername) == 0 )
+               {
+                       DEBUG(10,("Found printer\n"));
+                       *info2 = dup_printer_2( ctx, p->printer_info->info_2 );
+                       if ( *info2 )
+                               return WERR_OK;
+               }
+       }
+
+       return WERR_INVALID_PRINTER_NAME;
+}
+
+/****************************************************************************
+  destroy any cached printer_info_2 structures on open handles
+****************************************************************************/
+
+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 +353,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 +375,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 +403,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;
        }
 
@@ -424,7 +478,7 @@ static BOOL set_printer_hnd_name(Printer_entry *Printer, char *handlename)
        fstring sname;
        BOOL found=False;
        
-       DEBUG(4,("Setting printer name=%s (len=%d)\n", handlename, strlen(handlename)));
+       DEBUG(4,("Setting printer name=%s (len=%lu)\n", handlename, (unsigned long)strlen(handlename)));
 
        if (Printer->printer_type==PRINTER_HANDLE_IS_PRINTSERVER) {
                ZERO_STRUCT(Printer->dev.printerservername);
@@ -443,7 +497,7 @@ static BOOL set_printer_hnd_name(Printer_entry *Printer, char *handlename)
                aprinter=handlename;
        }
 
-       DEBUGADD(5,("searching for [%s] (len=%d)\n", aprinter, strlen(aprinter)));
+       DEBUGADD(5,("searching for [%s] (len=%lu)\n", aprinter, (unsigned long)strlen(aprinter)));
 
        /*
         * The original code allowed smbd to store a printer name that
@@ -499,16 +553,22 @@ static BOOL open_printer_hnd(pipes_struct *p, POLICY_HND *hnd, char *name, uint3
 
        ZERO_STRUCTP(new_printer);
        
-       new_printer->notify.option=NULL;
-                               
-       /* Add to the internal list. */
-       DLIST_ADD(printers_list, new_printer);
-
        if (!create_policy_hnd(p, hnd, free_printer_entry, new_printer)) {
                SAFE_FREE(new_printer);
                return False;
        }
-
+       
+       /* Add to the internal list. */
+       DLIST_ADD(printers_list, new_printer);
+       
+       new_printer->notify.option=NULL;
+                               
+       if ( !(new_printer->ctx = talloc_init("Printer Entry [%p]", hnd)) ) {
+               DEBUG(0,("open_printer_hnd: talloc_init() failed!\n"));
+               close_printer_handle(p, hnd);
+               return False;
+       }
+       
        if (!set_printer_hnd_printertype(new_printer, name)) {
                close_printer_handle(p, hnd);
                return False;
@@ -580,7 +640,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 +722,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 +731,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 +803,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 +886,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)) ) {
@@ -877,7 +935,7 @@ static void send_notify2_changes( SPOOLSS_NOTIFY_MSG_CTR *ctr, uint32 idx )
        TALLOC_CTX               *mem_ctx = notify_ctr_getctx( ctr );
        SPOOLSS_NOTIFY_MSG_GROUP *msg_group = notify_ctr_getgroup( ctr, idx );
        SPOOLSS_NOTIFY_MSG       *messages;
-       
+       int                      sending_msg_count;
        
        if ( !msg_group ) {
                DEBUG(5,("send_notify2_changes() called with no msg group!\n"));
@@ -895,12 +953,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 +980,67 @@ 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++ )
-               {
+               sending_msg_count = 0;
+               
+               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;
 
+                       sending_msg_count++;
                        
-               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:
@@ -994,8 +1051,10 @@ static void send_notify2_changes( SPOOLSS_NOTIFY_MSG_CTR *ctr, uint32 idx )
                        data_len++;
                }
 
-               cli_spoolss_rrpcn( &notify_cli, mem_ctx, &p->notify.client_hnd, 
-                               data_len, data, p->notify.change, 0 );
+               if ( sending_msg_count ) {
+                       cli_spoolss_rrpcn( &notify_cli, mem_ctx, &p->notify.client_hnd, 
+                                       data_len, data, p->notify.change, 0 );
+               }
        }
        
 done:
@@ -1006,18 +1065,20 @@ done:
 /***********************************************************************
  **********************************************************************/
 
-static BOOL notify2_unpack_msg( SPOOLSS_NOTIFY_MSG *msg, void *buf, size_t len )
+static BOOL notify2_unpack_msg( SPOOLSS_NOTIFY_MSG *msg, struct timeval *tv, void *buf, size_t len )
 {
 
-       int offset = 0;
+       uint32 tv_sec, tv_usec;
+       size_t offset = 0;
 
        /* Unpack message */
 
        offset += tdb_unpack((char *)buf + offset, len - offset, "f",
                             msg->printer);
        
-       offset += tdb_unpack((char *)buf + offset, len - offset, "ddddd",
-                            &msg->type, &msg->field, &msg->id, &msg->len, &msg->flags);
+       offset += tdb_unpack((char *)buf + offset, len - offset, "ddddddd",
+                               &tv_sec, &tv_usec,
+                               &msg->type, &msg->field, &msg->id, &msg->len, &msg->flags);
 
        if (msg->len == 0)
                tdb_unpack((char *)buf + offset, len - offset, "dd",
@@ -1026,8 +1087,11 @@ static BOOL notify2_unpack_msg( SPOOLSS_NOTIFY_MSG *msg, void *buf, size_t len )
                tdb_unpack((char *)buf + offset, len - offset, "B", 
                           &msg->len, &msg->notify.data);
 
-       DEBUG(3, ("notify2_unpack_msg: got NOTIFY2 message, type %d, field 0x%02x, flags 0x%04x\n",
-                 msg->type, msg->field, msg->flags));
+       DEBUG(3, ("notify2_unpack_msg: got NOTIFY2 message for printer %s, jobid %u type %d, field 0x%02x, flags 0x%04x\n",
+                 msg->printer, (unsigned int)msg->id, msg->type, msg->field, msg->flags));
+
+       tv->tv_sec = tv_sec;
+       tv->tv_usec = tv_usec;
 
        if (msg->len == 0)
                DEBUG(3, ("notify2_unpack_msg: value1 = %d, value2 = %d\n", msg->notify.value[0],
@@ -1038,6 +1102,58 @@ static BOOL notify2_unpack_msg( SPOOLSS_NOTIFY_MSG *msg, void *buf, size_t len )
        return True;
 }
 
+/* ENUMJOB last timestamp list. */
+struct ejts_list {
+       struct ejts_list *next, *prev;
+       char *printer_name;
+       struct timeval tv;
+};
+
+static struct ejts_list *ejts_head;
+
+static struct ejts_list *find_enumjobs_timestamp(const char *printer_name)
+{
+       struct ejts_list *ejtsl;
+
+       for( ejtsl = ejts_head; ejtsl; ejtsl = ejtsl->next)
+               if (strequal(ejtsl->printer_name, printer_name))
+                       return ejtsl;
+       return NULL;
+}
+
+static void set_enumjobs_timestamp(int snum)
+{
+       const char *printer_name = lp_const_servicename(snum);
+       struct ejts_list *ejtsl = find_enumjobs_timestamp(printer_name);
+
+       if (!ejtsl) {
+               ejtsl = (struct ejts_list *)malloc(sizeof(struct ejts_list));
+               if (!ejtsl)
+                       return;
+               ejtsl->printer_name = strdup(printer_name);
+               if (!ejtsl->printer_name) {
+                       SAFE_FREE(ejtsl);
+                       return;
+               }
+               DLIST_ADD(ejts_head, ejtsl);
+       }
+
+       gettimeofday(&ejtsl->tv, NULL);
+}
+
+static int timeval_diff(struct timeval *tv1, struct timeval *tv2)
+{
+       if (tv1->tv_sec > tv2->tv_sec)
+               return 1;
+       if (tv1->tv_sec < tv2->tv_sec)
+               return -1;
+       if (tv1->tv_usec > tv2->tv_usec)
+               return 1;
+       if (tv1->tv_usec < tv2->tv_usec)
+               return -1;
+       return 0;
+}
+
 /********************************************************************
  Receive a notify2 message list
  ********************************************************************/
@@ -1060,7 +1176,7 @@ static void receive_notify2_message_list(int msg_type, pid_t src, void *msg, siz
        msg_count = IVAL(buf, 0);
        msg_ptr = buf + 4;
 
-       DEBUG(5, ("receive_notify2_message_list: got %d messages in list\n", msg_count));
+       DEBUG(5, ("receive_notify2_message_list: got %lu messages in list\n", (unsigned long)msg_count));
 
        if (msg_count == 0) {
                DEBUG(0,("receive_notify2_message_list: bad message format (msg_count == 0) !\n"));
@@ -1079,8 +1195,9 @@ static void receive_notify2_message_list(int msg_type, pid_t src, void *msg, siz
         * call.  Therefore messages are grouped according to printer handle.
         */
         
-       for ( i=0; i<msg_count; i++ ) 
-       {
+       for ( i=0; i<msg_count; i++ ) {
+               struct timeval msg_tv;
+
                if (msg_ptr + 4 - buf > len) {
                        DEBUG(0,("receive_notify2_message_list: bad message format (len > buf_size) !\n"));
                        return;
@@ -1097,9 +1214,32 @@ static void receive_notify2_message_list(int msg_type, pid_t src, void *msg, siz
                /* unpack messages */
                
                ZERO_STRUCT( notify );
-               notify2_unpack_msg( &notify, msg_ptr, msg_len );
+               notify2_unpack_msg( &notify, &msg_tv, msg_ptr, msg_len );
                msg_ptr += msg_len;
                
+               /* See if it is still relevent. */
+               if (notify.type == JOB_NOTIFY_TYPE) {
+                       BOOL status_is_deleting = False;
+
+                       if (notify.field == JOB_NOTIFY_STATUS && (notify.notify.value[0] & (JOB_STATUS_DELETING|JOB_STATUS_DELETED)))
+                               status_is_deleting = True;
+
+                       if (!status_is_deleting) {
+                               struct ejts_list *ejtsl = find_enumjobs_timestamp(notify.printer);
+
+                               if (ejtsl && (timeval_diff(&ejtsl->tv, &msg_tv) > 0)) {
+
+                                       DEBUG(10, ("receive_notify2_message_list: enumjobs ts = %u, %u, msg ts = %u, %u discarding\n",
+                                               (unsigned int)ejtsl->tv.tv_sec, (unsigned int)ejtsl->tv.tv_usec,
+                                               (unsigned int)msg_tv.tv_sec, (unsigned int)msg_tv.tv_usec ));
+
+                                       /* Message no longer relevent. Ignore it. */
+                                       if ( notify.len != 0 )
+                                               SAFE_FREE( notify.notify.data );
+                                       continue;
+                               }
+                       }
+               }
                /* add to correct list in container */
                
                notify_msg_ctr_addmsg( &messages, &notify );
@@ -1149,7 +1289,7 @@ static BOOL srv_spoolss_drv_upgrade_printer(char* drivername)
 
 /**********************************************************************
  callback to receive a MSG_PRINTER_DRVUPGRADE message and interate
- over all printers, upgrading ones as neessary 
+ over all printers, upgrading ones as necessary 
  **********************************************************************/
  
 void do_drv_upgrade_printer(int msg_type, pid_t src, void *buf, size_t len)
@@ -1172,7 +1312,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 +1336,32 @@ void do_drv_upgrade_printer(int msg_type, pid_t src, void *buf, size_t len)
        /* all done */  
 }
 
+/********************************************************************
+ Update the cache 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 +1408,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 +1425,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 +1714,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;
@@ -1566,8 +1738,10 @@ Can't find printer handle we created for printer %s\n", name ));
                /* NT doesn't let us connect to a printer if the connecting user
                   doesn't have print permission.  */
 
-               if (!get_printer_snum(p, handle, &snum))
+               if (!get_printer_snum(p, handle, &snum)) {
+                       close_printer_handle(p, handle);
                        return WERR_BADFID;
+               }
 
                se_map_standard(&printer_default->access_required, &printer_std_mapping);
                
@@ -1589,7 +1763,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 +1799,16 @@ 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 ( (printer_default->access_required == PRINTER_ACCESS_ADMINISTER) 
+               && (RA_WIN2K == get_remote_arch()) )
+       {
+               DEBUG(10,("_spoolss_open_printer_ex: Enabling LAN/WAN hack for Win2k clients.\n"));
+               usleep( 500000 );
+       }
+
        return WERR_OK;
 }
 
@@ -1670,7 +1854,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 +2063,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 +2231,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 +2250,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 +2275,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 +2302,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 +2310,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 +2319,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 +2329,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,23 +2338,62 @@ 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
-               SIVAL(*data, 0, 3);
-#endif
+
+               /* Windows NT 4.0 seems to not allow uploading of drivers
+                  to a server that reports 0x3 as the MajorVersion.
+                  need to investigate more how Win2k gets around this .
+                  -- jerry */
+
+               if ( RA_WINNT == get_remote_arch() )
+                       SIVAL(*data, 0, 2);
+               else
+                       SIVAL(*data, 0, 3);
+               
+               *needed = 0x4;
+               return WERR_OK;
+       }
+
+       if (!StrCaseCmp(value, "MinorVersion")) {
+               *type = 0x4;
+               if((*data = (uint8 *)talloc(ctx, 4*sizeof(uint8) )) == NULL)
+                       return WERR_NOMEM;
+               SIVAL(*data, 0, 0);
                *needed = 0x4;
                return WERR_OK;
        }
 
-       if (!strcmp(value, "DefaultSpoolDirectory")) {
-               fstring string;
+       /* REG_BINARY
+        *  uint32 size          = 0x114
+        *  uint32 major         = 5
+        *  uint32 minor         = [0|1]
+        *  uint32 build         = [2195|2600]
+        *  extra unicode string = e.g. "Service Pack 3"
+        */
+       if (!StrCaseCmp(value, "OSVersion")) {
+               *type = 0x3;
+               *needed = 0x114;
+
+               if((*data = (uint8 *)talloc(ctx, (*needed)*sizeof(uint8) )) == NULL)
+                       return WERR_NOMEM;
+               ZERO_STRUCTP( *data );
+               
+               SIVAL(*data, 0, *needed);       /* size */
+               SIVAL(*data, 4, 5);             /* Windows 2000 == 5.0 */
+               SIVAL(*data, 8, 0);
+               SIVAL(*data, 12, 2195);         /* build */
+               
+               /* leave extra string empty */
+               
+               return WERR_OK;
+       }
+
 
-               fstrcpy(string, string_truncate(lp_serverstring(), MAX_SERVER_STRING_LENGTH));
+       if (!StrCaseCmp(value, "DefaultSpoolDirectory")) {
+               const char *string="C:\\PRINTERS";
                *type = 0x1;                    
                *needed = 2*(strlen(string)+1);         
                if((*data  = (uint8 *)talloc(ctx, ((*needed > in_size) ? *needed:in_size) *sizeof(uint8))) == NULL)
@@ -2175,8 +2408,8 @@ static WERROR getprinterdata_printer_server(TALLOC_CTX *ctx, fstring value, uint
                return WERR_OK;
        }
 
-       if (!strcmp(value, "Architecture")) {                   
-               pstring string="Windows NT x86";
+       if (!StrCaseCmp(value, "Architecture")) {                       
+               const char *string="Windows NT x86";
                *type = 0x1;                    
                *needed = 2*(strlen(string)+1); 
                if((*data  = (uint8 *)talloc(ctx, ((*needed > in_size) ? *needed:in_size) *sizeof(uint8))) == NULL)
@@ -2188,8 +2421,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 +2504,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;
+                       }
+                       SIVAL( *data, 0, 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 +2530,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,36 +2558,43 @@ 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, 
+                       struct in_addr *client_ip, 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"));
+               DEBUG(0,("spoolss_connect_to_client: unable to initialize client connection.\n"));
                return False;
        }
+       
+       if ( is_zero_ip(*client_ip) ) {
+               if(!resolve_name( remote_machine, &the_cli->dest_ip, 0x20)) {
+                       DEBUG(0,("spoolss_connect_to_client: Can't resolve address for %s\n", remote_machine));
+                       cli_shutdown(the_cli);
+               return False;
+               }
 
-       if(!resolve_name( remote_machine, &the_cli->dest_ip, 0x20)) {
-               DEBUG(0,("connect_to_client: Can't resolve address for %s\n", remote_machine));
-               cli_shutdown(the_cli);
-       return False;
+               if (ismyip(the_cli->dest_ip)) {
+                       DEBUG(0,("spoolss_connect_to_client: Machine %s is one of our addresses. Cannot add to ourselves.\n", remote_machine));
+                       cli_shutdown(the_cli);
+                       return False;
+               }
        }
-
-       if (ismyip(the_cli->dest_ip)) {
-               DEBUG(0,("connect_to_client: Machine %s is one of our addresses. Cannot add to ourselves.\n", remote_machine));
-               cli_shutdown(the_cli);
-               return False;
+       else {
+               the_cli->dest_ip.s_addr = client_ip->s_addr;
+               DEBUG(5,("spoolss_connect_to_client: Using address %s (no name resolution necessary)\n",
+                       inet_ntoa(*client_ip) ));
        }
 
        if (!cli_connect(the_cli, remote_machine, &the_cli->dest_ip)) {
-               DEBUG(0,("connect_to_client: unable to connect to SMB server on machine %s. Error was : %s.\n", remote_machine, cli_errstr(the_cli) ));
+               DEBUG(0,("spoolss_connect_to_client: unable to connect to SMB server on machine %s. Error was : %s.\n", remote_machine, cli_errstr(the_cli) ));
                cli_shutdown(the_cli);
                return False;
        }
   
-       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", 
+       if (!attempt_netbios_session_request(the_cli, global_myname(), remote_machine, &the_cli->dest_ip)) {
+               DEBUG(0,("spoolss_connect_to_client: machine %s rejected the NetBIOS session request.\n", 
                        remote_machine));
                cli_shutdown(the_cli);
                return False;
@@ -2323,13 +2603,13 @@ static BOOL spoolss_connect_to_client(struct cli_state *the_cli, char *remote_ma
        the_cli->protocol = PROTOCOL_NT1;
     
        if (!cli_negprot(the_cli)) {
-               DEBUG(0,("connect_to_client: machine %s rejected the negotiate protocol. Error was : %s.\n", remote_machine, cli_errstr(the_cli) ));
+               DEBUG(0,("spoolss_connect_to_client: machine %s rejected the negotiate protocol. Error was : %s.\n", remote_machine, cli_errstr(the_cli) ));
                cli_shutdown(the_cli);
                return False;
        }
 
        if (the_cli->protocol != PROTOCOL_NT1) {
-               DEBUG(0,("connect_to_client: machine %s didn't negotiate NT protocol.\n", remote_machine));
+               DEBUG(0,("spoolss_connect_to_client: machine %s didn't negotiate NT protocol.\n", remote_machine));
                cli_shutdown(the_cli);
                return False;
        }
@@ -2339,19 +2619,19 @@ static BOOL spoolss_connect_to_client(struct cli_state *the_cli, char *remote_ma
         */
     
        if (!cli_session_setup(the_cli, "", "", 0, "", 0, "")) {
-               DEBUG(0,("connect_to_client: machine %s rejected the session setup. Error was : %s.\n", remote_machine, cli_errstr(the_cli) ));
+               DEBUG(0,("spoolss_connect_to_client: machine %s rejected the session setup. Error was : %s.\n", remote_machine, cli_errstr(the_cli) ));
                cli_shutdown(the_cli);
                return False;
        }
     
        if (!(the_cli->sec_mode & 1)) {
-               DEBUG(0,("connect_to_client: machine %s isn't in user level security mode\n", remote_machine));
+               DEBUG(0,("spoolss_connect_to_client: machine %s isn't in user level security mode\n", remote_machine));
                cli_shutdown(the_cli);
                return False;
        }
     
        if (!cli_send_tconX(the_cli, "IPC$", "IPC", "", 1)) {
-               DEBUG(0,("connect_to_client: machine %s rejected the tconX on the IPC$ share. Error was : %s.\n", remote_machine, cli_errstr(the_cli) ));
+               DEBUG(0,("spoolss_connect_to_client: machine %s rejected the tconX on the IPC$ share. Error was : %s.\n", remote_machine, cli_errstr(the_cli) ));
                cli_shutdown(the_cli);
                return False;
        }
@@ -2361,8 +2641,8 @@ 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) {
-               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)));
+       if(cli_nt_session_open(the_cli, PI_SPOOLSS) == False) {
+               DEBUG(0,("spoolss_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);
                cli_shutdown(the_cli);
@@ -2376,20 +2656,22 @@ 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, struct in_addr *client_ip)
 {
        WERROR result;
 
        /*
         * If it's the first connection, contact the client
-        * and connect to the IPC$ share anonumously
+        * and connect to the IPC$ share anonymously
         */
        if (smb_connections==0) {
                fstring unix_printer;
 
                fstrcpy(unix_printer, printer+2); /* the +2 is to strip the leading 2 backslashs */
 
-               if(!spoolss_connect_to_client(&notify_cli, unix_printer))
+               if(!spoolss_connect_to_client(&notify_cli, client_ip, unix_printer))
                        return False;
                        
                message_register(MSG_PRINTER_NOTIFY2, receive_notify2_message_list);
@@ -2398,6 +2680,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,7 +2718,9 @@ 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;
+       struct in_addr client_ip;
 
        /* store the notify value in the printer struct */
 
@@ -2453,9 +2745,17 @@ 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;
+               
+       client_ip.s_addr = inet_addr(p->conn->client_address);
+
+       if(!srv_spoolss_replyopenprinter(snum, Printer->notify.localmachine,
                                        Printer->notify.printerlocal, 1,
-                                       &Printer->notify.client_hnd))
+                                       &Printer->notify.client_hnd, &client_ip))
                return WERR_SERVER_UNAVAILABLE;
 
        Printer->notify.client_connected=True;
@@ -2997,7 +3297,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 +3450,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 +3461,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 +3612,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 +3631,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 +3642,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 +3777,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 +3837,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 +3848,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 +3918,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 +3937,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 +3948,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 +3959,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,13 +4018,11 @@ 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
+       
+       /* in 2.2 we reported ourselves as 0x0004 and 0x0565 */
        printer->major_version = 0x0005;        /* NT 5 */
        printer->build_version = 0x0893;        /* build 2195 */
-#endif
+       
        printer->unknown7 = 0x1;
        printer->unknown8 = 0x0;
        printer->unknown9 = 0x0;
@@ -3757,13 +4055,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 +4160,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 +4193,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 +4256,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 +4311,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 +4331,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}", smb_uuid_string_static(guid));
+               strupper_m(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 +4393,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 +4562,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);
@@ -4389,7 +4714,7 @@ WERROR _spoolss_enumprinters( pipes_struct *p, SPOOL_Q_ENUMPRINTERS *q_u, SPOOL_
         */
 
        unistr2_to_ascii(name, servername, sizeof(name)-1);
-       strupper(name);
+       strupper_m(name);
 
        switch (level) {
        case 1:
@@ -4408,14 +4733,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 +4766,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 +4799,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 +4835,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 +4866,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 +4900,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 +4931,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 +4972,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 +4987,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 +5024,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 +5084,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 +5103,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;
 
@@ -4774,9 +5133,11 @@ static uint32 init_unistr_array(uint16 **uni_array, fstring *char_array, char *s
                else
                        pstrcpy( line, v );
                        
-               DEBUGADD(6,("%d:%s:%d\n", i, line, strlen(line)));
+               DEBUGADD(6,("%d:%s:%lu\n", i, line, (unsigned long)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 +5151,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 +5223,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 +5348,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 +5383,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 +5576,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 +5938,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 +5953,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 +5988,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 +6010,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 +6027,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;
        }
@@ -5708,6 +6065,9 @@ static WERROR update_printer(pipes_struct *p, POLICY_HND *handle, uint32 level,
                goto done;
        }
 
+       /* FIXME!!! If the driver has changed we really should verify that 
+          it is installed before doing much else   --jerry */
+
        /* Check calling user has permission to update printer description */
 
        if (Printer->access_granted != PRINTER_ACCESS_ADMINISTER) {
@@ -5717,12 +6077,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 +6117,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 +6183,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 +6239,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 +6252,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 +6259,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 +6335,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 +6342,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 +6440,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,
@@ -6055,6 +6501,7 @@ WERROR _spoolss_enumjobs( pipes_struct *p, SPOOL_Q_ENUMJOBS *q_u, SPOOL_R_ENUMJO
        uint32 offered = q_u->offered;
        uint32 *needed = &r_u->needed;
        uint32 *returned = &r_u->returned;
+       WERROR wret;
 
        int snum;
        print_status_struct prt_status;
@@ -6076,15 +6523,20 @@ WERROR _spoolss_enumjobs( pipes_struct *p, SPOOL_Q_ENUMJOBS *q_u, SPOOL_R_ENUMJO
        DEBUGADD(4,("count:[%d], status:[%d], [%s]\n", *returned, prt_status.status, prt_status.message));
 
        if (*returned == 0) {
+               set_enumjobs_timestamp(snum);
                SAFE_FREE(queue);
                return WERR_OK;
        }
 
        switch (level) {
        case 1:
-               return enumjobs_level1(queue, snum, buffer, offered, needed, returned);
+               wret = enumjobs_level1(queue, snum, buffer, offered, needed, returned);
+               set_enumjobs_timestamp(snum);
+               return wret;
        case 2:
-               return enumjobs_level2(queue, snum, buffer, offered, needed, returned);
+               wret = enumjobs_level2(queue, snum, buffer, offered, needed, returned);
+               set_enumjobs_timestamp(snum);
+               return wret;
        default:
                SAFE_FREE(queue);
                *returned=0;
@@ -6635,7 +7087,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 +7095,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");
@@ -6907,16 +7359,21 @@ static WERROR spoolss_addprinterex_level_2( pipes_struct *p, const UNISTR2 *uni_
                free_a_printer(&printer, 2);
                return WERR_PRINTER_ALREADY_EXISTS;
        }
+       
+       /* FIXME!!!  smbd should check to see if the driver is installed before
+          trying to add a printer like this  --jerry */
 
-       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;
@@ -7048,14 +7505,14 @@ WERROR _spoolss_addprinterdriver(pipes_struct *p, SPOOL_Q_ADDPRINTERDRIVER *q_u,
        /* BEGIN_ADMIN_LOG */
         switch(level) {
            case 3:
+               fstrcpy(driver_name, driver.info_3->name ? driver.info_3->name : "");
                sys_adminlog(LOG_INFO,"Added printer driver. Print driver name: %s. Print driver OS: %s. Administrator name: %s.",
-                       driver.info_3->name,drv_ver_to_os[driver.info_3->cversion],uidtoname(user.uid));
-               fstrcpy(driver_name, driver.info_3->name);
+                       driver_name, get_drv_ver_to_os(driver.info_3->cversion),uidtoname(user.uid));
                break;
            case 6:   
+               fstrcpy(driver_name, driver.info_6->name ?  driver.info_6->name : "");
                sys_adminlog(LOG_INFO,"Added printer driver. Print driver name: %s. Print driver OS: %s. Administrator name: %s.",
-                       driver.info_6->name,drv_ver_to_os[driver.info_6->version],uidtoname(user.uid));
-               fstrcpy(driver_name, driver.info_6->name);
+                       driver_name, get_drv_ver_to_os(driver.info_6->version),uidtoname(user.uid));
                break;
         }
        /* END_ADMIN_LOG */
@@ -7185,12 +7642,12 @@ static WERROR getprinterdriverdir_level_1(UNISTR2 *name, UNISTR2 *uni_environmen
 {
        pstring path;
        pstring long_archi;
-       pstring short_archi;
+       const char *short_archi;
        DRIVER_DIRECTORY_1 *info=NULL;
 
        unistr2_to_ascii(long_archi, uni_environment, sizeof(long_archi)-1);
 
-       if (get_short_archi(short_archi, long_archi)==False)
+       if (!(short_archi = get_short_archi(long_archi)))
                return WERR_INVALID_ENVIRONMENT;
 
        if((info=(DRIVER_DIRECTORY_1 *)malloc(sizeof(DRIVER_DIRECTORY_1))) == NULL)
@@ -7273,7 +7730,7 @@ WERROR _spoolss_enumprinterdata(pipes_struct *p, SPOOL_Q_ENUMPRINTERDATA *q_u, S
        Printer_entry   *Printer = find_printer_index_by_hnd(p, handle);
        int             snum;
        WERROR          result;
-       REGISTRY_VALUE  *val;
+       REGISTRY_VALUE  *val = NULL;
        NT_PRINTER_DATA *p_data;
        int             i, key_index, num_values;
        int             name_length;
@@ -7296,7 +7753,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;
                
@@ -7311,7 +7768,7 @@ WERROR _spoolss_enumprinterdata(pipes_struct *p, SPOOL_Q_ENUMPRINTERDATA *q_u, S
         * cf: MSDN EnumPrinterData remark section
         */
         
-       if ( !in_value_len && !in_data_len ) 
+       if ( !in_value_len && !in_data_len && (key_index != -1) 
        {
                DEBUGADD(6,("Activating NT mega-hack to find sizes\n"));
 
@@ -7351,8 +7808,9 @@ WERROR _spoolss_enumprinterdata(pipes_struct *p, SPOOL_Q_ENUMPRINTERDATA *q_u, S
         * the value len is wrong in NT sp3
         * that's the number of bytes not the number of unicode chars
         */
-        
-       val = regval_ctr_specific_value( &p_data->keys[key_index].values, idx );
+       
+       if ( key_index != -1 )
+               val = regval_ctr_specific_value( &p_data->keys[key_index].values, idx );
 
        if ( !val ) 
        {
@@ -7360,9 +7818,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 +7855,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;
@@ -7452,6 +7910,11 @@ WERROR _spoolss_setprinterdata( pipes_struct *p, SPOOL_Q_SETPRINTERDATA *q_u, SP
                return WERR_BADFID;
        }
 
+       if ( Printer->printer_type == PRINTER_HANDLE_IS_PRINTSERVER ) {
+               DEBUG(10,("_spoolss_setprinterdata: Not implemented for server handles yet\n"));
+               return WERR_INVALID_PARAM;
+       }
+
        if (!get_printer_snum(p,handle, &snum))
                return WERR_BADFID;
 
@@ -7470,7 +7933,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 +8025,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 +8069,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 +8140,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 +8208,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;
        }
@@ -8015,7 +8478,7 @@ WERROR _spoolss_enumprintmonitors(pipes_struct *p, SPOOL_Q_ENUMPRINTMONITORS *q_
 /****************************************************************************
 ****************************************************************************/
 
-static WERROR getjob_level_1(print_queue_struct *queue, int count, int snum, uint32 jobid, NEW_BUFFER *buffer, uint32 offered, uint32 *needed)
+static WERROR getjob_level_1(print_queue_struct **queue, int count, int snum, uint32 jobid, NEW_BUFFER *buffer, uint32 offered, uint32 *needed)
 {
        int i=0;
        BOOL found=False;
@@ -8024,23 +8487,21 @@ static WERROR getjob_level_1(print_queue_struct *queue, int count, int snum, uin
        info_1=(JOB_INFO_1 *)malloc(sizeof(JOB_INFO_1));
 
        if (info_1 == NULL) {
-               SAFE_FREE(queue);
                return WERR_NOMEM;
        }
                
        for (i=0; i<count && found==False; i++) { 
-               if (queue[i].job==(int)jobid)
+               if ((*queue)[i].job==(int)jobid)
                        found=True;
        }
        
        if (found==False) {
-               SAFE_FREE(queue);
                SAFE_FREE(info_1);
                /* NT treats not found as bad param... yet another bad choice */
                return WERR_INVALID_PARAM;
        }
        
-       fill_job_info_1(info_1, &(queue[i-1]), i, snum);
+       fill_job_info_1(info_1, &((*queue)[i-1]), i, snum);
        
        *needed += spoolss_size_job_info_1(info_1);
 
@@ -8062,7 +8523,7 @@ static WERROR getjob_level_1(print_queue_struct *queue, int count, int snum, uin
 /****************************************************************************
 ****************************************************************************/
 
-static WERROR getjob_level_2(print_queue_struct *queue, int count, int snum, uint32 jobid, NEW_BUFFER *buffer, uint32 offered, uint32 *needed)
+static WERROR getjob_level_2(print_queue_struct **queue, int count, int snum, uint32 jobid, NEW_BUFFER *buffer, uint32 offered, uint32 *needed)
 {
        int             i = 0;
        BOOL            found = False;
@@ -8083,7 +8544,7 @@ static WERROR getjob_level_2(print_queue_struct *queue, int count, int snum, uin
 
        for ( i=0; i<count && found==False; i++ ) 
        {
-               if (queue[i].job == (int)jobid)
+               if ((*queue)[i].job == (int)jobid)
                        found = True;
        }
        
@@ -8095,13 +8556,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,12 +8575,7 @@ 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);
+       fill_job_info_2(info_2, &((*queue)[i-1]), i, snum, ntprinter, devmode);
        
        *needed += spoolss_size_job_info_2(info_2);
 
@@ -8182,11 +8639,11 @@ WERROR _spoolss_getjob( pipes_struct *p, SPOOL_Q_GETJOB *q_u, SPOOL_R_GETJOB *r_
                
        switch ( level ) {
        case 1:
-                       wstatus = getjob_level_1(queue, count, snum, jobid, 
+                       wstatus = getjob_level_1(&queue, count, snum, jobid, 
                                buffer, offered, needed);
                        break;
        case 2:
-                       wstatus = getjob_level_2(queue, count, snum, jobid, 
+                       wstatus = getjob_level_2(&queue, count, snum, jobid, 
                                buffer, offered, needed);
                        break;
        default:
@@ -8244,7 +8701,7 @@ WERROR _spoolss_getprinterdataex(pipes_struct *p, SPOOL_Q_GETPRINTERDATAEX *q_u,
        /* Is the handle to a printer or to the server? */
 
        if (Printer->printer_type == PRINTER_HANDLE_IS_PRINTSERVER) {
-               DEBUG(10,("_spoolss_getprinterdatex: Not implemented for server handles yet\n"));
+               DEBUG(10,("_spoolss_getprinterdataex: Not implemented for server handles yet\n"));
                status = WERR_INVALID_PARAM;
                goto done;
        }
@@ -8252,7 +8709,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;
 
@@ -8326,10 +8783,15 @@ WERROR _spoolss_setprinterdataex(pipes_struct *p, SPOOL_Q_SETPRINTERDATAEX *q_u,
            SetPrinterData if key is "PrinterDriverData" */
 
        if (!Printer) {
-               DEBUG(2,("_spoolss_setprinterdata: Invalid handle (%s:%u:%u).\n", OUR_HANDLE(handle)));
+               DEBUG(2,("_spoolss_setprinterdataex: Invalid handle (%s:%u:%u).\n", OUR_HANDLE(handle)));
                return WERR_BADFID;
        }
 
+       if ( Printer->printer_type == PRINTER_HANDLE_IS_PRINTSERVER ) {
+               DEBUG(10,("_spoolss_setprinterdataex: Not implemented for server handles yet\n"));
+               return WERR_INVALID_PARAM;
+       }
+
        if ( !get_printer_snum(p,handle, &snum) )
                return WERR_BADFID;
 
@@ -8347,7 +8809,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 +8828,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 +8846,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 +8886,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 +8930,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 +9005,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 +9051,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;
        
@@ -8623,8 +9100,8 @@ WERROR _spoolss_enumprinterdataex(pipes_struct *p, SPOOL_Q_ENUMPRINTERDATAEX *q_
        {
                if ( (enum_values=talloc(p->mem_ctx, num_entries*sizeof(PRINTER_ENUM_VALUES))) == NULL )
                {
-                       DEBUG(0,("_spoolss_enumprinterdataex: talloc() failed to allocate memory for [%d] bytes!\n",
-                               num_entries*sizeof(PRINTER_ENUM_VALUES)));
+                       DEBUG(0,("_spoolss_enumprinterdataex: talloc() failed to allocate memory for [%lu] bytes!\n",
+                               (unsigned long)num_entries*sizeof(PRINTER_ENUM_VALUES)));
                        result = WERR_NOMEM;
                        goto done;
                }
@@ -8687,6 +9164,7 @@ WERROR _spoolss_enumprinterdataex(pipes_struct *p, SPOOL_Q_ENUMPRINTERDATAEX *q_
        
                
 done:  
+       if ( printer )
        free_a_printer(&printer, 2);
 
        return result;
@@ -8708,12 +9186,12 @@ static WERROR getprintprocessordirectory_level_1(UNISTR2 *name,
 {
        pstring path;
        pstring long_archi;
-       pstring short_archi;
+        const char *short_archi;
        PRINTPROCESSOR_DIRECTORY_1 *info=NULL;
 
        unistr2_to_ascii(long_archi, environment, sizeof(long_archi)-1);
 
-       if (get_short_archi(short_archi, long_archi)==False)
+       if (!(short_archi = get_short_archi(long_archi)))
                return WERR_INVALID_ENVIRONMENT;
 
        if((info=(PRINTPROCESSOR_DIRECTORY_1 *)malloc(sizeof(PRINTPROCESSOR_DIRECTORY_1))) == NULL)
@@ -8760,6 +9238,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;
        }