parse correctly getprinterdriver2
[kai/samba.git] / source / rpc_server / srv_spoolss_nt.c
index db48fa42ff400c8587d5457281b7bf76bca650d2..d0fc839154a0b909b44b3742e0c2a5c6e3aaa294 100644 (file)
@@ -39,43 +39,60 @@ extern pstring global_myname;
 /* and a reference to what it's pointing to */
 /* and the notify info asked about */
 /* that's the central struct */
-static struct
-{
-  BOOL        open;
-  BOOL        ok;
-  BOOL        document_started;
-  BOOL        page_started;
-  uint32      current_jobid;
-  uint32      document_fd;
-  uint32      document_lastwritten;
-  pstring     document_name;
-  pstring     job_name;
-  POLICY_HND printer_hnd;
-  BOOL        printer_type;
-  union
-  {
-       fstring printername;
-       fstring printerservername;
-  } dev;
-  uint32 type;
-  uint32 access;
-  uint32 number_of_notify;
-  SPOOL_NOTIFY_OPTION_TYPE notify_info[MAX_PRINTER_NOTIFY+MAX_JOB_NOTIFY];
-} Printer[MAX_OPEN_PRINTER_EXS];
-
-#define VALID_HANDLE(pnum)   (((pnum) >= 0) && ((pnum) < MAX_OPEN_PRINTER_EXS))
-#define OPEN_HANDLE(pnum)    (VALID_HANDLE(pnum) && Printer[pnum].open)
+typedef struct _Printer{
+       ubi_dlNode Next;
+       ubi_dlNode Prev;
+
+       BOOL open;
+       BOOL document_started;
+       BOOL page_started;
+       uint32 current_jobid;
+       uint32 document_fd;
+       uint32 document_lastwritten;
+       pstring document_name;
+       pstring job_name;
+       POLICY_HND printer_hnd;
+       BOOL printer_type;
+       union {
+               fstring printername;
+               fstring printerservername;
+       } dev;
+       uint32 type;
+       uint32 access;
+       struct {
+               uint32 flags;
+               uint32 options;
+               fstring localmachine; 
+               uint32 printerlocal;
+               SPOOL_NOTIFY_OPTION *option;
+       } notify;
+       struct {
+               fstring machine;
+               fstring user;
+       } client;
+} Printer_entry;
+
+typedef struct _counter_printer_0 {
+       ubi_dlNode Next;
+       ubi_dlNode Prev;
+       
+       int snum;
+       uint32 counter;
+} counter_printer_0;
+
+static ubi_dlList Printer_list;
+static ubi_dlList counter_list;
+
+
+#define OPEN_HANDLE(pnum)    ((pnum!=NULL) && (pnum->open!=False))
 
 /****************************************************************************
   initialise printer handle states...
 ****************************************************************************/
 void init_printer_hnd(void)
 {
-       int i;
-       for (i = 0; i < MAX_OPEN_PRINTER_EXS; i++)
-       {
-               Printer[i].open = False;
-       }
+       ubi_dlInitList(&Printer_list);
+       ubi_dlInitList(&counter_list);
 }
 
 /****************************************************************************
@@ -102,22 +119,25 @@ static void create_printer_hnd(POLICY_HND *hnd)
 /****************************************************************************
   find printer index by handle
 ****************************************************************************/
-static int find_printer_index_by_hnd(const POLICY_HND *hnd)
+static Printer_entry *find_printer_index_by_hnd(const POLICY_HND *hnd)
 {
-       int i;
+       Printer_entry *find_printer;
 
-       for (i = 0; i < MAX_OPEN_PRINTER_EXS; i++)
-       {
-               if (memcmp(&(Printer[i].printer_hnd), hnd, sizeof(*hnd)) == 0)
+       find_printer = (Printer_entry *)ubi_dlFirst(&Printer_list);
+
+       for(; find_printer; find_printer = (Printer_entry *)ubi_dlNext(find_printer)) {
+
+               if (memcmp(&(find_printer->printer_hnd), hnd, sizeof(*hnd)) == 0)
                {
-                       DEBUG(4,("Found printer handle[%x] ", i));
-                       dump_data(4, hnd->data, sizeof(hnd->data));
-                       return i;
+                       DEBUG(4,("Found printer handle \n"));
+                       /*dump_data(4, hnd->data, sizeof(hnd->data));*/
+                       return find_printer;
                }
        }
+       
        DEBUG(3,("Whoops, Printer handle not found: "));
-       dump_data(4, hnd->data, sizeof(hnd->data));
-       return -1;
+       /*dump_data(4, hnd->data, sizeof(hnd->data));*/
+       return NULL;
 }
 
 /****************************************************************************
@@ -125,7 +145,7 @@ static int find_printer_index_by_hnd(const POLICY_HND *hnd)
 ****************************************************************************/
 static void clear_handle(POLICY_HND *hnd)
 {
-       bzero(hnd->data, POLICY_HND_SIZE);
+       memset(hnd->data, 0, POLICY_HND_SIZE);
 }
 
 /****************************************************************************
@@ -133,17 +153,28 @@ static void clear_handle(POLICY_HND *hnd)
 ****************************************************************************/
 static BOOL close_printer_handle(POLICY_HND *hnd)
 {
-       int pnum = find_printer_index_by_hnd(hnd);
+       Printer_entry *Printer = find_printer_index_by_hnd(hnd);
 
-       if (pnum == -1)
+       if (!OPEN_HANDLE(Printer))
        {
-               DEBUG(3,("Error closing printer handle (pnum=%x)\n", pnum));
+               DEBUG(3,("Error closing printer handle\n"));
                return False;
        }
 
-       Printer[pnum].open=False;
+       Printer->open=False;
+       Printer->notify.flags=0;
+       Printer->notify.options=0;
+       Printer->notify.localmachine[0]='\0';
+       Printer->notify.printerlocal=0;
+       safe_free(Printer->notify.option);
+       Printer->notify.option=NULL;
+       
        clear_handle(hnd);
 
+       ubi_dlRemThis(&Printer_list, Printer);
+
+       safe_free(Printer);
+
        return True;
 }      
 
@@ -153,23 +184,23 @@ static BOOL close_printer_handle(POLICY_HND *hnd)
 static BOOL get_printer_snum(const POLICY_HND *hnd, int *number)
 {
        int snum;
-       int pnum = find_printer_index_by_hnd(hnd);
+       Printer_entry *Printer = find_printer_index_by_hnd(hnd);
        int n_services=lp_numservices();
                
-       if (!OPEN_HANDLE(pnum)) {
+       if (!OPEN_HANDLE(Printer))      {
                DEBUG(3,("Error getting printer - take a nap quickly !\n"));
                return False;
        }
        
-       switch (Printer[pnum].printer_type) {
+       switch (Printer->printer_type) {
        case PRINTER_HANDLE_IS_PRINTER:            
-               DEBUG(4,("short name:%s\n", Printer[pnum].dev.printername));                    
+               DEBUG(4,("short name:%s\n", Printer->dev.printername));                 
                for (snum=0;snum<n_services; snum++) {
                        if (lp_browseable(snum) && lp_snum_ok(snum) && lp_print_ok(snum) ) {
                                DEBUG(4,("share:%s\n",lp_servicename(snum)));
-                               if (   ( strlen(lp_servicename(snum)) == strlen( Printer[pnum].dev.printername ) ) 
+                               if (   ( strlen(lp_servicename(snum)) == strlen( Printer->dev.printername ) ) 
                                    && ( !strncasecmp(lp_servicename(snum), 
-                                                     Printer[pnum].dev.printername,
+                                                     Printer->dev.printername,
                                                      strlen( lp_servicename(snum) ))) ) {
                                        DEBUG(4,("Printer found: %s[%x]\n",lp_servicename(snum),snum));
                                        *number=snum;
@@ -194,24 +225,19 @@ static BOOL get_printer_snum(const POLICY_HND *hnd, int *number)
  ****************************************************************************/
 static BOOL open_printer_hnd(POLICY_HND *hnd)
 {
-       int i;
+       Printer_entry *new_printer;
 
-       for (i = 0; i < MAX_OPEN_PRINTER_EXS; i++)
-       {
-               if (!Printer[i].open)
-               {
-                       Printer[i].open = True; 
-                       Printer[i].ok = True;   
-               
-                       memcpy(&(Printer[i].printer_hnd), hnd, sizeof(*hnd));
+       new_printer=(Printer_entry *)malloc(sizeof(Printer_entry));
+       ZERO_STRUCTP(new_printer);
+       
+       new_printer->open = True;
+       new_printer->notify.option=NULL;
+                               
+       memcpy(&(new_printer->printer_hnd), hnd, sizeof(*hnd));
+       
+       ubi_dlAddHead( &Printer_list, (ubi_dlNode *)new_printer);
 
-                       DEBUG(4,("Opened printer handle[%x] ", i));
-                       dump_data(4, hnd->data, sizeof(hnd->data));
-                       return True;
-               }
-       }
-       DEBUG(1,("ERROR - open_printer_hnd: out of Printers Handles!\n"));
-       return False;
+       return True;
 }
 
 /****************************************************************************
@@ -219,34 +245,16 @@ static BOOL open_printer_hnd(POLICY_HND *hnd)
 ****************************************************************************/
 static BOOL set_printer_hnd_accesstype(POLICY_HND *hnd, uint32 access_required)
 {
-       int pnum = find_printer_index_by_hnd(hnd);
+       Printer_entry *Printer = find_printer_index_by_hnd(hnd);
 
-       if (OPEN_HANDLE(pnum)) {
-               DEBUG(4,("Setting printer access=%x (pnum=%x)\n", access_required, pnum));
-               Printer[pnum].access = access_required;
-               return True;            
-       }
-       else {
-               DEBUG(4,("Error setting printer type=%x (pnum=%x)", access_required, pnum));
+       if (!OPEN_HANDLE(Printer)) {
+               DEBUG(4,("Error setting printer type=%x", access_required));
                return False;
        }
-       return False;
-}
 
-/****************************************************************************
-  .
-****************************************************************************/
-static BOOL printer_entry_is_valid(POLICY_HND *hnd)
-{
-       int pnum = find_printer_index_by_hnd(hnd);
-
-       if (!OPEN_HANDLE(pnum))
-               return False;           
-       
-       if (Printer[pnum].ok == False)
-               return False;
-               
-       return True;
+       DEBUG(4,("Setting printer access=%x\n", access_required));
+       Printer->access = access_required;
+       return True;            
 }
 
 /****************************************************************************
@@ -255,34 +263,30 @@ static BOOL printer_entry_is_valid(POLICY_HND *hnd)
 ****************************************************************************/
 static BOOL set_printer_hnd_printertype(POLICY_HND *hnd, char *printername)
 {
-       int pnum = find_printer_index_by_hnd(hnd);
+       Printer_entry *Printer = find_printer_index_by_hnd(hnd);
                
-       if (!OPEN_HANDLE(pnum)) {
-               DEBUGADD(4,("Error setting printer name %s (pnum=%x)", printername, pnum));
+       if (!OPEN_HANDLE(Printer)) {
+               DEBUGADD(4,("Error setting printer name %s", printername));
                return False;
        }
        
-       DEBUG(3,("Setting printer type=%s (pnum=%x)\n", printername, pnum));
+       DEBUG(3,("Setting printer type=%s\n", printername));
 
        if ( strlen(printername) < 3 ) {
                DEBUGADD(4,("A print server must have at least 1 char ! %s\n", printername));
-               Printer[pnum].ok=False;
                return False;
        }
 
        /* it's a print server */
        if (!strchr(printername+2, '\\')) {
                DEBUGADD(4,("Printer is a print server\n"));
-               Printer[pnum].printer_type = PRINTER_HANDLE_IS_PRINTSERVER;
-               Printer[pnum].ok=True;
-               
+               Printer->printer_type = PRINTER_HANDLE_IS_PRINTSERVER;          
                return True;
        }
        /* it's a printer */
        else {
                DEBUGADD(4,("Printer is a printer\n"));
-               Printer[pnum].printer_type = PRINTER_HANDLE_IS_PRINTER;
-               Printer[pnum].ok=True;
+               Printer->printer_type = PRINTER_HANDLE_IS_PRINTER;
                return True;
        }
 
@@ -294,83 +298,130 @@ static BOOL set_printer_hnd_printertype(POLICY_HND *hnd, char *printername)
 ****************************************************************************/
 static BOOL set_printer_hnd_printername(POLICY_HND *hnd, char *printername)
 {
-       int pnum = find_printer_index_by_hnd(hnd);
-       char *back;
+       Printer_entry *Printer = find_printer_index_by_hnd(hnd);
        NT_PRINTER_INFO_LEVEL printer;
        int snum;
        int n_services=lp_numservices();
-       uint32 marche;
+       char *aprinter;
+       BOOL found=False;
        
-       if (!OPEN_HANDLE(pnum))
+       if (!OPEN_HANDLE(Printer))
        {
-               DEBUG(0,("Error setting printer name=%s (pnum=%x)\n", printername, pnum));
+               DEBUG(0,("Error setting printer name=%s\n", printername));
                return False;
        }
 
-       DEBUG(4,("Setting printer name=%s (len=%d) (pnum=%x)\n", printername, strlen(printername), pnum));
+       DEBUG(4,("Setting printer name=%s (len=%d)\n", printername, strlen(printername)));
 
-       switch (Printer[pnum].printer_type) {
-       case PRINTER_HANDLE_IS_PRINTSERVER:
-               ZERO_STRUCT(Printer[pnum].dev.printerservername);
-               strncpy(Printer[pnum].dev.printerservername, printername, strlen(printername));
+       if (Printer->printer_type==PRINTER_HANDLE_IS_PRINTSERVER) {
+               ZERO_STRUCT(Printer->dev.printerservername);
+               strncpy(Printer->dev.printerservername, printername, strlen(printername));
                return True;
-               break;
+       }
 
-       case PRINTER_HANDLE_IS_PRINTER:
-               back=strchr(printername+2, '\\');
-               back=back+1;
-               DEBUGADD(5,("searching for %s (len=%d)\n", back,strlen(back)));
-               /*
-                * store the Samba share name in it
-                * in back we have the long printer name
-                * need to iterate all the snum and do a
-                * get_a_printer each time to find the printer
-                * faster to do it here than later.
-                */
-               for (snum=0;snum<n_services; snum++) {
-                       if (lp_browseable(snum) && lp_snum_ok(snum) && lp_print_ok(snum) ) {
-                               DEBUGADD(5,("share:%s\n",lp_servicename(snum)));
-
-                               marche=get_a_printer(&printer, 2, lp_servicename(snum));
-                               DEBUGADD(6,("marche:%d\n",marche));
-
-                               if ( marche==0 && ( strlen(printer.info_2->printername) == strlen(back) )
-                                    && ( !strncasecmp(printer.info_2->printername, back, strlen(back)))
-                                  ) {
-                                       DEBUGADD(4,("Printer found: %s[%x]\n",lp_servicename(snum),snum));
-                                       ZERO_STRUCT(Printer[pnum].dev.printername);
-                                       strncpy(Printer[pnum].dev.printername, lp_servicename(snum), strlen(lp_servicename(snum)));
-                                       free_a_printer(printer, 2);
-                                       return True;
-                                       break;
-                               }
-                               free_a_printer(printer, 2);
-                       }
-               }
+       if (Printer->printer_type!=PRINTER_HANDLE_IS_PRINTER)
                return False;
-               break;
-                               
-          default:
+       
+       aprinter=strchr(printername+2, '\\');
+       aprinter++;
+
+       DEBUGADD(5,("searching for [%s] (len=%d)\n", aprinter, strlen(aprinter)));
+       /*
+        * store the Samba share name in it
+        * in back we have the long printer name
+        * need to iterate all the snum and do a
+        * get_a_printer each time to find the printer
+        * faster to do it here than later.
+        */
+
+       for (snum=0;snum<n_services && found==False;snum++) {
+       
+               if ( !(lp_browseable(snum) && lp_snum_ok(snum) && lp_print_ok(snum) ) )
+                       continue;
+               
+               DEBUGADD(5,("share:%s\n",lp_servicename(snum)));
+
+               if (get_a_printer(&printer, 2, lp_servicename(snum))!=0)
+                       continue;
+
+               if ( strlen(printer.info_2->printername) != strlen(aprinter) ) {
+                       free_a_printer(printer, 2);
+                       continue;
+               }
+               
+               if ( strncasecmp(printer.info_2->printername, aprinter, strlen(aprinter)))  {
+                       free_a_printer(printer, 2);
+                       continue;
+               }
+               
+               found=True;
+       }
+
+       if (found==False)
+       {
+               DEBUGADD(4,("Printer not found\n"));
                return False;
-               break;
-        }
+       }
+       
+       snum--;
+       DEBUGADD(4,("Printer found: %s[%x]\n",lp_servicename(snum),snum));
+       ZERO_STRUCT(Printer->dev.printername);
+       strncpy(Printer->dev.printername, lp_servicename(snum), strlen(lp_servicename(snum)));
+       free_a_printer(printer, 2);
+       
+       return True;
 }
 
 /********************************************************************
+ Return True is the handle is a print server.
  ********************************************************************/
 static BOOL handle_is_printserver(const POLICY_HND *handle)
 {
-       int pnum=find_printer_index_by_hnd(handle);
+       Printer_entry *Printer=find_printer_index_by_hnd(handle);
 
-       if (!OPEN_HANDLE(pnum))
+       if (!OPEN_HANDLE(Printer))
                return False;
                
-       if (Printer[pnum].printer_type != PRINTER_HANDLE_IS_PRINTSERVER)
+       if (Printer->printer_type != PRINTER_HANDLE_IS_PRINTSERVER)
                return False;
        
        return True;
 }
 
+/****************************************************************************
+ allocate more memory for a BUFFER.
+****************************************************************************/
+static BOOL alloc_buffer_size(NEW_BUFFER *buffer, uint32 buffer_size)
+{
+       prs_struct *ps;
+       uint32 extra_space;
+       uint32 old_offset;
+       
+       ps=&(buffer->prs);
+
+       /* damn, I'm doing the reverse operation of prs_grow() :) */
+       if (buffer_size < prs_data_size(ps))
+               extra_space=0;
+       else    
+               extra_space = buffer_size - prs_data_size(ps);
+
+       /* 
+        * save the offset and move to the end of the buffer
+        * prs_grow() checks the extra_space against the offset 
+        */
+       old_offset=prs_offset(ps);      
+       prs_set_offset(ps, prs_data_size(ps));
+       
+       if (!prs_grow(ps, extra_space))
+               return False;
+
+       prs_set_offset(ps, old_offset);
+
+       buffer->string_at_end=prs_data_size(ps);
+
+       return True;
+}
+
 /********************************************************************
  * spoolss_open_printer
  *
@@ -381,9 +432,7 @@ uint32 _spoolss_open_printer_ex( const UNISTR2 *printername,
                                 uint32  user_switch, SPOOL_USER_CTR user_ctr,
                                 POLICY_HND *handle)
 {
-       BOOL printer_open = False;
        fstring name;
-       fstring datatype;
        
        clear_handle(handle);
        
@@ -400,9 +449,15 @@ uint32 _spoolss_open_printer_ex( const UNISTR2 *printername,
 
        open_printer_hnd(handle);
        
-       set_printer_hnd_printertype(handle, name);
+       if (!set_printer_hnd_printertype(handle, name)) {
+               close_printer_handle(handle);
+               return NT_STATUS_ACCESS_DENIED;
+       }
        
-       set_printer_hnd_printername(handle, name);
+       if (!set_printer_hnd_printername(handle, name)) {
+               close_printer_handle(handle);
+               return NT_STATUS_ACCESS_DENIED;
+       }
 
 /*
        if (printer_default->datatype_ptr != NULL)
@@ -414,68 +469,49 @@ uint32 _spoolss_open_printer_ex( const UNISTR2 *printername,
                set_printer_hnd_datatype(handle, "");
 */
        
-       set_printer_hnd_accesstype(handle, printer_default->access_required);
-
-       if (!printer_entry_is_valid(handle))
-       {
+       if (!set_printer_hnd_accesstype(handle, printer_default->access_required)) {
                close_printer_handle(handle);
                return NT_STATUS_ACCESS_DENIED;
        }
-       
+               
        return NT_STATUS_NO_PROBLEMO;
 }
 
+/****************************************************************************
+****************************************************************************/
 static BOOL convert_printer_info(const SPOOL_PRINTER_INFO_LEVEL *uni,
-                          NT_PRINTER_INFO_LEVEL *printer,
-                         uint32 level)
+                               NT_PRINTER_INFO_LEVEL *printer, uint32 level)
 {
-       switch (level)
-       {
+       switch (level) {
                case 2: 
-               {
-                       uni_2_asc_printer_info_2(uni->info_2,
-                                                &(printer->info_2));
+                       uni_2_asc_printer_info_2(uni->info_2, &(printer->info_2));
                        break;
-               }
                default:
                        break;
        }
-       
-
 
        return True;
 }
 
 static BOOL convert_printer_driver_info(const SPOOL_PRINTER_DRIVER_INFO_LEVEL *uni,
-                                 NT_PRINTER_DRIVER_INFO_LEVEL *printer,
-                                uint32 level)
+                                       NT_PRINTER_DRIVER_INFO_LEVEL *printer, uint32 level)
 {
-       switch (level)
-       {
+       switch (level) {
                case 3: 
-               {
                        printer->info_3=NULL;
                        uni_2_asc_printer_driver_3(uni->info_3, &(printer->info_3));                                            
                        break;
-               }
                default:
                        break;
        }
-       
-
 
        return True;
 }
 
 static BOOL convert_devicemode(DEVICEMODE devmode, NT_DEVICEMODE *nt_devmode)
 {
-       unistr_to_ascii(nt_devmode->devicename,
-                       devmode.devicename.buffer,
-                       31);
-
-       unistr_to_ascii(nt_devmode->formname,
-                       devmode.formname.buffer,
-                       31);
+       unistr_to_ascii(nt_devmode->devicename, devmode.devicename.buffer, 31);
+       unistr_to_ascii(nt_devmode->formname, devmode.formname.buffer, 31);
 
        nt_devmode->specversion=devmode.specversion;
        nt_devmode->driverversion=devmode.driverversion;
@@ -510,7 +546,7 @@ static BOOL convert_devicemode(DEVICEMODE devmode, NT_DEVICEMODE *nt_devmode)
        nt_devmode->reserved2=devmode.reserved2;
        nt_devmode->panningwidth=devmode.panningwidth;
        nt_devmode->panningheight=devmode.panningheight;
-       
+
        if (nt_devmode->driverextra != 0) 
        {
                /* if we had a previous private delete it and make a new one */
@@ -519,7 +555,6 @@ static BOOL convert_devicemode(DEVICEMODE devmode, NT_DEVICEMODE *nt_devmode)
                nt_devmode->private=(uint8 *)malloc(nt_devmode->driverextra * sizeof(uint8));
                memcpy(nt_devmode->private, devmode.private, nt_devmode->driverextra);
        }
-       
 
        return True;
 }
@@ -536,16 +571,19 @@ uint32 _spoolss_closeprinter(POLICY_HND *handle)
 }
 
 /********************************************************************
- ********************************************************************/
-static BOOL getprinterdata_printer_server(fstring value, uint32 *type, uint8 **data, uint32 *needed)
+ GetPrinterData on a printer server Handle.
+********************************************************************/
+static BOOL getprinterdata_printer_server(fstring value, uint32 *type, uint8 **data, uint32 *needed, uint32 in_size)
 {              
        int i;
+       
+       DEBUG(8,("getprinterdata_printer_server:%s\n", value));
                
        if (!strcmp(value, "BeepEnabled"))
        {
                *type = 0x4;
                *data = (uint8 *)malloc( 4*sizeof(uint8) );
-               SIVAL(data, 0, 0x01);
+               SIVAL(*data, 0, 0x01);
                *needed = 0x4;                  
                return True;
        }
@@ -554,7 +592,7 @@ static BOOL getprinterdata_printer_server(fstring value, uint32 *type, uint8 **d
        {
                *type = 0x4;
                *data = (uint8 *)malloc( 4*sizeof(uint8) );
-               SIVAL(data, 0, 0x1B);
+               SIVAL(*data, 0, 0x1B);
                *needed = 0x4;                  
                return True;
        }
@@ -563,7 +601,7 @@ static BOOL getprinterdata_printer_server(fstring value, uint32 *type, uint8 **d
        {
                *type = 0x4;
                *data = (uint8 *)malloc( 4*sizeof(uint8) );
-               SIVAL(data, 0, 0x01);
+               SIVAL(*data, 0, 0x01);
                *needed = 0x4;
                return True;
        }
@@ -572,23 +610,23 @@ static BOOL getprinterdata_printer_server(fstring value, uint32 *type, uint8 **d
        {
                *type = 0x4;
                *data = (uint8 *)malloc( 4*sizeof(uint8) );
-               SIVAL(data, 0, 0x02);
+               SIVAL(*data, 0, 0x02);
                *needed = 0x4;
                return True;
        }
 
        if (!strcmp(value, "DefaultSpoolDirectory"))
        {
-               pstring directory="You are using a Samba server";
+               pstring string="You are using a Samba server";
                *type = 0x1;                    
-               *needed = 2*(strlen(directory)+1);
-               *data  = (uint8 *)malloc(*needed *sizeof(uint8));
-               ZERO_STRUCTP(*data);
+               *needed = 2*(strlen(string)+1);         
+               *data  = (uint8 *)malloc( ((*needed > in_size) ? *needed:in_size) *sizeof(uint8));
+               memset(*data, 0, (*needed > in_size) ? *needed:in_size);
                
                /* it's done by hand ready to go on the wire */
-               for (i=0; i<strlen(directory); i++)
+               for (i=0; i<strlen(string); i++)
                {
-                       (*data)[2*i]=directory[i];
+                       (*data)[2*i]=string[i];
                        (*data)[2*i+1]='\0';
                }                       
                return True;
@@ -596,14 +634,14 @@ static BOOL getprinterdata_printer_server(fstring value, uint32 *type, uint8 **d
 
        if (!strcmp(value, "Architecture"))
        {                       
-               pstring directory="Windows NT x86";
+               pstring string="Windows NT x86";
                *type = 0x1;                    
-               *needed = 2*(strlen(directory)+1);      
-               *data  = (uint8 *)malloc(*needed *sizeof(uint8));
-               ZERO_STRUCTP(*data);
-               for (i=0; i<strlen(directory); i++)
+               *needed = 2*(strlen(string)+1); 
+               *data  = (uint8 *)malloc( ((*needed > in_size) ? *needed:in_size) *sizeof(uint8));
+               memset(*data, 0, (*needed > in_size) ? *needed:in_size);
+               for (i=0; i<strlen(string); i++)
                {
-                       (*data)[2*i]=directory[i];
+                       (*data)[2*i]=string[i];
                        (*data)[2*i+1]='\0';
                }                       
                return True;
@@ -613,30 +651,30 @@ static BOOL getprinterdata_printer_server(fstring value, uint32 *type, uint8 **d
 }
 
 /********************************************************************
- ********************************************************************/
+ GetPrinterData on a printer Handle.
+********************************************************************/
 static BOOL getprinterdata_printer(const POLICY_HND *handle,
                                fstring value, uint32 *type, 
-                               uint8 **data, uint32 *needed )
+                               uint8 **data, uint32 *needed, uint32 in_size )
 {
        NT_PRINTER_INFO_LEVEL printer;
-       int pnum=0;
        int snum=0;
        uint8 *idata=NULL;
        uint32 len;
+       Printer_entry *Printer = find_printer_index_by_hnd(handle);
        
        DEBUG(5,("getprinterdata_printer\n"));
 
-       pnum = find_printer_index_by_hnd(handle);
-       if (OPEN_HANDLE(pnum))
+       if (OPEN_HANDLE(Printer))
        {
                get_printer_snum(handle, &snum);                
                get_a_printer(&printer, 2, lp_servicename(snum));
                
                if (get_specific_param(printer, 2, value, &idata, type, &len)) 
                {
-                       *data  = (uint8 *)malloc( len*sizeof(uint8) );
-                       bzero(*data, sizeof(uint8)*len);
-                       memcpy(*data, idata, len);
+                       *data  = (uint8 *)malloc( (len>in_size)?len:in_size *sizeof(uint8) );
+                       memset(*data, 0, sizeof(uint8)*len);
+                       memcpy(*data, idata, (len>in_size)?len:in_size);
                        *needed = len;
                        
                        if (idata) free(idata);
@@ -659,8 +697,8 @@ uint32 _spoolss_getprinterdata(const POLICY_HND *handle, UNISTR2 *valuename,
                                uint32 *needed)
 {
        fstring value;
-       BOOL found;
-       int pnum = find_printer_index_by_hnd(handle);
+       BOOL found=False;
+       Printer_entry *Printer = find_printer_index_by_hnd(handle);
        
        /* 
         * Reminder: when it's a string, the length is in BYTES
@@ -672,11 +710,12 @@ uint32 _spoolss_getprinterdata(const POLICY_HND *handle, UNISTR2 *valuename,
        *out_size=in_size;
 
        /* in case of problem, return some default values */
-       *needed=in_size;
-       *type=4;
+       *needed=0;
+       *type=0;
        
+       DEBUG(4,("_spoolss_getprinterdata\n"));
        
-       if (!OPEN_HANDLE(pnum)) {
+       if (!OPEN_HANDLE(Printer)) {
                *data=(uint8 *)malloc(4*sizeof(uint8));
                return NT_STATUS_INVALID_HANDLE;
        }
@@ -684,13 +723,14 @@ uint32 _spoolss_getprinterdata(const POLICY_HND *handle, UNISTR2 *valuename,
        unistr2_to_ascii(value, valuename, sizeof(value)-1);
        
        if (handle_is_printserver(handle))
-               found=getprinterdata_printer_server(value, type, data, needed);
+               found=getprinterdata_printer_server(value, type, data, needed, *out_size);
        else
-               found=getprinterdata_printer(handle, value, type, data, needed);
+               found=getprinterdata_printer(handle, value, type, data, needed, *out_size);
 
        if (found==False) {
                /* reply this param doesn't exist */
                *data=(uint8 *)malloc(4*sizeof(uint8));
+               memset(*data, 0x0, 4);
                return ERROR_INVALID_PARAMETER;
        }
        
@@ -711,42 +751,24 @@ uint32 _spoolss_getprinterdata(const POLICY_HND *handle, UNISTR2 *valuename,
  * in fact ReplyOpenPrinter is the changenotify equivalent on the spoolss pipe
  * called from api_spoolss_rffpcnex 
  ********************************************************************/
-uint32 _spoolss_rffpcnex(const POLICY_HND *handle,
-                               uint32 flags, uint32 options,
-                               const UNISTR2 *localmachine,
-                               uint32  printerlocal,
-                               SPOOL_NOTIFY_OPTION *option)
+uint32 _spoolss_rffpcnex(const POLICY_HND *handle, uint32 flags, uint32 options,
+                        const UNISTR2 *localmachine, uint32 printerlocal,
+                        SPOOL_NOTIFY_OPTION *option)
 {
-       int i,j,k;
-
        /* store the notify value in the printer struct */
 
-       i=find_printer_index_by_hnd(handle);
+       Printer_entry *Printer=find_printer_index_by_hnd(handle);
 
-       if (i == -1)
-       {
+       if (!OPEN_HANDLE(Printer))
                return NT_STATUS_INVALID_HANDLE;
-       }
-
-       Printer[i].number_of_notify=option->count;
-
-       DEBUG(3,("Copying %x notify option info\n",Printer[i].number_of_notify));
 
-       for (j=0;j<Printer[i].number_of_notify;j++)
-       {
-               Printer[i].notify_info[j].count=option->type[j].count;
-               Printer[i].notify_info[j].type=option->type[j].type     ;
-               
-               DEBUG(4,("Copying %x info fields of type %x\n",
-                        Printer[i].notify_info[j].count,
-                        Printer[i].notify_info[j].type));
-               for(k=0;k<Printer[i].notify_info[j].count;k++)
-               {
-                       Printer[i].notify_info[j].fields[k]=option->type[j].fields[k];
-               }
-       }
+       Printer->notify.flags=flags;
+       Printer->notify.options=options;
+       Printer->notify.printerlocal=printerlocal;
+       Printer->notify.option=option;
+       unistr2_to_ascii(Printer->notify.localmachine, localmachine, sizeof(Printer->notify.localmachine)-1);
 
-       return 0x0;
+       return NT_STATUS_NO_PROBLEMO;
 }
 
 /*******************************************************************
@@ -959,10 +981,8 @@ static void spoolss_notify_status(int snum, SPOOL_NOTIFY_INFO_DATA *data, print_
        print_queue_struct *q=NULL;
        print_status_struct status;
 
-       bzero(&status,sizeof(status));
-
+       memset(&status, 0, sizeof(status));
        count=get_printqueue(snum, NULL, &q, &status);
-
        data->notify_data.value[0]=(uint32) status.status;
        if (q) free(q);
 }
@@ -975,8 +995,7 @@ static void spoolss_notify_cjobs(int snum, SPOOL_NOTIFY_INFO_DATA *data, print_q
        print_queue_struct *q=NULL;
        print_status_struct status;
 
-       bzero(&status,sizeof(status));
-
+       memset(&status, 0, sizeof(status));
        data->notify_data.value[0]=get_printqueue(snum, NULL, &q, &status);
        if (q) free(q);
 }
@@ -1161,40 +1180,30 @@ static int search_notify(uint16 type, uint16 field, int *value)
        int j;
        BOOL found;
 
-       DEBUG(4,("\tsearch_notify: in\n"));     
        for (j=0, found=False; found==False && notify_info_data_table[j].type != END ; j++)
        {
                if ( (notify_info_data_table[j].type  == type  ) &&
                     (notify_info_data_table[j].field == field ) )
-               {
                        found=True;
-               }
        }
        *value=--j;
 
        if ( found && (notify_info_data_table[j].fn != NULL) )
-       {
-               DEBUG(4,("\tsearch_notify: out TRUE\n"));
-               return (True);
-       }
+               return True;
        else
-       {
-               DEBUG(4,("\tsearch_notify: out FALSE\n"));
-               return (False); 
-       }
+               return False;   
 }
 
 /****************************************************************************
 ****************************************************************************/
 static void construct_info_data(SPOOL_NOTIFY_INFO_DATA *info_data, uint16 type, uint16 field, int id)
 {
-       DEBUG(4,("\tconstruct_info_data: in\n"));
        info_data->type     = type;
        info_data->field    = field;
+       info_data->reserved = 0;
        info_data->id       = id;
        info_data->size     = size_of_notify_info_data(type, field);
        info_data->enc_type = type_of_notify_info_data(type, field);
-       DEBUG(4,("\tconstruct_info_data: out\n"));
 }
 
 
@@ -1203,49 +1212,48 @@ static void construct_info_data(SPOOL_NOTIFY_INFO_DATA *info_data, uint16 type,
  * fill a notify_info struct with info asked
  * 
  ********************************************************************/
-static void construct_notify_printer_info(SPOOL_NOTIFY_INFO *info, int pnum, 
-                                         int snum, int i, uint32 id)
+static BOOL construct_notify_printer_info(SPOOL_NOTIFY_INFO *info, int snum, SPOOL_NOTIFY_OPTION_TYPE *option_type, uint32 id)
 {
-
-       int k,j;
+       int field_num,j;
        uint16 type;
        uint16 field;
 
-       SPOOL_NOTIFY_INFO_DATA *info_data;
-       print_queue_struct *queue=NULL;
+       SPOOL_NOTIFY_INFO_DATA *current_data;
        NT_PRINTER_INFO_LEVEL printer;
+       print_queue_struct *queue=NULL;
        
        DEBUG(4,("construct_notify_printer_info\n"));
        
-       info_data=&(info->data[info->count]);
-       
-       type = Printer[pnum].notify_info[i].type;
+       type=option_type->type;
 
-       DEBUGADD(4,("Notify number %d -> number of notify info: %d\n",i,Printer[pnum].notify_info[i].count));
+       DEBUGADD(4,("Notify type: [%s], number of notify info: [%d] on printer: [%s]\n",
+               (option_type->type==PRINTER_NOTIFY_TYPE?"PRINTER_NOTIFY_TYPE":"JOB_NOTIFY_TYPE"), 
+               option_type->count, lp_servicename(snum)));
        
-       if (!get_a_printer(&printer, 2, lp_servicename(snum)))
+       if (get_a_printer(&printer, 2, lp_servicename(snum))!=0)
+       {
+               return False;
+       }
+
+       for(field_num=0; field_num<option_type->count; field_num++)
        {
+               field = option_type->fields[field_num];
+               DEBUGADD(4,("notify [%d]: type [%x], field [%x]\n", field_num, type, field));
+
+               if (!search_notify(type, field, &j) )
+                       continue;
                
-               for(k=0; k<Printer[pnum].notify_info[i].count; k++)
-               {
-                       field = Printer[pnum].notify_info[i].fields[k];
-                       DEBUGADD(4,("notify [%d]: type [%x], field [%x]\n", k, type, field));
+               info->data=Realloc(info->data, (info->count+1)*sizeof(SPOOL_NOTIFY_INFO_DATA));
+               current_data=&(info->data[info->count]);
 
-                       if (search_notify(type, field, &j) )
-                       {
-                               DEBUGADD(4,("j=[%d]:%s\n", j, notify_info_data_table[j].name));
-                               construct_info_data(info_data, type, field, id);
-                       
-                               DEBUGADD(4,("notify_info_data_table: in\n"));
-                               notify_info_data_table[j].fn(snum, info_data, queue, &printer);
-                               DEBUGADD(4,("notify_info_data_table: out\n"));
-                               info->count++;
-                               info_data=&(info->data[info->count]);
-                       }
-               }
-       
-               free_a_printer(printer, 2);
+               construct_info_data(current_data, type, field, id);             
+               notify_info_data_table[j].fn(snum, current_data, queue, &printer);
+
+               info->count++;
        }
+
+       free_a_printer(printer, 2);
+       return True;
 }
 
 /*******************************************************************
@@ -1253,46 +1261,72 @@ static void construct_notify_printer_info(SPOOL_NOTIFY_INFO *info, int pnum,
  * fill a notify_info struct with info asked
  * 
  ********************************************************************/
-static void construct_notify_jobs_info(print_queue_struct *queue, SPOOL_NOTIFY_INFO *info,
-                                       int pnum, int snum, int i, uint32 id)
+static BOOL construct_notify_jobs_info(print_queue_struct *queue, SPOOL_NOTIFY_INFO *info, int snum, SPOOL_NOTIFY_OPTION_TYPE *option_type, uint32 id)
 {
-
-       int k,j;
+       int field_num,j;
        uint16 type;
        uint16 field;
 
-       SPOOL_NOTIFY_INFO_DATA *info_data;
+       SPOOL_NOTIFY_INFO_DATA *current_data;
        NT_PRINTER_INFO_LEVEL printer;
        
        DEBUG(4,("construct_notify_jobs_info\n"));
-       info_data=&(info->data[info->count]);
        
-       type = Printer[pnum].notify_info[i].type;
+       type = option_type->type;
 
-       DEBUGADD(4,("Notify number %d -> number of notify info: %d\n",i,Printer[pnum].notify_info[i].count));
+       DEBUGADD(4,("Notify type: [%s], number of notify info: [%d]\n",
+               (option_type->type==PRINTER_NOTIFY_TYPE?"PRINTER_NOTIFY_TYPE":"JOB_NOTIFY_TYPE"), 
+               option_type->count));
 
-       if (!get_a_printer(&printer, 2, lp_servicename(snum)))
+       if (get_a_printer(&printer, 2, lp_servicename(snum))!=0)
        {       
-               for(k=0; k<Printer[pnum].notify_info[i].count; k++)
-               {
-                       field = Printer[pnum].notify_info[i].fields[k];
-                       DEBUGADD(4,("notify [%d]: type [%x], field [%x]\n",k, type, field));
+               return False;
+       }
+       
+       for(field_num=0; field_num<option_type->count; field_num++)
+       {
+               field = option_type->fields[field_num];
 
-                       if (search_notify(type, field, &j) )
-                       {
-                               DEBUGADD(4,("j=[%d]:%s\n", j, notify_info_data_table[j].name));
-                               construct_info_data(info_data, type, field, id);
-                               DEBUGADD(4,("notify_info_data_table: in\n"));
-                               notify_info_data_table[j].fn(snum, info_data, queue, &printer);
-                               DEBUGADD(4,("notify_info_data_table: out\n"));
-                               info->count++;
-                               info_data=&(info->data[info->count]);
-                       }
-               }
-               free_a_printer(printer, 2);
+               if (!search_notify(type, field, &j) )
+                       continue;
+
+               info->data=Realloc(info->data, (info->count+1)*sizeof(SPOOL_NOTIFY_INFO_DATA));
+               current_data=&(info->data[info->count]);
+
+               construct_info_data(current_data, type, field, id);
+               notify_info_data_table[j].fn(snum, current_data, queue, &printer);
+               info->count++;
        }
+       
+       free_a_printer(printer, 2);
+       
+       return True;
 }
 
+/*
+ * JFM: The enumeration is not that simple, it's even non obvious.
+ *
+ * let's take an example: I want to monitor the PRINTER SERVER for
+ * the printer's name and the number of jobs currently queued.
+ * So in the NOTIFY_OPTION, I have one NOTIFY_OPTION_TYPE structure.
+ * Its type is PRINTER_NOTIFY_TYPE and it has 2 fields NAME and CJOBS.
+ * 
+ * I have 3 printers on the back of my server.
+ *
+ * Now the response is a NOTIFY_INFO structure, with 6 NOTIFY_INFO_DATA
+ * structures.
+ *   Number    Data                    Id
+ *     1       printer 1 name          1
+ *     2       printer 1 cjob          1
+ *     3       printer 2 name          2
+ *     4       printer 2 cjob          2
+ *     5       printer 3 name          3
+ *     6       printer 3 name          3
+ *
+ * that's the print server case, the printer case is even worse.
+ */
+
+
 
 /*******************************************************************
  *
@@ -1300,40 +1334,54 @@ static void construct_notify_jobs_info(print_queue_struct *queue, SPOOL_NOTIFY_I
  * fill a notify_info struct with info asked
  * 
  ********************************************************************/
-static uint32 printserver_notify_info(const POLICY_HND *hnd,
-                               SPOOL_NOTIFY_INFO *info)
+static uint32 printserver_notify_info(const POLICY_HND *hnd, SPOOL_NOTIFY_INFO *info)
 {
        int snum;
-       int pnum=find_printer_index_by_hnd(hnd);
+       Printer_entry *Printer=find_printer_index_by_hnd(hnd);
        int n_services=lp_numservices();
-       int i=0;
-       uint32 id=1;
+       int i;
+       uint32 id;
+       SPOOL_NOTIFY_OPTION *option;
+       SPOOL_NOTIFY_OPTION_TYPE *option_type;
+
+       DEBUG(4,("printserver_notify_info\n"));
+       
+       option=Printer->notify.option;
+       id=1;
+       info->version=2;
+       info->data=NULL;
        info->count=0;
 
-       if (pnum == -1)
+       for (i=0; i<option->count; i++)
        {
-               return NT_STATUS_INVALID_HANDLE;
+               option_type=&(option->ctr.type[i]);
+               
+               if (option_type->type!=PRINTER_NOTIFY_TYPE)
+                       continue;
+               
+               for (snum=0; snum<n_services; snum++)
+                       if ( lp_browseable(snum) && lp_snum_ok(snum) && lp_print_ok(snum) )
+                               if (construct_notify_printer_info(info, snum, option_type, id))
+                                       id++;
        }
-
-       DEBUG(4,("Enumerating printers\n"));
-
-       for (i=0; i<Printer[pnum].number_of_notify; i++)
+                       
+       /*
+        * Debugging information, don't delete.
+        */
+       /* 
+       DEBUG(1,("dumping the NOTIFY_INFO\n"));
+       DEBUGADD(1,("info->version:[%d], info->flags:[%d], info->count:[%d]\n", info->version, info->flags, info->count));
+       DEBUGADD(1,("num\ttype\tfield\tres\tid\tsize\tenc_type\n"));
+       
+       for (i=0; i<info->count; i++)
        {
-        if ( Printer[pnum].notify_info[i].type == PRINTER_NOTIFY_TYPE )
-        {
-         for (snum=0; snum<n_services; snum++)
-         {
-          if ( lp_browseable(snum) && lp_snum_ok(snum) && lp_print_ok(snum) )
-          {
-               construct_notify_printer_info(info, pnum, snum, i, id);
-               id++;
-          }
-         }
-        }
-       }
-       DEBUG(4,("All printers enumerated\n"));
-
-       return 0x0;
+               DEBUGADD(1,("[%d]\t[%d]\t[%d]\t[%d]\t[%d]\t[%d]\t[%d]\n",
+               i, info->data[i].type, info->data[i].field, info->data[i].reserved,
+               info->data[i].id, info->data[i].size, info->data[i].enc_type));
+       }
+       */
+       
+       return NT_STATUS_NO_PROBLEMO;
 }
 
 /*******************************************************************
@@ -1341,82 +1389,104 @@ static uint32 printserver_notify_info(const POLICY_HND *hnd,
  * fill a notify_info struct with info asked
  * 
  ********************************************************************/
-static uint32 printer_notify_info(const POLICY_HND *hnd,
-                               SPOOL_NOTIFY_INFO *info)
+static uint32 printer_notify_info(const POLICY_HND *hnd, SPOOL_NOTIFY_INFO *info)
 {
        int snum;
-       int pnum=find_printer_index_by_hnd(hnd);
-       int i=0, j;
-       uint32 id=0xFFFF;
+       Printer_entry *Printer=find_printer_index_by_hnd(hnd);
+       int i;
+       uint32 id;
+       SPOOL_NOTIFY_OPTION *option;
+       SPOOL_NOTIFY_OPTION_TYPE *option_type;
+       int count,j;
+       print_queue_struct *queue=NULL;
+       print_status_struct status;
        
+       DEBUG(4,("printer_notify_info\n"));
+
+       option=Printer->notify.option;
+       id=1;
+       info->version=2;
+       info->data=NULL;
        info->count=0;
 
-       if (pnum == -1 || !get_printer_snum(hnd, &snum) )
-       {
-               return NT_STATUS_INVALID_HANDLE;
-       }
+       get_printer_snum(hnd, &snum);
 
-       for (i=0; i<Printer[pnum].number_of_notify; i++)
+       for (i=0; i<option->count; i++)
        {
-        switch ( Printer[pnum].notify_info[i].type )
-        {
-         case PRINTER_NOTIFY_TYPE:
-          {
-               construct_notify_printer_info(info, pnum, snum, i, id);
-               id--;
-               break;
-          }
-         case JOB_NOTIFY_TYPE:
-          {
-               int count;
-               print_queue_struct *queue=NULL;
-               print_status_struct status;
-               bzero(&status, sizeof(status)); 
-               count=get_printqueue(snum, NULL, &queue, &status);
-               for (j=0; j<count; j++)
-               {
-                       construct_notify_jobs_info(&(queue[j]), info, pnum, snum, i, queue[j].job);
+               option_type=&(option->ctr.type[i]);
+               
+               switch ( option_type->type ) {
+               case PRINTER_NOTIFY_TYPE:
+                       if(construct_notify_printer_info(info, snum, option_type, id))
+                               id++;
+                       break;
+                       
+               case JOB_NOTIFY_TYPE:
+                       memset(&status, 0, sizeof(status));     
+                       count=get_printqueue(snum, NULL, &queue, &status);
+                       for (j=0; j<count; j++)
+                               if (construct_notify_jobs_info(&(queue[j]), info, snum, option_type, id))
+                                       id++;
+                       safe_free(queue);
+                       break;
                }
-               safe_free(queue);
-               break;
-          }
-        }
        }
-
-       return 0x0;
+       
+       /*
+        * Debugging information, don't delete.
+        */
+       /* 
+       DEBUG(1,("dumping the NOTIFY_INFO\n"));
+       DEBUGADD(1,("info->version:[%d], info->flags:[%d], info->count:[%d]\n", info->version, info->flags, info->count));
+       DEBUGADD(1,("num\ttype\tfield\tres\tid\tsize\tenc_type\n"));
+       
+       for (i=0; i<info->count; i++)
+       {
+               DEBUGADD(1,("[%d]\t[%d]\t[%d]\t[%d]\t[%d]\t[%d]\t[%d]\n",
+               i, info->data[i].type, info->data[i].field, info->data[i].reserved,
+               info->data[i].id, info->data[i].size, info->data[i].enc_type));
+       }
+       */
+       return NT_STATUS_NO_PROBLEMO;
 }
 
 /********************************************************************
  * spoolss_rfnpcnex
  ********************************************************************/
-uint32 _spoolss_rfnpcnex( const POLICY_HND *handle,
-                               uint32 change,
-                               const SPOOL_NOTIFY_OPTION *option,
-                               uint32 *count,
-                               SPOOL_NOTIFY_INFO *info)
+uint32 _spoolss_rfnpcnex( const POLICY_HND *handle, uint32 change,
+                         SPOOL_NOTIFY_OPTION *option, SPOOL_NOTIFY_INFO *info)
 {
-       int pnum=find_printer_index_by_hnd(handle);
+       Printer_entry *Printer=find_printer_index_by_hnd(handle);
 
-       if (pnum == -1 || !OPEN_HANDLE(pnum))
-       {
+       if (!OPEN_HANDLE(Printer))
                return NT_STATUS_INVALID_HANDLE;
-       }
 
-       DEBUG(4,("Printer %x of type %x\n",pnum,Printer[pnum].printer_type));
+       DEBUG(4,("Printer type %x\n",Printer->printer_type));
+
+       /* jfm: the change value isn't used right now.
+        *      we will honour it when
+        *      a) we'll be able to send notification to the client
+        *      b) we'll have a way to communicate between the spoolss process.
+        *
+        *      same thing for option->flags
+        *      I should check for PRINTER_NOTIFY_OPTIONS_REFRESH but as 
+        *      I don't have a global notification system, I'm sending back all the
+        *      informations even when _NOTHING_ has changed.
+        */
 
-       /* lkxlXXXX - jfm, is this right? put a warning in for you to review! */
-       DEBUG(0,("_spoolss_rfnpcnex: change, option and count ignored\n"));
+       /* just discard the SPOOL_NOTIFY_OPTION */
+       if (option!=NULL)
+               safe_free(option->ctr.type);
+       
+       safe_free(option);
 
-       switch (Printer[pnum].printer_type)
-       {
+       switch (Printer->printer_type) {
                case PRINTER_HANDLE_IS_PRINTSERVER:
-               {
                        return printserver_notify_info(handle, info);
-               }
+                       break;
                case PRINTER_HANDLE_IS_PRINTER:
-               {
                        return printer_notify_info(handle, info);
-               }
+                       break;
        }
 
        return NT_STATUS_INVALID_INFO_CLASS;
@@ -1426,22 +1496,50 @@ uint32 _spoolss_rfnpcnex( const POLICY_HND *handle,
  * construct_printer_info_0
  * fill a printer_info_1 struct
  ********************************************************************/
-static BOOL construct_printer_info_0(PRINTER_INFO_0 *printer,int snum, pstring servername)
+static BOOL construct_printer_info_0(PRINTER_INFO_0 *printer, int snum, pstring servername)
 {
        pstring chaine;
        int count;
        NT_PRINTER_INFO_LEVEL ntprinter;
-       
+       counter_printer_0 *session_counter;
+       uint32 global_counter;
+       struct tm *t;
+
        print_queue_struct *queue=NULL;
        print_status_struct status;
-       bzero(&status,sizeof(status));  
+       
+       memset(&status, 0, sizeof(status));     
 
        if (get_a_printer(&ntprinter, 2, lp_servicename(snum)) != 0)
-       {
-               return (False);
-       }
+               return False;
 
        count=get_printqueue(snum, NULL, &queue, &status);
+
+       /* check if we already have a counter for this printer */       
+       session_counter = (counter_printer_0 *)ubi_dlFirst(&counter_list);
+
+       for(; session_counter; session_counter = (counter_printer_0 *)ubi_dlNext(session_counter)) {
+               if (session_counter->snum == snum)
+                       break;
+       }
+
+       /* it's the first time, add it to the list */
+       if (session_counter==NULL) {
+               session_counter=(counter_printer_0 *)malloc(sizeof(counter_printer_0));
+               ZERO_STRUCTP(session_counter);
+               session_counter->snum=snum;
+               session_counter->counter=0;
+               ubi_dlAddHead( &counter_list, (ubi_dlNode *)session_counter);
+       }
+       
+       /* increment it */
+       session_counter->counter++;
+       
+       /* JFM:
+        * the global_counter should be stored in a TDB as it's common to all the clients
+        * and should be zeroed on samba startup
+        */
+       global_counter=session_counter->counter;
        
        /* the description and the name are of the form \\server\share */
        slprintf(chaine,sizeof(chaine)-1,"\\\\%s\\%s",servername, ntprinter.info_2->printername);
@@ -1452,36 +1550,48 @@ static BOOL construct_printer_info_0(PRINTER_INFO_0 *printer,int snum, pstring s
        init_unistr(&(printer->servername), chaine);
        
        printer->cjobs = count;
-       printer->attributes =   PRINTER_ATTRIBUTE_SHARED   \
-                             | PRINTER_ATTRIBUTE_NETWORK  \
-                             | PRINTER_ATTRIBUTE_RAW_ONLY ;
-       printer->unknown0     = 0x1; /* pointer */
-       printer->unknown1     = 0x000A07CE; /* don't known */
-       printer->unknown2     = 0x00020005;
-       printer->unknown3     = 0x0006000D;
-       printer->unknown4     = 0x02180026;
-       printer->unknown5     = 0x09;
-       printer->unknown6     = 0x36;
-       printer->majorversion = 0x0004; /* NT 4 */
-       printer->buildversion = 0x0565; /* build 1381 */
-       printer->unknown7     = 0x1;
-       printer->unknown8     = 0x0;
-       printer->unknown9     = 0x2;
-       printer->unknown10    = 0x3;
-       printer->unknown11    = 0x0;
-       printer->unknown12    = 0x0;
-       printer->unknown13    = 0x0;
-       printer->unknown14    = 0x1;
-       printer->unknown15    = 0x024a; /*586 Pentium ? */
-       printer->unknown16    = 0x0;
-       printer->unknown17    = 0x423ed444;
-       printer->unknown18    = 0x0;
-       printer->status       = status.status;
-       printer->unknown20    = 0x0;
-       printer->unknown21    = 0x0648;
-       printer->unknown22    = 0x0;
-       printer->unknown23    = 0x5;
-
+       printer->total_jobs = 0;
+       printer->total_bytes = 0;
+
+       t=gmtime(&ntprinter.info_2->setuptime);
+
+       printer->year = t->tm_year+1900;
+       printer->month = t->tm_mon+1;
+       printer->dayofweek = t->tm_wday;
+       printer->day = t->tm_mday;
+       printer->hour = t->tm_hour;
+       printer->minute = t->tm_min;
+       printer->second = t->tm_sec;
+       printer->milliseconds = 0;
+
+       printer->global_counter = global_counter;
+       printer->total_pages = 0;
+       printer->major_version = 0x0004;        /* NT 4 */
+       printer->build_version = 0x0565;        /* build 1381 */
+       printer->unknown7 = 0x1;
+       printer->unknown8 = 0x0;
+       printer->unknown9 = 0x2;
+       printer->session_counter = session_counter->counter;
+       printer->unknown11 = 0x0;
+       printer->printer_errors = 0x0;          /* number of print failure */
+       printer->unknown13 = 0x0;
+       printer->unknown14 = 0x1;
+       printer->unknown15 = 0x024a;            /* 586 Pentium ? */
+       printer->unknown16 = 0x0;
+       printer->change_id = ntprinter.info_2->changeid; /* ChangeID in milliseconds*/
+       printer->unknown18 = 0x0;
+       printer->status = status.status;
+       printer->unknown20 = 0x0;
+       printer->c_setprinter = ntprinter.info_2->c_setprinter; /* how many times setprinter has been called */
+       printer->unknown22 = 0x0;
+       printer->unknown23 = 0x6;               /* 6  ???*/
+       printer->unknown24 = 0;                 /* unknown 24 to 26 are always 0 */
+       printer->unknown25 = 0;
+       printer->unknown26 = 0;
+       printer->unknown27 = 0;
+       printer->unknown28 = 0;
+       printer->unknown29 = 0;
+       
        safe_free(queue);
 
        free_a_printer(ntprinter, 2);
@@ -1492,32 +1602,29 @@ static BOOL construct_printer_info_0(PRINTER_INFO_0 *printer,int snum, pstring s
  * construct_printer_info_1
  * fill a printer_info_1 struct
  ********************************************************************/
-static BOOL construct_printer_info_1(PRINTER_INFO_1 *printer,int snum, pstring servername)
+static BOOL construct_printer_info_1(fstring server, uint32 flags, PRINTER_INFO_1 *printer, int snum)
 {
        pstring chaine;
+       pstring chaine2;
        NT_PRINTER_INFO_LEVEL ntprinter;
-       
+
        if (get_a_printer(&ntprinter, 2, lp_servicename(snum)) != 0)
-       {
-               return (False);
-       }
-       
-       printer->flags=PRINTER_ENUM_NAME;
+               return False;
 
-       /* the description and the name are of the form \\server\share */
-       slprintf(chaine,sizeof(chaine)-1,"\\\\%s\\%s,%s,%s",servername,
-                                                           ntprinter.info_2->printername,
-                                                           ntprinter.info_2->drivername,
-                                                           lp_comment(snum));
-       init_unistr(&(printer->description), chaine);
-       
-       slprintf(chaine,sizeof(chaine)-1,"\\\\%s\\%s", servername, ntprinter.info_2->printername);
-       init_unistr(&(printer->name), chaine);
-       
-       init_unistr(&(printer->comment), lp_comment(snum));
+       printer->flags=flags;
+
+       snprintf(chaine,sizeof(chaine)-1,"%s%s,%s,%s",server, ntprinter.info_2->printername,
+               ntprinter.info_2->drivername, lp_comment(snum));
+               
+       snprintf(chaine2,sizeof(chaine)-1,"%s%s", server, ntprinter.info_2->printername);
+
+       init_unistr(&printer->description, chaine);
+       init_unistr(&printer->name, chaine2);   
+       init_unistr(&printer->comment, lp_comment(snum));
        
        free_a_printer(ntprinter, 2);
-       return (True);
+
+       return True;
 }
 
 /****************************************************************************
@@ -1531,8 +1638,8 @@ static void construct_dev_mode(DEVICEMODE *devmode, int snum, char *servername)
 
        DEBUG(7,("construct_dev_mode\n"));
        
-       bzero(&(devmode->devicename), 2*sizeof(adevice));
-       bzero(&(devmode->formname), 2*sizeof(aform));
+       memset(&(devmode->devicename), 0, 2*sizeof(adevice));
+       memset(&(devmode->formname), 0, 2*sizeof(aform));
 
        DEBUGADD(8,("getting printer characteristics\n"));
 
@@ -1584,52 +1691,57 @@ static void construct_dev_mode(DEVICEMODE *devmode, int snum, char *servername)
  * construct_printer_info_2
  * fill a printer_info_2 struct
  ********************************************************************/
-static BOOL construct_printer_info_2(PRINTER_INFO_2 *printer, int snum, pstring servername)
+static BOOL construct_printer_info_2(pstring servername, PRINTER_INFO_2 *printer, int snum)
 {
        pstring chaine;
+       pstring chaine2;
+       pstring sl;
        int count;
        DEVICEMODE *devmode;
        NT_PRINTER_INFO_LEVEL ntprinter;
-       
+
        print_queue_struct *queue=NULL;
        print_status_struct status;
-       bzero(&status, sizeof(status)); 
-       count=get_printqueue(snum, NULL, &queue, &status);
+       memset(&status, 0, sizeof(status));     
 
        if (get_a_printer(&ntprinter, 2, lp_servicename(snum)) !=0 )
-       {
-               return (False);
-       }       
-
-       snprintf(chaine, sizeof(chaine)-1, "\\\\%s", servername);
-       init_unistr(&(printer->servername), chaine);                    /* servername*/
-       
-       snprintf(chaine, sizeof(chaine)-1, "\\\\%s\\%s", servername, ntprinter.info_2->printername);
-       init_unistr(&(printer->printername), chaine);                   /* printername*/
+               return False;
+               
+       memset(&status, 0, sizeof(status));             
+       count=get_printqueue(snum, NULL, &queue, &status);
 
-       init_unistr(&(printer->sharename),      lp_servicename(snum));  /* sharename */
+       snprintf(chaine, sizeof(chaine)-1, "%s", servername);
 
-       init_unistr(&(printer->portname),       lp_servicename(snum));          /* port */      
-       init_unistr(&(printer->drivername),     ntprinter.info_2->drivername);  /* drivername */
-               
-       init_unistr(&(printer->comment),        ntprinter.info_2->comment);     /* comment */   
-       init_unistr(&(printer->location),       ntprinter.info_2->location);    /* location */  
-       init_unistr(&(printer->sepfile),        ntprinter.info_2->sepfile);     /* separator file */
-       init_unistr(&(printer->printprocessor), ntprinter.info_2->printprocessor);/* print processor */
-       init_unistr(&(printer->datatype),       ntprinter.info_2->datatype);    /* datatype */  
-       init_unistr(&(printer->parameters),     ntprinter.info_2->parameters);  /* parameters (of print processor) */   
+       if (strlen(servername)!=0)
+               fstrcpy(sl, "\\");
+       else
+               fstrcpy(sl, '\0');
+
+       snprintf(chaine2, sizeof(chaine)-1, "%s%s%s", servername, sl, ntprinter.info_2->printername);
+
+       init_unistr(&printer->servername, chaine);                              /* servername*/
+       init_unistr(&printer->printername, chaine2);                            /* printername*/
+       init_unistr(&printer->sharename, lp_servicename(snum));                 /* sharename */
+       init_unistr(&printer->portname, lp_servicename(snum));                  /* port */      
+       init_unistr(&printer->drivername, ntprinter.info_2->drivername);        /* drivername */
+       init_unistr(&printer->comment, lp_comment(snum));                       /* comment */   
+       init_unistr(&printer->location, ntprinter.info_2->location);            /* location */  
+       init_unistr(&printer->sepfile, ntprinter.info_2->sepfile);              /* separator file */
+       init_unistr(&printer->printprocessor, ntprinter.info_2->printprocessor);/* print processor */
+       init_unistr(&printer->datatype, ntprinter.info_2->datatype);            /* datatype */  
+       init_unistr(&printer->parameters, ntprinter.info_2->parameters);        /* parameters (of print processor) */   
 
        printer->attributes =   PRINTER_ATTRIBUTE_SHARED   \
-                             | PRINTER_ATTRIBUTE_NETWORK  \
-                             | PRINTER_ATTRIBUTE_RAW_ONLY ;            /* attributes */
-
-       printer->priority        = ntprinter.info_2->priority;          /* priority */  
-       printer->defaultpriority = ntprinter.info_2->default_priority;  /* default priority */
-       printer->starttime       = ntprinter.info_2->starttime;         /* starttime */
-       printer->untiltime       = ntprinter.info_2->untiltime;         /* untiltime */
-       printer->status          = status.status;                       /* status */
-       printer->cjobs           = count;                               /* jobs */
-       printer->averageppm      = ntprinter.info_2->averageppm;        /* average pages per minute */
+                             | PRINTER_ATTRIBUTE_LOCAL  \
+                             | PRINTER_ATTRIBUTE_RAW_ONLY ;                    /* attributes */
+
+       printer->priority = ntprinter.info_2->priority;                         /* priority */  
+       printer->defaultpriority = ntprinter.info_2->default_priority;          /* default priority */
+       printer->starttime = ntprinter.info_2->starttime;                       /* starttime */
+       printer->untiltime = ntprinter.info_2->untiltime;                       /* untiltime */
+       printer->status = status.status;                                        /* status */
+       printer->cjobs = count;                                                 /* jobs */
+       printer->averageppm = ntprinter.info_2->averageppm;                     /* average pages per minute */
                        
        devmode=(DEVICEMODE *)malloc(sizeof(DEVICEMODE));
        ZERO_STRUCTP(devmode);  
@@ -1638,78 +1750,160 @@ static BOOL construct_printer_info_2(PRINTER_INFO_2 *printer, int snum, pstring
        
        safe_free(queue);
        free_a_printer(ntprinter, 2);
-       return (True);
+       return True;
 }
 
 /********************************************************************
- * enum_printer_info_1
- * glue between spoolss_enumprinters and construct_printer_info_1
- ********************************************************************/
-static BOOL enum_printer_info_1(PRINTER_INFO_1 **printer, int snum, int number)
+ Spoolss_enumprinters.
+********************************************************************/
+static BOOL enum_all_printers_info_1(fstring server, uint32 flags, NEW_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
 {
-       pstring servername;
+       int snum;
+       int i;
+       int n_services=lp_numservices();
+       PRINTER_INFO_1 *printers=NULL;
+       PRINTER_INFO_1 current_prt;
+       
+       DEBUG(4,("enum_all_printers_info_1\n"));        
 
-       *printer=(PRINTER_INFO_1 *)malloc(sizeof(PRINTER_INFO_1));
-       DEBUG(4,("Allocated memory for ONE PRINTER_INFO_1 at [%p]\n", *printer));       
-       pstrcpy(servername, global_myname);
-       if (!construct_printer_info_1(*printer, snum, servername))
-       {
-               free(*printer);
-               return (False);
+       for (snum=0; snum<n_services; snum++) {
+               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(server, flags, &current_prt, snum)) {
+                               printers=Realloc(printers, (*returned +1)*sizeof(PRINTER_INFO_1));
+                               DEBUG(4,("ReAlloced memory for [%d] PRINTER_INFO_1\n", *returned));             
+                               memcpy(&(printers[*returned]), &current_prt, sizeof(PRINTER_INFO_1));
+                               (*returned)++;
+                       }
+               }
        }
-       else
-       {
-               return (True);
+               
+       /* check the required size. */  
+       for (i=0; i<*returned; i++)
+               (*needed) += spoolss_size_printer_info_1(&(printers[i]));
+
+       if (!alloc_buffer_size(buffer, *needed))
+               return ERROR_INSUFFICIENT_BUFFER;
+
+       /* fill the buffer with the structures */
+       for (i=0; i<*returned; i++)
+               new_smb_io_printer_info_1("", buffer, &(printers[i]), 0);       
+
+       /* clear memory */
+       safe_free(printers);
+
+       if (*needed > offered) {
+               *returned=0;
+               return ERROR_INSUFFICIENT_BUFFER;
        }
+       else
+               return NT_STATUS_NO_PROBLEMO;
 }
 
 /********************************************************************
- * enum_printer_info_2
- * glue between spoolss_enumprinters and construct_printer_info_2
- ********************************************************************/
-static BOOL enum_printer_info_2(PRINTER_INFO_2 **printer, int snum, int number)
+ enum_all_printers_info_1_local.
+*********************************************************************/
+static BOOL enum_all_printers_info_1_local(fstring name, NEW_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
 {
-       pstring servername;
+       fstring temp;
+       DEBUG(4,("enum_all_printers_info_1_local\n"));  
+       
+       fstrcpy(temp, "\\\\");
+       fstrcat(temp, global_myname);
 
-       *printer=(PRINTER_INFO_2 *)malloc(sizeof(PRINTER_INFO_2));
-       DEBUG(4,("Allocated memory for ONE PRINTER_INFO_2 at [%p]\n", *printer));       
-       pstrcpy(servername, global_myname);
-       if (!construct_printer_info_2(*printer, snum, servername))
-       {
-               free(*printer);
-               return (False);
+       if (!strcmp(name, temp)) {
+               fstrcat(temp, "\\");
+               return enum_all_printers_info_1(temp, PRINTER_ENUM_ICON8, buffer, offered, needed, returned);
        }
        else
-       {
-               return (True);
+               return enum_all_printers_info_1("", PRINTER_ENUM_ICON8, buffer, offered, needed, returned);
+}
+
+/********************************************************************
+ enum_all_printers_info_1_name.
+*********************************************************************/
+static BOOL enum_all_printers_info_1_name(fstring name, NEW_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+{
+       fstring temp;
+       DEBUG(4,("enum_all_printers_info_1_name\n"));   
+       
+       fstrcpy(temp, "\\\\");
+       fstrcat(temp, global_myname);
+
+       if (!strcmp(name, temp)) {
+               fstrcat(temp, "\\");
+               return enum_all_printers_info_1(temp, PRINTER_ENUM_ICON8, buffer, offered, needed, returned);
        }
+       else
+               return ERROR_INVALID_NAME;
 }
 
 /********************************************************************
- * spoolss_enumprinters
- *
- * called from api_spoolss_enumprinters (see this to understand)
- ********************************************************************/
-static void enum_all_printers_info_1(PRINTER_INFO_1 ***printers, uint32 *number)
+ enum_all_printers_info_1_remote.
+*********************************************************************/
+static BOOL enum_all_printers_info_1_remote(fstring name, NEW_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
 {
-       int snum;
-       int n_services=lp_numservices();
-       *printers=NULL;
-       *number=0;
+       PRINTER_INFO_1 *printer;
+       fstring printername;
+       fstring desc;
+       fstring comment;
+       DEBUG(4,("enum_all_printers_info_1_remote\n")); 
+
+       /* JFM: currently it's more a place holder than anything else.
+        * In the spooler world there is a notion of server registration.
+        * the print servers are registring (sp ?) on the PDC (in the same domain)
+        * 
+        * We should have a TDB here. The registration is done thru an undocumented RPC call.
+        */
+       
+       printer=(PRINTER_INFO_1 *)malloc(sizeof(PRINTER_INFO_1));
 
-       for (snum=0;snum<n_services; snum++)
-       {
-               if (lp_browseable(snum) && lp_snum_ok(snum) && lp_print_ok(snum) )
-               {
-                       DEBUG(4,("Found a printer: %s[%x]\n",lp_servicename(snum),snum));
-                       *printers=Realloc(*printers, (*number+1)*sizeof(PRINTER_INFO_1 *));                     
-                       DEBUG(4,("ReAlloced memory for [%d] PRINTER_INFO_1 pointers at [%p]\n", *number+1, *printers));         
-                       if (enum_printer_info_1( &((*printers)[*number]), snum, *number) )
-                       {                       
-                               (*number)++;
-                       }
-               }
+       *returned=1;
+       
+       snprintf(printername, sizeof(printername)-1,"Windows NT Remote Printers!!\\\\%s", global_myname);               
+       snprintf(desc, sizeof(desc)-1,"%s", global_myname);
+       snprintf(comment, sizeof(comment)-1, "Logged on Domain");
+
+       init_unistr(&printer->description, desc);
+       init_unistr(&printer->name, printername);       
+       init_unistr(&printer->comment, comment);
+       printer->flags=PRINTER_ENUM_ICON3|PRINTER_ENUM_CONTAINER;
+               
+       /* check the required size. */  
+       *needed += spoolss_size_printer_info_1(printer);
+
+       if (!alloc_buffer_size(buffer, *needed)) {
+               safe_free(printer);
+               return ERROR_INSUFFICIENT_BUFFER;
+       }
+
+       /* fill the buffer with the structures */
+       new_smb_io_printer_info_1("", buffer, printer, 0);      
+
+       /* clear memory */
+       safe_free(printer);
+
+       if (*needed > offered) {
+               *returned=0;
+               return ERROR_INSUFFICIENT_BUFFER;
        }
+       else
+               return NT_STATUS_NO_PROBLEMO;
+}
+
+/********************************************************************
+ enum_all_printers_info_1_network.
+*********************************************************************/
+static BOOL enum_all_printers_info_1_network(fstring name, NEW_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+{
+       fstring temp;
+       DEBUG(4,("enum_all_printers_info_1_network\n"));        
+       
+       fstrcpy(temp, "\\\\");
+       fstrcat(temp, global_myname);
+       fstrcat(temp, "\\");
+       return enum_all_printers_info_1(temp, PRINTER_ENUM_UNKNOWN_8, buffer, offered, needed, returned);
 }
 
 /********************************************************************
@@ -1717,203 +1911,350 @@ static void enum_all_printers_info_1(PRINTER_INFO_1 ***printers, uint32 *number)
  *
  * called from api_spoolss_enumprinters (see this to understand)
  ********************************************************************/
-static void enum_all_printers_info_2(PRINTER_INFO_2 ***printers, uint32 *number)
+static BOOL enum_all_printers_info_2(fstring servername, NEW_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
 {
        int snum;
+       int i;
        int n_services=lp_numservices();
-       *printers=NULL;
-       *number=0;
+       PRINTER_INFO_2 *printers=NULL;
+       PRINTER_INFO_2 current_prt;
 
-       for (snum=0;snum<n_services; snum++)
-       {
-               if (lp_browseable(snum) && lp_snum_ok(snum) && lp_print_ok(snum) )
-               {
-                       DEBUG(4,("Found a printer: %s[%x]\n",lp_servicename(snum),snum));
-                       *printers=Realloc(*printers, (*number+1)*sizeof(PRINTER_INFO_2 *));                     
-                       DEBUG(4,("ReAlloced memory for [%d] PRINTER_INFO_2 pointers at [%p]\n", *number+1, *printers));                 
-                       if (enum_printer_info_2( &((*printers)[*number]), snum, *number) )
-                       {                       
-                               (*number)++;
+       for (snum=0; snum<n_services; snum++) {
+               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(servername, &current_prt, snum)) {
+                               printers=Realloc(printers, (*returned +1)*sizeof(PRINTER_INFO_2));
+                               DEBUG(4,("ReAlloced memory for [%d] PRINTER_INFO_2\n", *returned));             
+                               memcpy(&(printers[*returned]), &current_prt, sizeof(PRINTER_INFO_2));
+                               (*returned)++;
                        }
                }
        }
+       
+       /* check the required size. */  
+       for (i=0; i<*returned; i++)
+               (*needed) += spoolss_size_printer_info_2(&(printers[i]));
+
+       if (!alloc_buffer_size(buffer, *needed))
+               return ERROR_INSUFFICIENT_BUFFER;
+
+       /* fill the buffer with the structures */
+       for (i=0; i<*returned; i++)
+               new_smb_io_printer_info_2("", buffer, &(printers[i]), 0);       
+       
+       /* clear memory */
+       safe_free(printers);
+
+       if (*needed > offered) {
+               *returned=0;
+               return ERROR_INSUFFICIENT_BUFFER;
+       }
+       else
+               return NT_STATUS_NO_PROBLEMO;
 }
 
 /********************************************************************
- * api_spoolss_enumprinters
- *
- * called from api_spoolss_enumprinters (see this to understand)
+ * handle enumeration of printers at level 1
  ********************************************************************/
-uint32 _spoolss_enumprinters(
-                               uint32 flags,
-                               const UNISTR2 *servername,
-                               uint32 level,
-                               const BUFFER *buffer,
-                               uint32 buf_size,
-                               uint32 *offered,
-                               uint32 *needed,
-                               PRINTER_INFO_CTR *ctr,
-                               uint32 *returned)
+static uint32 enumprinters_level1( uint32 flags, fstring name,
+                                NEW_BUFFER *buffer, uint32 offered,
+                                uint32 *needed, uint32 *returned)
 {
-       DEBUG(4,("Enumerating printers\n"));
+       /* Not all the flags are equals */
 
-       (*returned)=0;
+       if (flags & PRINTER_ENUM_LOCAL)
+               return enum_all_printers_info_1_local(name, buffer, offered, needed, returned);
 
-       switch (level)
-       {
-               case 1:
-                       if (flags == PRINTER_ENUM_NAME ||
-                           flags == PRINTER_ENUM_NETWORK )
-                       {
-                               /*if (is_a_printerserver(servername))*/
-                                       enum_all_printers_info_1(&ctr->printer.printers_1, returned );
-                               /*else  
-                                       enum_one_printer_info_1(&r_u);*/
-                               break;
-                       }
-               case 2:
-                       if (flags == PRINTER_ENUM_NAME ||
-                           flags == PRINTER_ENUM_NETWORK )
-                       {
-                               /*if (is_a_printerserver(servername))*/
-                                       enum_all_printers_info_2(&ctr->printer.printers_2, returned );
-                               /*else  
-                                       enum_one_printer_info_2(&r_u);*/
-                               break;
-                       }
-               case 3:         /* doesn't exist */
-                       return NT_STATUS_INVALID_INFO_CLASS;
-               case 4:         /* can't, always on local machine */
-                       break;
-               case 5:
-                       return NT_STATUS_INVALID_INFO_CLASS;
-                       
-       }
-       DEBUG(4,("%d printers enumerated\n", *returned));
-       (*offered) = buffer->size;
+       if (flags & PRINTER_ENUM_NAME)
+               return enum_all_printers_info_1_name(name, buffer, offered, needed, returned);
 
-       return 0x0;
+       if (flags & PRINTER_ENUM_REMOTE)
+               return enum_all_printers_info_1_remote(name, buffer, offered, needed, returned);
+
+       if (flags & PRINTER_ENUM_NETWORK)
+               return enum_all_printers_info_1_network(name, buffer, offered, needed, returned);
+
+       return NT_STATUS_NO_PROBLEMO; /* NT4sp5 does that */
 }
 
-/****************************************************************************
-****************************************************************************/
-uint32 _spoolss_getprinter( POLICY_HND *handle,
-                               uint32 level,
-                               PRINTER_INFO *ctr,
-                               uint32 *offered,
-                               uint32 *needed)
+/********************************************************************
+ * handle enumeration of printers at level 2
+ ********************************************************************/
+static uint32 enumprinters_level2( uint32 flags, fstring servername,
+                                NEW_BUFFER *buffer, uint32 offered,
+                                uint32 *needed, uint32 *returned)
 {
-       int snum;
-       pstring servername;
+       fstring temp;
        
-       pstrcpy(servername, global_myname);
+       fstrcpy(temp, "\\\\");
+       fstrcat(temp, global_myname);
 
-       if (!get_printer_snum(handle,&snum))
-       {
-               return NT_STATUS_INVALID_HANDLE;
+       if (flags & PRINTER_ENUM_LOCAL) {
+               if (!strcmp(servername, temp))
+                       return enum_all_printers_info_2(temp, buffer, offered, needed, returned);
+               else
+                       return enum_all_printers_info_2("", buffer, offered, needed, returned);
        }
 
-       DEBUG(0,("_spoolss_getprinter: offered and needed params ignored\n"));
-
-       switch (level)
-       {
-               case 0:
-               { 
-                       PRINTER_INFO_0 *printer;
-                       
-                       printer=(PRINTER_INFO_0*)malloc(sizeof(PRINTER_INFO_0));
-                       construct_printer_info_0(printer, snum, servername);
-                       ctr->printer.info0=printer;
-                       
-                       return 0x0;
-               }
-               case 1:
-               {
-                       PRINTER_INFO_1 *printer;
-                       
-                       printer=(PRINTER_INFO_1*)malloc(sizeof(PRINTER_INFO_1));
-                       construct_printer_info_1(printer, snum, servername);
-                       ctr->printer.info1=printer;                     
-
-                       return 0x0;
-               }
-               case 2:
-               {
-                       PRINTER_INFO_2 *printer;
-                       
-                       printer=(PRINTER_INFO_2*)malloc(sizeof(PRINTER_INFO_2));        
-                       construct_printer_info_2(printer, snum, servername);
-                       ctr->printer.info2=printer;     
-
-                       return 0x0;
-               }
-               default:
-               {
-                       break;
-               }
+       if (flags & PRINTER_ENUM_NAME) {
+               if (!strcmp(servername, temp))
+                       return enum_all_printers_info_2(temp, buffer, offered, needed, returned);
+               else
+                       return ERROR_INVALID_NAME;
        }
 
-       return NT_STATUS_INVALID_INFO_CLASS;
+       if (flags & PRINTER_ENUM_REMOTE)
+               return ERROR_INVALID_LEVEL;
+
+       return NT_STATUS_NO_PROBLEMO;
 }
 
 /********************************************************************
- * construct_printer_driver_info_1
- * fill a construct_printer_driver_info_1 struct
+ * handle enumeration of printers at level 5
  ********************************************************************/
-static void fill_printer_driver_info_1(DRIVER_INFO_1 *info, 
-                                       NT_PRINTER_DRIVER_INFO_LEVEL driver, 
-                                      pstring servername, fstring architecture)
+static uint32 enumprinters_level5( uint32 flags, fstring servername,
+                                NEW_BUFFER *buffer, uint32 offered,
+                                uint32 *needed, uint32 *returned)
 {
-       init_unistr( &(info->name), driver.info_3->name);
+/*     return enum_all_printers_info_5(buffer, offered, needed, returned);*/
+       return NT_STATUS_NO_PROBLEMO;
 }
 
-static void construct_printer_driver_info_1(DRIVER_INFO_1 *info, int snum, 
-                                            pstring servername, fstring architecture)
-{      
-       NT_PRINTER_INFO_LEVEL printer;
-       NT_PRINTER_DRIVER_INFO_LEVEL driver;
-
-       get_a_printer(&printer, 2, lp_servicename(snum) );
-       get_a_printer_driver(&driver, 3, printer.info_2->drivername, architecture);     
+/********************************************************************
+ * api_spoolss_enumprinters
+ *
+ * called from api_spoolss_enumprinters (see this to understand)
+ ********************************************************************/
+uint32 _spoolss_enumprinters( uint32 flags, const UNISTR2 *servername, uint32 level,
+                             NEW_BUFFER *buffer, uint32 offered,
+                             uint32 *needed, uint32 *returned)
+{
+       fstring name;
        
-       fill_printer_driver_info_1(info, driver, servername, architecture);
+       DEBUG(4,("_spoolss_enumprinters\n"));
+
+       *needed=0;
+       *returned=0;
        
-       free_a_printer_driver(driver, 3);
-       free_a_printer(printer, 2);
+       /*
+        * Level 1: 
+        *          flags==PRINTER_ENUM_NAME
+        *           if name=="" then enumerates all printers
+        *           if name!="" then enumerate the printer
+        *          flags==PRINTER_ENUM_REMOTE
+        *          name is NULL, enumerate printers
+        * Level 2: name!="" enumerates printers, name can't be NULL
+        * Level 3: doesn't exist
+        * Level 4: does a local registry lookup
+        * Level 5: same as Level 2
+        */
+
+       unistr2_to_ascii(name, servername, sizeof(name)-1);
+       strupper(name);
+
+       switch (level) {
+       case 1:
+               return enumprinters_level1(flags, name, buffer, offered, needed, returned);
+               break;
+       case 2:
+               return enumprinters_level2(flags, name, buffer, offered, needed, returned);
+               break;                          
+       case 5:
+               return enumprinters_level5(flags, name, buffer, offered, needed, returned);
+               break;                          
+       case 3:
+       case 4:
+       default:
+               return NT_STATUS_INVALID_LEVEL;
+               break;
+       }
 }
 
-/********************************************************************
- * construct_printer_driver_info_2
- * fill a printer_info_2 struct
- ********************************************************************/
-static void fill_printer_driver_info_2(DRIVER_INFO_2 *info, 
-                                       NT_PRINTER_DRIVER_INFO_LEVEL driver, 
-                                      pstring servername, fstring architecture)
+/****************************************************************************
+****************************************************************************/
+static uint32 getprinter_level_0(pstring servername, int snum, NEW_BUFFER *buffer, uint32 offered, uint32 *needed)
 {
-       pstring where;
-       pstring temp_driverpath;
-       pstring temp_datafile;
-       pstring temp_configfile;
-       fstring short_archi;
+       PRINTER_INFO_0 *printer=NULL;
 
-       get_short_archi(short_archi,architecture);
+       printer=(PRINTER_INFO_0*)malloc(sizeof(PRINTER_INFO_0));
+
+       construct_printer_info_0(printer, snum, servername);
        
-       snprintf(where,sizeof(where)-1,"\\\\%s\\print$\\%s\\", servername, short_archi);
+       /* check the required size. */  
+       *needed += spoolss_size_printer_info_0(printer);
 
-       info->version=driver.info_3->cversion;
+       if (!alloc_buffer_size(buffer, *needed)) {
+               safe_free(printer);
+               return ERROR_INSUFFICIENT_BUFFER;
+       }
 
-       init_unistr( &(info->name),         driver.info_3->name );
-       init_unistr( &(info->architecture), architecture );
+       /* fill the buffer with the structures */
+       new_smb_io_printer_info_0("", buffer, printer, 0);      
        
-       snprintf(temp_driverpath, sizeof(temp_driverpath)-1, "%s%s", where, 
-                driver.info_3->driverpath);
-       init_unistr( &(info->driverpath),   temp_driverpath );
-
-       snprintf(temp_datafile,   sizeof(temp_datafile)-1, "%s%s", where, 
-                driver.info_3->datafile);
-       init_unistr( &(info->datafile),     temp_datafile );
+       /* clear memory */
+       safe_free(printer);
 
-       snprintf(temp_configfile, sizeof(temp_configfile)-1, "%s%s", where, 
+       if (*needed > offered) {
+               return ERROR_INSUFFICIENT_BUFFER;
+       }
+       else
+               return NT_STATUS_NO_PROBLEMO;   
+}
+
+/****************************************************************************
+****************************************************************************/
+static uint32 getprinter_level_1(pstring servername, int snum, NEW_BUFFER *buffer, uint32 offered, uint32 *needed)
+{
+       PRINTER_INFO_1 *printer=NULL;
+
+       printer=(PRINTER_INFO_1*)malloc(sizeof(PRINTER_INFO_1));
+       construct_printer_info_1(servername, PRINTER_ENUM_ICON8, printer, snum);
+       
+       /* check the required size. */  
+       *needed += spoolss_size_printer_info_1(printer);
+
+       if (!alloc_buffer_size(buffer, *needed)) {
+               safe_free(printer);
+               return ERROR_INSUFFICIENT_BUFFER;
+       }
+
+       /* fill the buffer with the structures */
+       new_smb_io_printer_info_1("", buffer, printer, 0);      
+       
+       /* clear memory */
+       safe_free(printer);
+
+       if (*needed > offered) {
+               return ERROR_INSUFFICIENT_BUFFER;
+       }
+       else
+               return NT_STATUS_NO_PROBLEMO;   
+}
+
+/****************************************************************************
+****************************************************************************/
+static uint32 getprinter_level_2(pstring servername, int snum, NEW_BUFFER *buffer, uint32 offered, uint32 *needed)
+{
+       PRINTER_INFO_2 *printer=NULL;
+       fstring temp;
+
+       printer=(PRINTER_INFO_2*)malloc(sizeof(PRINTER_INFO_2));
+       
+       fstrcpy(temp, "\\\\");
+       fstrcat(temp, servername);
+       construct_printer_info_2(temp, printer, snum);
+       
+       /* check the required size. */  
+       *needed += spoolss_size_printer_info_2(printer);
+
+       if (!alloc_buffer_size(buffer, *needed)) {
+               safe_free(printer);
+               return ERROR_INSUFFICIENT_BUFFER;
+       }
+
+       /* fill the buffer with the structures */
+       new_smb_io_printer_info_2("", buffer, printer, 0);      
+       
+       /* clear memory */
+       safe_free(printer);
+
+       if (*needed > offered) {
+               return ERROR_INSUFFICIENT_BUFFER;
+       }
+       else
+               return NT_STATUS_NO_PROBLEMO;   
+}
+
+/****************************************************************************
+****************************************************************************/
+uint32 _spoolss_getprinter(POLICY_HND *handle, uint32 level,
+                          NEW_BUFFER *buffer, uint32 offered, uint32 *needed)
+{
+       int snum;
+       pstring servername;
+       
+       *needed=0;
+
+       pstrcpy(servername, global_myname);
+
+       if (!get_printer_snum(handle, &snum))
+               return NT_STATUS_INVALID_HANDLE;
+
+       switch (level) {
+       case 0:
+               return getprinter_level_0(servername, snum, buffer, offered, needed);
+               break;
+       case 1:
+               return getprinter_level_1(servername,snum, buffer, offered, needed);
+               break;
+       case 2:         
+               return getprinter_level_2(servername,snum, buffer, offered, needed);
+               break;
+       default:
+               return ERROR_INVALID_LEVEL;
+               break;
+       }
+}      
+               
+/********************************************************************
+ * construct_printer_driver_info_1
+ * fill a construct_printer_driver_info_1 struct
+ ********************************************************************/
+static void fill_printer_driver_info_1(DRIVER_INFO_1 *info, 
+                                       NT_PRINTER_DRIVER_INFO_LEVEL driver, 
+                                      pstring servername, fstring architecture)
+{
+       init_unistr( &(info->name), driver.info_3->name);
+}
+
+static void construct_printer_driver_info_1(DRIVER_INFO_1 *info, int snum, 
+                                            pstring servername, fstring architecture)
+{      
+       NT_PRINTER_INFO_LEVEL printer;
+       NT_PRINTER_DRIVER_INFO_LEVEL driver;
+
+       get_a_printer(&printer, 2, lp_servicename(snum) );
+       get_a_printer_driver(&driver, 3, printer.info_2->drivername, architecture);     
+       
+       fill_printer_driver_info_1(info, driver, servername, architecture);
+       
+       free_a_printer_driver(driver, 3);
+       free_a_printer(printer, 2);
+}
+
+/********************************************************************
+ * construct_printer_driver_info_2
+ * fill a printer_info_2 struct
+ ********************************************************************/
+static void fill_printer_driver_info_2(DRIVER_INFO_2 *info, 
+                                       NT_PRINTER_DRIVER_INFO_LEVEL driver, 
+                                      pstring servername, fstring architecture)
+{
+       pstring where;
+       pstring temp_driverpath;
+       pstring temp_datafile;
+       pstring temp_configfile;
+       fstring short_archi;
+
+       get_short_archi(short_archi,architecture);
+       
+       snprintf(where,sizeof(where)-1,"\\\\%s\\print$\\%s\\", servername, short_archi);
+
+       info->version=driver.info_3->cversion;
+
+       init_unistr( &(info->name),         driver.info_3->name );
+       init_unistr( &(info->architecture), architecture );
+       
+       snprintf(temp_driverpath, sizeof(temp_driverpath)-1, "%s%s", where, 
+                driver.info_3->driverpath);
+       init_unistr( &(info->driverpath),   temp_driverpath );
+
+       snprintf(temp_datafile,   sizeof(temp_datafile)-1, "%s%s", where, 
+                driver.info_3->datafile);
+       init_unistr( &(info->datafile),     temp_datafile );
+
+       snprintf(temp_configfile, sizeof(temp_configfile)-1, "%s%s", where, 
                 driver.info_3->configfile);
        init_unistr( &(info->configfile),   temp_configfile );  
 }
@@ -2036,78 +2377,146 @@ static void construct_printer_driver_info_3(DRIVER_INFO_3 *info, int snum,
 
 /****************************************************************************
 ****************************************************************************/
-uint32 _spoolss_getprinterdriver2( const POLICY_HND *handle,
-                               const UNISTR2 *uni_arch,
-                               uint32 level,
-                               DRIVER_INFO *ctr,
-                               uint32 *offered,
-                               uint32 *needed)
+static uint32 getprinterdriver2_level1(pstring servername, pstring architecture, int snum, NEW_BUFFER *buffer, uint32 offered, uint32 *needed)
 {
-       pstring servername;
-       fstring architecture;
-       int snum;
-       DRIVER_INFO_1 *info1=NULL;
-       DRIVER_INFO_2 *info2=NULL;
-       DRIVER_INFO_3 *info3=NULL;
+       DRIVER_INFO_1 *info=NULL;
+       
+       info=(DRIVER_INFO_1 *)malloc(sizeof(DRIVER_INFO_1));
+       
+       construct_printer_driver_info_1(info, snum, servername, architecture);
 
-       pstrcpy(servername, global_myname);
+       /* check the required size. */  
+       *needed += spoolss_size_printer_driver_info_1(info);
 
-       if (!get_printer_snum(handle,&snum))
-       {
-               return NT_STATUS_INVALID_HANDLE;
+       if (!alloc_buffer_size(buffer, *needed)) {
+               safe_free(info);
+               return ERROR_INSUFFICIENT_BUFFER;
        }
 
-       unistr2_to_ascii(architecture, uni_arch, sizeof(architecture) );
+       /* fill the buffer with the structures */
+       new_smb_io_printer_driver_info_1("", buffer, info, 0);  
+
+       /* clear memory */
+       safe_free(info);
+
+       if (*needed > offered)
+               return ERROR_INSUFFICIENT_BUFFER;
+       else
+               return NT_STATUS_NO_PROBLEMO;
+}
+
+/****************************************************************************
+****************************************************************************/
+static uint32 getprinterdriver2_level2(pstring servername, pstring architecture, int snum, NEW_BUFFER *buffer, uint32 offered, uint32 *needed)
+{
+       DRIVER_INFO_2 *info=NULL;
        
-       DEBUG(1,("spoolss_getprinterdriver2:[%d]\n", level));
+       info=(DRIVER_INFO_2 *)malloc(sizeof(DRIVER_INFO_2));
        
-       switch (level)
-       {
-               case 1:
-               {                       
-                       info1=(DRIVER_INFO_1 *)malloc(sizeof(DRIVER_INFO_1));
-                       construct_printer_driver_info_1(info1, snum, servername, architecture);
-                       ctr->driver.info1=info1;                        
+       construct_printer_driver_info_2(info, snum, servername, architecture);
 
-                       return 0x0;
-               }
-               case 2:
-               {
-                       info2=(DRIVER_INFO_2 *)malloc(sizeof(DRIVER_INFO_2));
-                       construct_printer_driver_info_2(info2, snum, servername, architecture);
-                       ctr->driver.info2=info2;                        
+       /* check the required size. */  
+       *needed += spoolss_size_printer_driver_info_2(info);
 
-                       return 0x0;
-               }
-               case 3:
-               {
-                       info3=(DRIVER_INFO_3 *)malloc(sizeof(DRIVER_INFO_3));
-                       construct_printer_driver_info_3(info3, snum, servername, architecture);
-                       ctr->driver.info3=info3;
+       if (!alloc_buffer_size(buffer, *needed)) {
+               safe_free(info);
+               return ERROR_INSUFFICIENT_BUFFER;
+       }
 
-                       return 0x0;
-               }
-               default:
-               {
-                       break;
-               }
+       /* fill the buffer with the structures */
+       new_smb_io_printer_driver_info_2("", buffer, info, 0);  
+
+       /* clear memory */
+       safe_free(info);
+
+       if (*needed > offered)
+               return ERROR_INSUFFICIENT_BUFFER;
+       else
+               return NT_STATUS_NO_PROBLEMO;
+}
+
+/****************************************************************************
+****************************************************************************/
+static uint32 getprinterdriver2_level3(pstring servername, pstring architecture, int snum, NEW_BUFFER *buffer, uint32 offered, uint32 *needed)
+{
+       DRIVER_INFO_3 *info=NULL;
+       
+       info=(DRIVER_INFO_3 *)malloc(sizeof(DRIVER_INFO_3));
+       
+       construct_printer_driver_info_3(info, snum, servername, architecture);
+
+       /* check the required size. */  
+       *needed += spoolss_size_printer_driver_info_3(info);
+
+       if (!alloc_buffer_size(buffer, *needed)) {
+               safe_free(info);
+               return ERROR_INSUFFICIENT_BUFFER;
+       }
+
+       /* fill the buffer with the structures */
+       new_smb_io_printer_driver_info_3("", buffer, info, 0);  
+
+       /* clear memory */
+       safe_free(info);
+
+       if (*needed > offered)
+               return ERROR_INSUFFICIENT_BUFFER;
+       else
+               return NT_STATUS_NO_PROBLEMO;
+}
+
+/****************************************************************************
+****************************************************************************/
+uint32 _spoolss_getprinterdriver2(const POLICY_HND *handle, const UNISTR2 *uni_arch, uint32 level, 
+                               uint32 clientmajorversion, uint32 clientminorversion,
+                               NEW_BUFFER *buffer, uint32 offered,
+                               uint32 *needed, uint32 *servermajorversion, uint32 *serverminorversion)
+{
+       pstring servername;
+       fstring architecture;
+       int snum;
+
+       DEBUG(4,("_spoolss_getprinterdriver2\n"));
+
+       *needed=0;
+       *servermajorversion=0;
+       *serverminorversion=0;
+
+       pstrcpy(servername, global_myname);
+       unistr2_to_ascii(architecture, uni_arch, sizeof(architecture)-1);
+
+       if (!get_printer_snum(handle, &snum))
+               return NT_STATUS_INVALID_HANDLE;
+
+       switch (level) {
+       case 1:
+               return getprinterdriver2_level1(servername, architecture, snum, buffer, offered, needed);
+               break;
+       case 2:
+               return getprinterdriver2_level2(servername, architecture, snum, buffer, offered, needed);
+               break;                          
+       case 3:
+               return getprinterdriver2_level3(servername, architecture, snum, buffer, offered, needed);
+               break;                          
+       default:
+               return NT_STATUS_INVALID_LEVEL;
+               break;
        }
-       return NT_STATUS_INVALID_INFO_CLASS;
 }
 
 /****************************************************************************
 ****************************************************************************/
 uint32 _spoolss_startpageprinter(const POLICY_HND *handle)
 {
-       int pnum = find_printer_index_by_hnd(handle);
+       Printer_entry *Printer = find_printer_index_by_hnd(handle);
 
-       if (OPEN_HANDLE(pnum))
+       if (OPEN_HANDLE(Printer))
        {
-               Printer[pnum].page_started=True;
+               Printer->page_started=True;
                return 0x0;
        }
 
-       DEBUG(3,("Error in startpageprinter printer handle (pnum=%x)\n",pnum));
+       DEBUG(3,("Error in startpageprinter printer handle\n"));
        return NT_STATUS_INVALID_HANDLE;
 }
 
@@ -2115,16 +2524,17 @@ uint32 _spoolss_startpageprinter(const POLICY_HND *handle)
 ****************************************************************************/
 uint32 _spoolss_endpageprinter(const POLICY_HND *handle)
 {
-       int pnum = find_printer_index_by_hnd(handle);
+       Printer_entry *Printer = find_printer_index_by_hnd(handle);
 
-       if (OPEN_HANDLE(pnum))
+       if (!OPEN_HANDLE(Printer))
        {
-               Printer[pnum].page_started=False;
-               return 0x0;
+               DEBUG(3,("Error in endpageprinter printer handle\n"));
+               return NT_STATUS_INVALID_HANDLE;
        }
+       
+       Printer->page_started=False;
 
-       DEBUG(3,("Error in endpageprinter printer handle (pnum=%x)\n",pnum));
-       return NT_STATUS_INVALID_HANDLE;
+       return NT_STATUS_NO_PROBLEMO;
 }
 
 
@@ -2143,11 +2553,9 @@ uint32 _spoolss_startdocprinter( const POLICY_HND *handle, uint32 level,
        pstring datatype;
        int fd = -1;
        int snum;
-       int pnum;
-
-       pnum = find_printer_index_by_hnd(handle);
+       Printer_entry *Printer = find_printer_index_by_hnd(handle);
 
-       if (!VALID_HANDLE(pnum))
+       if (!OPEN_HANDLE(Printer))
        {
                return NT_STATUS_INVALID_HANDLE;
        }
@@ -2170,7 +2578,7 @@ uint32 _spoolss_startdocprinter( const POLICY_HND *handle, uint32 level,
                if (strcmp(datatype, "RAW") != 0)
                {
                        (*jobid)=0;
-                       return STATUS_1804;
+                       return ERROR_INVALID_DATATYPE;
                }               
        }                
        
@@ -2187,19 +2595,17 @@ uint32 _spoolss_startdocprinter( const POLICY_HND *handle, uint32 level,
        slprintf(tempname,sizeof(tempname)-1, "%s/smb_print.XXXXXX",lp_pathname(snum));  
        pstrcpy(fname, (char *)mktemp(tempname));
 
-       fd=open(fname, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR );
+       fd=open(fname, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, S_IRUSR|S_IWUSR );
        DEBUG(4,("Temp spool file created: [%s]\n", fname));
 
-       Printer[pnum].current_jobid=fd;
-       pstrcpy(Printer[pnum].document_name,fname);
+       Printer->current_jobid=fd;
+       pstrcpy(Printer->document_name, fname);
        
-       unistr2_to_ascii(Printer[pnum].job_name, 
-                        &info_1->docname, 
-                        sizeof(Printer[pnum].job_name));
+       unistr2_to_ascii(Printer->job_name, &info_1->docname, sizeof(Printer->job_name));
        
-       Printer[pnum].document_fd=fd;
-       Printer[pnum].document_started=True;
-       (*jobid) = Printer[pnum].current_jobid;
+       Printer->document_fd=fd;
+       Printer->document_started=True;
+       (*jobid) = Printer->current_jobid;
 
        return 0x0;
 }
@@ -2211,29 +2617,28 @@ uint32 _spoolss_startdocprinter( const POLICY_HND *handle, uint32 level,
  ********************************************************************/
 uint32 _spoolss_enddocprinter(const POLICY_HND *handle)
 {
-       int pnum;
        int snum;
        pstring filename;
        pstring filename1;
        pstring job_name;
        pstring syscmd;
        char *tstr;
+       Printer_entry *Printer=find_printer_index_by_hnd(handle);
        
        *syscmd=0;
        
-       pnum = find_printer_index_by_hnd(handle);
-       
-       if (!OPEN_HANDLE(pnum))
+       if (!OPEN_HANDLE(Printer))
        {
-               DEBUG(3,("Error in enddocprinter handle (pnum=%x)\n",pnum));
+               DEBUG(3,("Error in enddocprinter handle\n"));
                return NT_STATUS_INVALID_HANDLE;
        }
-       Printer[pnum].document_started=False;
-       close(Printer[pnum].document_fd);
+       
+       Printer->document_started=False;
+       close(Printer->document_fd);
        DEBUG(4,("Temp spool file closed, printing now ...\n"));
 
-       pstrcpy(filename1, Printer[pnum].document_name);
-       pstrcpy(job_name, Printer[pnum].job_name);
+       pstrcpy(filename1, Printer->document_name);
+       pstrcpy(job_name, Printer->job_name);
        
        if (!get_printer_snum(handle,&snum))
        {
@@ -2303,20 +2708,18 @@ uint32 _spoolss_writeprinter( const POLICY_HND *handle,
                                const uint8 *buffer,
                                uint32 *buffer_written)
 {
-       int pnum;
        int fd;
+       Printer_entry *Printer = find_printer_index_by_hnd(handle);
        
-       pnum = find_printer_index_by_hnd(handle);
-       
-       if (!OPEN_HANDLE(pnum))
+       if (!OPEN_HANDLE(Printer))
        {
-               DEBUG(3,("Error in writeprinter handle (pnum=%x)\n",pnum));
+               DEBUG(3,("Error in writeprinter handle\n"));
                return NT_STATUS_INVALID_HANDLE;
        }
 
-       fd = Printer[pnum].document_fd;
+       fd = Printer->document_fd;
        (*buffer_written) = write(fd, buffer, buffer_size);
-       Printer[pnum].document_lastwritten = (*buffer_written);
+       Printer->document_lastwritten = (*buffer_written);
 
        return 0x0;
 }
@@ -2328,29 +2731,36 @@ uint32 _spoolss_writeprinter( const POLICY_HND *handle,
  ********************************************************************/
 static uint32 control_printer(const POLICY_HND *handle, uint32 command)
 {
-       int pnum;
        int snum;
-       pnum = find_printer_index_by_hnd(handle);
+       Printer_entry *Printer = find_printer_index_by_hnd(handle);
 
-       if ( pnum == -1 || !get_printer_snum(handle, &snum) )
-       {                
+       if (!OPEN_HANDLE(Printer))
                return NT_STATUS_INVALID_HANDLE;
-       }
 
-       switch (command)
-       {
+       if (!get_printer_snum(handle, &snum) )   
+               return NT_STATUS_INVALID_HANDLE;
+
+       switch (command) {
                case PRINTER_CONTROL_PAUSE:
                        /* pause the printer here */
                        status_printqueue(NULL, snum, LPSTAT_STOPPED);
                        return 0x0;
-
+                       break;
                case PRINTER_CONTROL_RESUME:
                case PRINTER_CONTROL_UNPAUSE:
                        /* UN-pause the printer here */
                        status_printqueue(NULL, snum, LPSTAT_OK);
                        return 0x0;
+                       break;
                case PRINTER_CONTROL_PURGE:
-                       /* Envoi des dragées FUCA dans l'imprimante */
+                       /*
+                        * It's not handled by samba
+                        * we need a smb.conf param to do
+                        * lprm -P%p - on BSD
+                        * lprm -P%p all on LPRNG
+                        * I don't know on SysV
+                        * we could do it by looping in the job's list...
+                        */
                        break;
        }
 
@@ -2365,35 +2775,33 @@ static uint32 update_printer(const POLICY_HND *handle, uint32 level,
                            const SPOOL_PRINTER_INFO_LEVEL *info,
                            const DEVICEMODE *devmode)
 {
-       int pnum;
        int snum;
        NT_PRINTER_INFO_LEVEL printer;
        NT_DEVICEMODE *nt_devmode;
-       uint32 status = 0x0;
+       Printer_entry *Printer = find_printer_index_by_hnd(handle);
 
        nt_devmode=NULL;
        
        DEBUG(8,("update_printer\n"));
        
-       if (level!=2)
-       {
-               DEBUG(0,("Send a mail to samba-bugs@samba.org\n"));
+       if (level!=2) {
+               DEBUG(0,("Send a mail to jfm@samba.org\n"));
                DEBUGADD(0,("with the following message: update_printer: level!=2\n"));
                return NT_STATUS_INVALID_INFO_CLASS;
        }
 
-       pnum = find_printer_index_by_hnd(handle);
-       if ( pnum == -1 || !get_printer_snum(handle, &snum) )
-       {
+       if (!OPEN_HANDLE(Printer))
                return NT_STATUS_INVALID_HANDLE;
-       }
-       get_a_printer(&printer, level, lp_servicename(snum));
+
+       if (!get_printer_snum(handle, &snum) )
+               return NT_STATUS_INVALID_HANDLE;
+       
+       get_a_printer(&printer, 2, lp_servicename(snum));
 
        DEBUGADD(8,("Converting info_2 struct\n"));
        convert_printer_info(info, &printer, level);
        
-       if ((info->info_2)->devmode_ptr != 0)
-       {
+       if ((info->info_2)->devmode_ptr != 0) {
                /* we have a valid devmode
                   convert it and link it*/
                
@@ -2409,48 +2817,44 @@ static uint32 update_printer(const POLICY_HND *handle, uint32 level,
                                
                convert_devicemode(*devmode, nt_devmode);
        }
-       else
-       {
+       else {
                if (printer.info_2->devmode != NULL)
-               {
                        free(printer.info_2->devmode);
-               }
                printer.info_2->devmode=NULL;
        }
                        
-       if (status == 0x0)
-       {
-               status = add_a_printer(printer, level);
-       }
-       if (status == 0x0)
-       {
-               status = free_a_printer(printer, level);
+       if (add_a_printer(printer, 2)!=0) {
+               free_a_printer(printer, 2);
+               
+               /* I don't really know what to return here !!! */
+               return NT_STATUS_INVALID_INFO_CLASS;
        }
 
-       return status;
+       free_a_printer(printer, 2);
+
+       return NT_STATUS_NO_PROBLEMO;
 }
 
 /****************************************************************************
 ****************************************************************************/
-uint32 _spoolss_setprinter( const POLICY_HND *handle,
-                               uint32 level,
-                               const SPOOL_PRINTER_INFO_LEVEL *info,
-                               const DEVICEMODE *devmode,
-                               uint32 sec_buf_size,
-                               const char *sec_buf,
-                               uint32 command)
+uint32 _spoolss_setprinter(const POLICY_HND *handle, uint32 level,
+                          const SPOOL_PRINTER_INFO_LEVEL *info,
+                          const DEVMODE_CTR devmode_ctr,
+                          uint32 command)
 {
-       int pnum = find_printer_index_by_hnd(handle);
+       Printer_entry *Printer = find_printer_index_by_hnd(handle);
        
-       if (!OPEN_HANDLE(pnum))
-       {
+       if (!OPEN_HANDLE(Printer))
                return NT_STATUS_INVALID_HANDLE;
-       }
+
        /* check the level */   
-       switch (level)
-       {
-               case 0: return control_printer(handle, command);
-               case 2: return update_printer(handle, level, info, devmode);
+       switch (level) {
+               case 0:
+                       return control_printer(handle, command);
+                       break;
+               case 2:
+                       return update_printer(handle, level, info, devmode_ctr.devmode);
+                       break;
        }
 
        return NT_STATUS_INVALID_INFO_CLASS;
@@ -2458,18 +2862,29 @@ uint32 _spoolss_setprinter( const POLICY_HND *handle,
 
 /****************************************************************************
 ****************************************************************************/
-uint32 _spoolss_fcpn( const POLICY_HND *handle)
+uint32 _spoolss_fcpn(const POLICY_HND *handle)
 {
-       return 0x0;
-}
-
-/****************************************************************************
+       Printer_entry *Printer= find_printer_index_by_hnd(handle);
+       
+       if (!OPEN_HANDLE(Printer))
+               return NT_STATUS_INVALID_HANDLE;
+       
+       Printer->notify.flags=0;
+       Printer->notify.options=0;
+       Printer->notify.localmachine[0]='\0';
+       Printer->notify.printerlocal=0;
+       safe_free(Printer->notify.option);
+       Printer->notify.option=NULL;
+       
+       return NT_STATUS_NO_PROBLEMO;
+}
+
+/****************************************************************************
 ****************************************************************************/
-uint32 _spoolss_addjob( const POLICY_HND *handle, uint32 level,
-                               const BUFFER *buffer,
-                               uint32 buf_size)
+uint32 _spoolss_addjob(const POLICY_HND *handle, uint32 level,
+                       NEW_BUFFER *buffer, uint32 offered)
 {
-       return 0x0;
+       return NT_STATUS_NO_PROBLEMO;
 }
 
 /****************************************************************************
@@ -2559,76 +2974,125 @@ static BOOL fill_job_info_2(JOB_INFO_2 *job_info, print_queue_struct *queue,
 }
 
 /****************************************************************************
+ Enumjobs at level 1.
 ****************************************************************************/
-uint32 _spoolss_enumjobs( const POLICY_HND *handle,
-                               uint32 reqfirstjob,
-                               uint32 reqnumofjobs,
-                               uint32 level,
-                               JOB_INFO_CTR *ctr,
-                               uint32 *buf_size,
-                               uint32 *numofjobs)
+static uint32 enumjobs_level1(print_queue_struct *queue, int snum, 
+                             NEW_BUFFER *buffer, uint32 offered, 
+                             uint32 *needed, uint32 *returned)
 {
-       int snum;
-       int count;
+       JOB_INFO_1 *info;
+       int i;
+       
+       info=(JOB_INFO_1 *)malloc(*returned*sizeof(JOB_INFO_1));
+       
+       for (i=0; i<*returned; i++)
+       {
+               fill_job_info_1(&(info[i]), &(queue[i]), i, snum);
+       }
+
+       /* check the required size. */  
+       for (i=0; i<*returned; i++)
+               (*needed) += spoolss_size_job_info_1(&(info[i]));
+
+       if (!alloc_buffer_size(buffer, *needed))
+               return ERROR_INSUFFICIENT_BUFFER;
+
+       /* fill the buffer with the structures */
+       for (i=0; i<*returned; i++)
+               new_smb_io_job_info_1("", buffer, &(info[i]), 0);       
+
+       /* clear memory */
+       safe_free(queue);
+       safe_free(info);
+
+       if (*needed > offered) {
+               *returned=0;
+               return ERROR_INSUFFICIENT_BUFFER;
+       }
+       else
+               return NT_STATUS_NO_PROBLEMO;
+}
+
+/****************************************************************************
+ Enumjobs at level 2.
+****************************************************************************/
+static uint32 enumjobs_level2(print_queue_struct *queue, int snum, 
+                             NEW_BUFFER *buffer, uint32 offered, 
+                             uint32 *needed, uint32 *returned)
+{
+       JOB_INFO_2 *info;
        int i;
+       
+       info=(JOB_INFO_2 *)malloc(*returned*sizeof(JOB_INFO_2));
+       
+       for (i=0; i<*returned; i++)
+       {
+               fill_job_info_2(&(info[i]), &(queue[i]), i, snum);
+       }
+
+       /* check the required size. */  
+       for (i=0; i<*returned; i++)
+               (*needed) += spoolss_size_job_info_2(&(info[i]));
+
+       if (!alloc_buffer_size(buffer, *needed))
+               return ERROR_INSUFFICIENT_BUFFER;
+
+       /* fill the buffer with the structures */
+       for (i=0; i<*returned; i++)
+               new_smb_io_job_info_2("", buffer, &(info[i]), 0);       
+
+       /* clear memory */
+       safe_free(queue);
+       safe_free(info);
+
+       if (*needed > offered) {
+               *returned=0;
+               return ERROR_INSUFFICIENT_BUFFER;
+       }
+       else
+               return NT_STATUS_NO_PROBLEMO;
+}
+
+/****************************************************************************
+ Enumjobs.
+****************************************************************************/
+uint32 _spoolss_enumjobs( POLICY_HND *handle, uint32 firstjob, uint32 numofjobs, uint32 level,                   
+                         NEW_BUFFER *buffer, uint32 offered,
+                         uint32 *needed, uint32 *returned)
+{      
+       int snum;
        print_queue_struct *queue=NULL;
        print_status_struct prt_status;
 
-       DEBUG(4,("spoolss_enumjobs\n"));
-       
+       DEBUG(4,("_spoolss_enumjobs\n"));
+
        ZERO_STRUCT(prt_status);
 
+       *needed=0;
+       *returned=0;
+
        if (!get_printer_snum(handle, &snum))
        {
                return NT_STATUS_INVALID_HANDLE;
        }
 
-       count = get_printqueue(snum, NULL, &queue, &prt_status);
-       (*numofjobs) = 0;
-       
-       DEBUG(4,("count:[%d], status:[%d], [%s]\n",
-                 count, prt_status.status, prt_status.message));
-       
-       switch (level)
-       {
-               case 1:
-               {
-                       for (i=0; i<count; i++)
-                       {
-                               JOB_INFO_1 *job_info_1;
-                               job_info_1=(JOB_INFO_1 *)malloc(sizeof(JOB_INFO_1));
-                               add_job1_to_array(numofjobs,
-                                                 &ctr->job.job_info_1,
-                                                 job_info_1);
-
-                               fill_job_info_1(ctr->job.job_info_1[i],
-                                               &(queue[i]), i, snum);
-                       }
-                       safe_free(queue);
-                       return 0x0;
-               }
-               case 2:
-               {
-                       for (i=0; i<count; i++)
-                       {
-                               JOB_INFO_2 *job_info_2;
-                               job_info_2=(JOB_INFO_2 *)malloc(sizeof(JOB_INFO_2));
-                               add_job2_to_array(numofjobs,
-                                                 &ctr->job.job_info_2,
-                                                 job_info_2);
-
-                               fill_job_info_2(ctr->job.job_info_2[i],
-                                               &(queue[i]), i, snum);
-                       }
-                       safe_free(queue);
-                       return 0x0;
-               }
+       *returned = get_printqueue(snum, NULL, &queue, &prt_status);
+       DEBUGADD(4,("count:[%d], status:[%d], [%s]\n", *returned, prt_status.status, prt_status.message));
+
+       switch (level) {
+       case 1:
+               return enumjobs_level1(queue, snum, buffer, offered, needed, returned);
+               break;
+       case 2:
+               return enumjobs_level2(queue, snum, buffer, offered, needed, returned);
+               break;                          
+       default:
+               return NT_STATUS_INVALID_LEVEL;
+               break;
        }
+}
 
-       safe_free(queue);
 
-       return NT_STATUS_INVALID_INFO_CLASS;
-}
 
 /****************************************************************************
 ****************************************************************************/
@@ -2653,7 +3117,7 @@ uint32 _spoolss_setjob( const POLICY_HND *handle,
        BOOL found=False;
        int count;
                
-       bzero(&prt_status,sizeof(prt_status));
+       memset(&prt_status, 0, sizeof(prt_status));
 
        if (!get_printer_snum(handle, &snum))
        {
@@ -2702,86 +3166,166 @@ uint32 _spoolss_setjob( const POLICY_HND *handle,
 }
 
 /****************************************************************************
+ Enumerates all printer drivers at level 1.
 ****************************************************************************/
-uint32 _spoolss_enumprinterdrivers( const UNISTR2 *name,
-                               const UNISTR2 *environment,
-                               uint32 level,
-                               DRIVER_INFO *ctr,
-                               uint32 *offered,
-                               uint32 *numofdrivers)
+static uint32 enumprinterdrivers_level1(fstring *list, fstring servername, fstring architecture, NEW_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
 {
-       NT_PRINTER_DRIVER_INFO_LEVEL driver;
-       int count;
        int i;
-       fstring *list;
-       fstring servername;
-       fstring architecture;
+       NT_PRINTER_DRIVER_INFO_LEVEL driver;
+       DRIVER_INFO_1 *driver_info_1=NULL;
+       driver_info_1=(DRIVER_INFO_1 *)malloc(*returned * sizeof(DRIVER_INFO_1));
 
-       DEBUG(4,("spoolss_enumdrivers\n"));
-       fstrcpy(servername, global_myname);
+       for (i=0; i<*returned; i++) {
+               get_a_printer_driver(&driver, 3, list[i], architecture);
+               fill_printer_driver_info_1(&(driver_info_1[i]), driver, servername, architecture );
+               free_a_printer_driver(driver, 3);
+       }
+       
+       /* check the required size. */
+       for (i=0; i<*returned; i++)
+       {
+               DEBUGADD(6,("adding driver [%d]'s size\n",i));
+               *needed += spoolss_size_printer_driver_info_1(&(driver_info_1[i]));
+       }
 
-       unistr2_to_ascii(architecture, environment, sizeof(architecture));
-       count=get_ntdrivers(&list, architecture);
+       if (!alloc_buffer_size(buffer, *needed))
+               return ERROR_INSUFFICIENT_BUFFER;
 
-       DEBUGADD(4,("we have: [%d] drivers on archi [%s]\n",count, architecture));
-       for (i=0; i<count; i++)
+       /* fill the buffer with the form structures */
+       for (i=0; i<*returned; i++)
        {
-               DEBUGADD(5,("driver [%s]\n",list[i]));
+               DEBUGADD(6,("adding driver [%d] to buffer\n",i));
+               new_smb_io_printer_driver_info_1("", buffer, &(driver_info_1[i]), 0);
+       }
+
+       safe_free(list);
+
+       if (*needed > offered)
+               return ERROR_INSUFFICIENT_BUFFER;
+       else
+               return NT_STATUS_NO_PROBLEMO;
+}
+
+/****************************************************************************
+ Enumerates all printer drivers at level 2.
+****************************************************************************/
+static uint32 enumprinterdrivers_level2(fstring *list, fstring servername, fstring architecture, NEW_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+{
+       int i;
+       NT_PRINTER_DRIVER_INFO_LEVEL driver;
+       DRIVER_INFO_2 *driver_info_2=NULL;
+       driver_info_2=(DRIVER_INFO_2 *)malloc(*returned * sizeof(DRIVER_INFO_2));
+
+       for (i=0; i<*returned; i++) {
+               get_a_printer_driver(&driver, 3, list[i], architecture);
+               fill_printer_driver_info_2(&(driver_info_2[i]), driver, servername, architecture );
+               free_a_printer_driver(driver, 3);
        }
        
-       (*numofdrivers)=count;
+       /* check the required size. */
+       for (i=0; i<*returned; i++)
+       {
+               DEBUGADD(6,("adding driver [%d]'s size\n",i));
+               *needed += spoolss_size_printer_driver_info_2(&(driver_info_2[i]));
+       }
+
+       if (!alloc_buffer_size(buffer, *needed))
+               return ERROR_INSUFFICIENT_BUFFER;
+
+       /* fill the buffer with the form structures */
+       for (i=0; i<*returned; i++)
+       {
+               DEBUGADD(6,("adding driver [%d] to buffer\n",i));
+               new_smb_io_printer_driver_info_2("", buffer, &(driver_info_2[i]), 0);
+       }
+
+       safe_free(list);
+
+       if (*needed > offered)
+               return ERROR_INSUFFICIENT_BUFFER;
+       else
+               return NT_STATUS_NO_PROBLEMO;
+}
+
+/****************************************************************************
+ Enumerates all printer drivers at level 3.
+****************************************************************************/
+static uint32 enumprinterdrivers_level3(fstring *list, fstring servername, fstring architecture, NEW_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+{
+       int i;
+       NT_PRINTER_DRIVER_INFO_LEVEL driver;
+       DRIVER_INFO_3 *driver_info_3=NULL;
+       driver_info_3=(DRIVER_INFO_3 *)malloc((*returned)*sizeof(DRIVER_INFO_3));
+
+       for (i=0; i<*returned; i++) {
+               get_a_printer_driver(&driver, 3, list[i], architecture);
+               fill_printer_driver_info_3(&(driver_info_3[i]), driver, servername, architecture );
+               free_a_printer_driver(driver, 3);
+       }
        
-       switch (level)
+       /* check the required size. */
+       for (i=0; i<*returned; i++)
        {
-               case 1:
-               {
-                       DRIVER_INFO_1 *driver_info_1=NULL;
-                       driver_info_1=(DRIVER_INFO_1 *)malloc(count*sizeof(DRIVER_INFO_1));
+               DEBUGADD(6,("adding driver [%d]'s size\n",i));
+               *needed += spoolss_size_printer_driver_info_3(&(driver_info_3[i]));
+       }
 
-                       for (i=0; i<count; i++)
-                       {
-                               get_a_printer_driver(&driver, 3, list[i], architecture);
-                               fill_printer_driver_info_1(&(driver_info_1[i]), driver, servername, architecture );
-                               free_a_printer_driver(driver, 3);
-                       }
-                       ctr->driver.info1=driver_info_1;
-                       break;
-               }
-               case 2:
-               {
-                       DRIVER_INFO_2 *driver_info_2=NULL;
-                       driver_info_2=(DRIVER_INFO_2 *)malloc(count*sizeof(DRIVER_INFO_2));
-
-                       for (i=0; i<count; i++)
-                       {
-                               get_a_printer_driver(&driver, 3, list[i], architecture);
-                               fill_printer_driver_info_2(&(driver_info_2[i]), driver, servername, architecture );
-                               free_a_printer_driver(driver, 3);
-                       }
-                       ctr->driver.info2=driver_info_2;
-                       break;
-               }
-               case 3:
-               {
-                       DRIVER_INFO_3 *driver_info_3=NULL;
-                       driver_info_3=(DRIVER_INFO_3 *)malloc(count*sizeof(DRIVER_INFO_3));
-
-                       for (i=0; i<count; i++)
-                       {
-                               get_a_printer_driver(&driver, 3, list[i], architecture);
-                               fill_printer_driver_info_3(&(driver_info_3[i]), driver, servername, architecture );
-                               free_a_printer_driver(driver, 3);
-                       }
-                       ctr->driver.info3=driver_info_3;
-                       break;
-               }
-               default:
-               {
-                       return NT_STATUS_INVALID_INFO_CLASS;
-               }
+       if (!alloc_buffer_size(buffer, *needed))
+               return ERROR_INSUFFICIENT_BUFFER;
+
+       /* fill the buffer with the form structures */
+       for (i=0; i<*returned; i++)
+       {
+               DEBUGADD(6,("adding form [%d] to buffer\n",i));
+               new_smb_io_printer_driver_info_3("", buffer, &(driver_info_3[i]), 0);
        }
-       return 0x0;
 
+       safe_free(list);
+
+       if (*needed > offered)
+               return ERROR_INSUFFICIENT_BUFFER;
+       else
+               return NT_STATUS_NO_PROBLEMO;
+}
+
+/****************************************************************************
+ Enumerates all printer drivers.
+****************************************************************************/
+uint32 _spoolss_enumprinterdrivers( UNISTR2 *name, UNISTR2 *environment, uint32 level,
+                                   NEW_BUFFER *buffer, uint32 offered,
+                                   uint32 *needed, uint32 *returned)
+{
+       int i;
+       fstring *list;
+       fstring servername;
+       fstring architecture;
+
+       DEBUG(4,("_spoolss_enumprinterdrivers\n"));
+       fstrcpy(servername, global_myname);
+       *needed=0;
+       *returned=0;
+
+       unistr2_to_ascii(architecture, environment, sizeof(architecture)-1);
+       *returned=get_ntdrivers(&list, architecture);
+
+       DEBUGADD(4,("we have: [%d] drivers in environment [%s]\n", *returned, architecture));
+       for (i=0; i<*returned; i++)
+               DEBUGADD(5,("driver: [%s]\n", list[i]));
+       
+       switch (level) {
+       case 1:
+               return enumprinterdrivers_level1(list, servername, architecture, buffer, offered, needed, returned);
+               break;
+       case 2:
+               return enumprinterdrivers_level2(list, servername, architecture, buffer, offered, needed, returned);
+               break;
+       case 3:
+               return enumprinterdrivers_level3(list, servername, architecture, buffer, offered, needed, returned);
+               break;
+       default:
+               return NT_STATUS_INVALID_INFO_CLASS;
+               break;
+       }
 }
 
 /****************************************************************************
@@ -2798,26 +3342,6 @@ static void fill_form_1(FORM_1 *form, nt_forms_struct *list, int position)
        form->bottom=list->bottom;      
 }
        
-/****************************************************************************
-****************************************************************************/
-static BOOL alloc_buffer_size(NEW_BUFFER *buffer, uint32 buffer_size)
-{
-       prs_struct *ps;
-       uint32 extra_space;
-       
-       ps=&(buffer->prs);
-       
-       /* damn, I'm doing the reverse operation of prs_grow() :) */
-       extra_space = buffer_size - prs_data_size(ps);
-       
-       if (!prs_grow(ps, extra_space))
-               return False;
-
-       buffer->string_at_end=buffer_size;
-
-       return True;
-}
-
 /****************************************************************************
 ****************************************************************************/
 uint32 _new_spoolss_enumforms( const POLICY_HND *handle, uint32 level, 
@@ -2829,7 +3353,6 @@ uint32 _new_spoolss_enumforms( const POLICY_HND *handle, uint32 level,
        int buffer_size=0;
        int i;
 
-
        DEBUG(4,("_new_spoolss_enumforms\n"));
        DEBUGADD(5,("Offered buffer size [%d]\n", offered));
        DEBUGADD(5,("Info level [%d]\n",          level));
@@ -2857,8 +3380,10 @@ uint32 _new_spoolss_enumforms( const POLICY_HND *handle, uint32 level,
 
                *needed=buffer_size;            
                
-               if (!alloc_buffer_size(buffer, buffer_size))
+               if (!alloc_buffer_size(buffer, buffer_size)){
+                       safe_free(list);
                        return ERROR_INSUFFICIENT_BUFFER;
+               }
 
                /* fill the buffer with the form structures */
                for (i=0; i<*numofforms; i++)
@@ -2876,50 +3401,16 @@ uint32 _new_spoolss_enumforms( const POLICY_HND *handle, uint32 level,
                        
        default:
                safe_free(list);
-               return NT_STATUS_INVALID_INFO_CLASS;
+               return ERROR_INVALID_LEVEL;
        }
 
 }
 
 /****************************************************************************
 ****************************************************************************/
-uint32 _spoolss_enumforms( const POLICY_HND *handle,
-                               uint32 level,
-                               FORM_1 **forms_1,
-                               uint32 *offered,
-                               uint32 *numofforms)
+static void fill_port_1(PORT_INFO_1 *port, char *name)
 {
-       int count;
-       int i;
-       nt_forms_struct *list=NULL;
-       (*forms_1)=NULL;
-
-       DEBUG(4,("spoolss_enumforms\n"));
-       
-       count = get_ntforms(&list);
-       (*numofforms) = count;
-
-       DEBUGADD(5,("Offered buffer size [%d]\n", *offered));
-       DEBUGADD(5,("Number of forms [%d]\n",     *numofforms));
-       DEBUGADD(5,("Info level [%d]\n",          level));
-               
-       switch (level)
-       {
-               case 1:
-               {
-                       (*forms_1)=(FORM_1 *)malloc(count*sizeof(FORM_1));
-                       for (i=0; i<count; i++)
-                       {
-                               DEBUGADD(6,("Filling form number [%d]\n",i));
-                               fill_form_1(&((*forms_1)[i]), &(list[i]), i);
-                       }
-                       safe_free(list);
-                       return 0x0;
-               }
-       }
-
-       safe_free(list);
-       return NT_STATUS_INVALID_INFO_CLASS;
+       init_unistr(&(port->port_name), name);
 }
 
 /****************************************************************************
@@ -2935,105 +3426,186 @@ static void fill_port_2(PORT_INFO_2 *port, char *name)
 }
 
 /****************************************************************************
+ enumports level 1.
 ****************************************************************************/
-uint32 _spoolss_enumports( const UNISTR2 *name,
-                               uint32 level,
-                               PORT_INFO_CTR *ctr,
-                               uint32 *offered,
-                               uint32 *numofports)
+static uint32 enumports_level_1(NEW_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
 {
        int n_services=lp_numservices();
        int snum;
+       int i=0;
+       
+       PORT_INFO_1 *ports=NULL;
 
-       DEBUG(4,("spoolss_enumports\n"));
+       for (snum=0; snum<n_services; snum++)
+               if ( lp_browseable(snum) && lp_snum_ok(snum) && lp_print_ok(snum) )
+                       (*returned)++;
+
+       ports=(PORT_INFO_1 *)malloc( (*returned+1) * sizeof(PORT_INFO_1) );
        
-       (*numofports) = 0;
+       for (snum=0; snum<n_services; snum++) {
+               if ( lp_browseable(snum) && lp_snum_ok(snum) && lp_print_ok(snum) ) {
+                       DEBUGADD(6,("Filling port number [%d]\n", i));
+                       fill_port_1(&(ports[i]), lp_servicename(snum));
+                       i++;
+               }
+       }
 
-       switch (level)
-       {
-               case 2:
-               {
-                       PORT_INFO_2 *ports_2=NULL;
-                       ports_2=(PORT_INFO_2 *)malloc(n_services*sizeof(PORT_INFO_2));
-                       for (snum=0; snum<n_services; snum++)
-                       {
-                               if ( lp_browseable(snum) &&
-                                    lp_snum_ok(snum) && 
-                                    lp_print_ok(snum) )
-                               {
-                                       DEBUGADD(6,("Filling port no [%d]\n",
-                                                     (*numofports)));
-                                       fill_port_2(&(ports_2[(*numofports)]),
-                                                   lp_servicename(snum));
-                                       (*numofports)++;
-                               }
-                       }
-                       ctr->port.info_2=ports_2;
-                       return 0x0;
-               }
+       /* check the required size. */
+       for (i=0; i<*returned; i++) {
+               DEBUGADD(6,("adding port [%d]'s size\n", i));
+               *needed += spoolss_size_port_info_1(&(ports[i]));
+       }
+               
+       if (!alloc_buffer_size(buffer, *needed)) {
+               safe_free(ports);
+               return ERROR_INSUFFICIENT_BUFFER;
+       }
+
+       /* fill the buffer with the ports structures */
+       for (i=0; i<*returned; i++) {
+               DEBUGADD(6,("adding port [%d] to buffer\n", i));
+               new_smb_io_port_1("", buffer, &(ports[i]), 0);
        }
 
-       return NT_STATUS_INVALID_INFO_CLASS;
+       safe_free(ports);
+
+       if (*needed > offered) {
+               *returned=0;
+               return ERROR_INSUFFICIENT_BUFFER;
+       }
+       else
+               return NT_STATUS_NO_PROBLEMO;
 }
 
+
 /****************************************************************************
+ enumports level 2.
 ****************************************************************************/
-uint32 _spoolss_addprinterex( const UNISTR2 *uni_srv_name,
-                               uint32 level,
-                               const SPOOL_PRINTER_INFO_LEVEL *info,
-                               uint32 unk0,
-                               uint32 unk1,
-                               uint32 unk2,
-                               uint32 unk3,
-                               uint32 user_level,
-                               const SPOOL_USER_LEVEL *user,
-                               POLICY_HND *handle)
+static uint32 enumports_level_2(NEW_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
 {
-       NT_PRINTER_INFO_LEVEL printer;  
-       fstring ascii_name;
-       fstring server_name;
-       fstring share_name;
-       UNISTR2 *portname;
-       SPOOL_PRINTER_INFO_LEVEL_2 *info2;
-       uint32 status = 0x0;
+       int n_services=lp_numservices();
+       int snum;
+       int i=0;
        
-       if (!open_printer_hnd(handle))
-       {
-               return NT_STATUS_ACCESS_DENIED;
-       }
-
-       /* NULLify info_2 here */
-       /* don't put it in convert_printer_info as it's used also with non-NULL values */
-       printer.info_2=NULL;
+       PORT_INFO_2 *ports=NULL;
 
-       /* convert from UNICODE to ASCII */
-       convert_printer_info(info, &printer, level);
+       for (snum=0; snum<n_services; snum++)
+               if ( lp_browseable(snum) && lp_snum_ok(snum) && lp_print_ok(snum) )
+                       (*returned)++;
 
-       /* write the ASCII on disk */
-       status = add_a_printer(printer, level);
-       if (status != 0x0)
-       {
-               close_printer_handle(handle);
-               return status;
+       ports=(PORT_INFO_2 *)malloc( (*returned+1) * sizeof(PORT_INFO_2) );
+       
+       for (snum=0; snum<n_services; snum++) {
+               if ( lp_browseable(snum) && lp_snum_ok(snum) && lp_print_ok(snum) ) {
+                       DEBUGADD(6,("Filling port number [%d]\n", i));
+                       fill_port_2(&(ports[i]), lp_servicename(snum));
+                       i++;
+               }
        }
 
-       info2=info->info_2;
-       portname=&(info2->portname);
+       /* check the required size. */
+       for (i=0; i<*returned; i++) {
+               DEBUGADD(6,("adding port [%d]'s size\n", i));
+               *needed += spoolss_size_port_info_2(&(ports[i]));
+       }
+               
+       if (!alloc_buffer_size(buffer, *needed)) {
+               safe_free(ports);
+               return ERROR_INSUFFICIENT_BUFFER;
+       }
+
+       /* fill the buffer with the ports structures */
+       for (i=0; i<*returned; i++) {
+               DEBUGADD(6,("adding port [%d] to buffer\n", i));
+               new_smb_io_port_2("", buffer, &(ports[i]), 0);
+       }
 
-       StrnCpy(server_name, global_myname, strlen(global_myname) );
-       unistr2_to_ascii(share_name, portname, sizeof(share_name)-1);
+       safe_free(ports);
+
+       if (*needed > offered) {
+               *returned=0;
+               return ERROR_INSUFFICIENT_BUFFER;
+       }
+       else
+               return NT_STATUS_NO_PROBLEMO;
+}
+
+/****************************************************************************
+ enumports.
+****************************************************************************/
+uint32 _spoolss_enumports( UNISTR2 *name, uint32 level, 
+                          NEW_BUFFER *buffer, uint32 offered, 
+                          uint32 *needed, uint32 *returned)
+{
+       DEBUG(4,("_spoolss_enumports\n"));
        
-       slprintf(ascii_name, sizeof(ascii_name)-1, "\\\\%s\\%s", 
-                server_name, share_name);
-               
-       if (!set_printer_hnd_printertype(handle, ascii_name) ||
-           !set_printer_hnd_printername(handle, ascii_name))
-       {
+       *returned=0;
+       *needed=0;
+       
+       switch (level) {
+       case 1:
+               return enumports_level_1(buffer, offered, needed, returned);
+               break;
+       case 2:
+               return enumports_level_2(buffer, offered, needed, returned);
+               break;
+       default:
+               return NT_STATUS_INVALID_INFO_CLASS;
+               break;
+       }
+}
+
+/****************************************************************************
+****************************************************************************/
+uint32 _spoolss_addprinterex( const UNISTR2 *uni_srv_name, uint32 level,
+                               const SPOOL_PRINTER_INFO_LEVEL *info,
+                               uint32 unk0, uint32 unk1, uint32 unk2, uint32 unk3,
+                               uint32 user_switch, const SPOOL_USER_CTR *user,
+                               POLICY_HND *handle)
+{
+       NT_PRINTER_INFO_LEVEL printer;  
+       fstring name;
+       fstring share_name;
+
+       clear_handle(handle);
+       
+/* 
+ * FIX: JFM: we need to check the user here !!!!
+ *
+ * as the code is running as root, anybody can add printers to the server
+ */
+       /* NULLify info_2 here */
+       /* don't put it in convert_printer_info as it's used also with non-NULL values */
+       printer.info_2=NULL;
+
+       /* convert from UNICODE to ASCII */
+       convert_printer_info(info, &printer, level);
+
+       unistr2_to_ascii(share_name, &((info->info_2)->portname), sizeof(share_name)-1);
+       
+       slprintf(name, sizeof(name)-1, "\\\\%s\\%s", global_myname, share_name);
+
+       create_printer_hnd(handle);
+
+       open_printer_hnd(handle);
+
+       if (!set_printer_hnd_printertype(handle, name)) {
+               close_printer_handle(handle);
+               return NT_STATUS_ACCESS_DENIED;
+       }
+       
+       if (!set_printer_hnd_printername(handle, name)) {
                close_printer_handle(handle);
                return NT_STATUS_ACCESS_DENIED;
        }
 
-       return 0x0;
+       /* write the ASCII on disk */
+       if (add_a_printer(printer, level) != 0x0) {
+               close_printer_handle(handle);
+               return NT_STATUS_ACCESS_DENIED;
+       }
+       
+       return NT_STATUS_NO_PROBLEMO;
 }
 
 /****************************************************************************
@@ -3043,46 +3615,86 @@ uint32 _spoolss_addprinterdriver( const UNISTR2 *server_name,
                                const SPOOL_PRINTER_DRIVER_INFO_LEVEL *info)
 {
        NT_PRINTER_DRIVER_INFO_LEVEL driver;
+       
        convert_printer_driver_info(info, &driver, level);
-       return add_a_printer_driver(driver, level);
+
+       if (add_a_printer_driver(driver, level)!=0)
+               return NT_STATUS_ACCESS_DENIED;
+
+       return NT_STATUS_NO_PROBLEMO;
 }
 
 /****************************************************************************
 ****************************************************************************/
-uint32 _spoolss_getprinterdriverdirectory( const UNISTR2 *name,
-                               const UNISTR2 *uni_environment,
-                               uint32 level,
-                               DRIVER_DIRECTORY_CTR *ctr,
-                               uint32 *offered)
+static void fill_driverdir_1(DRIVER_DIRECTORY_1 *info, char *name)
+{
+       init_unistr(&(info->name), name);
+}
+
+/****************************************************************************
+****************************************************************************/
+static uint32 getprinterdriverdir_level_1(UNISTR2 *name, UNISTR2 *uni_environment, NEW_BUFFER *buffer, uint32 offered, uint32 *needed)
 {
        pstring chaine;
        pstring long_archi;
-       pstring archi;
-
+       pstring short_archi;
+       DRIVER_DIRECTORY_1 *info=NULL;
+       
+       info=(DRIVER_DIRECTORY_1 *)malloc(sizeof(DRIVER_DIRECTORY_1));
+       
        unistr2_to_ascii(long_archi, uni_environment, sizeof(long_archi)-1);
-       get_short_archi(archi, long_archi);
+       get_short_archi(short_archi, long_archi);
                
-       slprintf(chaine,sizeof(chaine)-1,"\\\\%s\\print$\\%s",
-                                        global_myname, archi);
+       slprintf(chaine, sizeof(chaine)-1, "\\\\%s\\print$\\%s", global_myname, short_archi);
 
        DEBUG(4,("printer driver directory: [%s]\n", chaine));
-                                                           
-       init_unistr(&(ctr->driver.info_1.name), chaine);
 
-       return 0x0;
+       fill_driverdir_1(info, chaine);
+       
+       *needed += spoolss_size_driverdir_info_1(info);                                                     
+
+       if (!alloc_buffer_size(buffer, *needed)) {
+               safe_free(info);
+               return ERROR_INSUFFICIENT_BUFFER;
+       }
+
+       new_smb_io_driverdir_1("", buffer, info, 0);
+
+       safe_free(info);
+       
+       if (*needed > offered)
+               return ERROR_INSUFFICIENT_BUFFER;
+       else
+               return NT_STATUS_NO_PROBLEMO;
 }
 
 /****************************************************************************
 ****************************************************************************/
-uint32 _spoolss_enumprinterdata(const POLICY_HND *handle, 
-                               uint32 idx,
-                               uint32 *valuesize,
-                               UNISTR *uni_value,
-                               uint32 *realvaluesize,
-                               uint32 *type,
-                               uint32 *datasize,
-                               uint8  **data,
-                               uint32 *realdatasize)
+uint32 _spoolss_getprinterdriverdirectory(UNISTR2 *name, UNISTR2 *uni_environment, uint32 level,
+                                       NEW_BUFFER *buffer, uint32 offered, 
+                                       uint32 *needed)
+{
+       DEBUG(4,("_spoolss_getprinterdriverdirectory\n"));
+
+       *needed=0;
+
+       switch(level) {
+       case 1:
+               return getprinterdriverdir_level_1(name, uni_environment, buffer, offered, needed);
+               break;
+       default:
+               return ERROR_INVALID_LEVEL;
+               break;
+       }
+}
+       
+/****************************************************************************
+****************************************************************************/
+uint32 _spoolss_enumprinterdata(const POLICY_HND *handle, uint32 idx,
+                               uint32 in_value_len, uint32 in_data_len,
+                               uint32 *out_max_value_len, uint16 **out_value, uint32 *out_value_len,
+                               uint32 *out_type,
+                               uint32 *out_max_data_len, uint8  **data_out, uint32 *out_data_len)
 {
        NT_PRINTER_INFO_LEVEL printer;
        
@@ -3092,94 +3704,102 @@ uint32 _spoolss_enumprinterdata(const POLICY_HND *handle,
        uint32 biggest_valuesize;
        uint32 biggest_datasize;
        uint32 data_len;
-       uint32 status = 0x0;
-       
-       int pnum = find_printer_index_by_hnd(handle);
+       Printer_entry *Printer = find_printer_index_by_hnd(handle);
        int snum;
+       uint8 *data=NULL;
+       uint32 type;
 
        ZERO_STRUCT(printer);
-       (*data)=NULL;
+       
+       *out_max_value_len=0;
+       *out_value=NULL;
+       *out_value_len=0;
+
+       *out_type=0;
+
+       *out_max_data_len=0;
+       *data_out=NULL;
+       *out_data_len=0;
 
        DEBUG(5,("spoolss_enumprinterdata\n"));
 
-       if (!OPEN_HANDLE(pnum))
-       {
+       if (!OPEN_HANDLE(Printer))
                return NT_STATUS_INVALID_HANDLE;
-       }
+
        if (!get_printer_snum(handle, &snum))
-       {
                return NT_STATUS_INVALID_HANDLE;
-       }
-       status = get_a_printer(&printer, 2, lp_servicename(snum));
-
-       if (status != 0x0)
-       {
-               return status;
-       }
+       
+       if (get_a_printer(&printer, 2, lp_servicename(snum)) != 0x0)
+               return NT_STATUS_INVALID_HANDLE;
 
-       /* The NT machine wants to know the biggest size of value and data */   
-       if ( ((*valuesize)==0) && ((*datasize)==0) )
-       {
+       /* 
+        * The NT machine wants to know the biggest size of value and data
+        *
+        * cf: MSDN EnumPrinterData remark section
+        */
+       if ( (in_value_len==0) && (in_data_len==0) ) {
                DEBUGADD(6,("Activating NT mega-hack to find sizes\n"));
                
-               (*valuesize)=0;
-               (*realvaluesize)=0;
-               (*type)=0;
-               (*datasize)=0;
-               (*realdatasize)=0;
-               status=0;
-               
                param_index=0;
                biggest_valuesize=0;
                biggest_datasize=0;
                
-               while (get_specific_param_by_index(printer, 2, param_index, value, data, type, &data_len))
-               {
+               while (get_specific_param_by_index(printer, 2, param_index, value, &data, &type, &data_len)) {
                        if (strlen(value) > biggest_valuesize) biggest_valuesize=strlen(value);
-                       if (data_len  > biggest_datasize)  biggest_datasize=data_len;
+                       if (data_len > biggest_datasize) biggest_datasize=data_len;
+
+                       DEBUG(6,("current values: [%d], [%d]\n", biggest_valuesize, biggest_datasize));
 
+                       safe_free(data);
                        param_index++;
                }
-               
-               /* I wrote it, I didn't designed the protocol */
-               if (biggest_valuesize!=0)
-               {
-                       SIVAL(&(value),0, 2*(biggest_valuesize+1) );
-               }
-               (*data)=(uint8 *)malloc(4*sizeof(uint8));
-               SIVAL((*data), 0, biggest_datasize );
+
+               /* the value is an UNICODE string but realvaluesize is the length in bytes including the leading 0 */
+               *out_value_len=2*(1+biggest_valuesize);
+               *out_data_len=biggest_datasize;
+
+               DEBUG(6,("final values: [%d], [%d]\n", *out_value_len, *out_data_len));
+
+               free_a_printer(printer, 2);             
+               return NT_STATUS_NO_PROBLEMO;
        }
-       else
-       {
-               /* 
-                * the value len is wrong in NT sp3
-                * that's the number of bytes not the number of unicode chars
-                */
-                
-               if (get_specific_param_by_index(printer, 2, idx, value, data, type, &data_len))
-               {
-                       init_unistr(uni_value, value);
-                       
-                       /* the length are in bytes including leading NULL */
-                       (*realvaluesize)=2*(strlen(value)+1);
-                       (*realdatasize)=data_len;
-                       
-                       status=0;
-               }
-               else
-               {
-                       (*valuesize)=0;
-                       (*realvaluesize)=0;
-                       (*datasize)=0;
-                       (*realdatasize)=0;
-                       (*type)=0;
-                       status=0x0103; /* ERROR_NO_MORE_ITEMS */
-               }               
+       
+       /* 
+        * the value len is wrong in NT sp3
+        * that's the number of bytes not the number of unicode chars
+        */
+
+       if (!get_specific_param_by_index(printer, 2, idx, value, &data, &type, &data_len)) {
+               free_a_printer(printer, 2);
+               return ERROR_NO_MORE_ITEMS;
        }
+                       
+       /* 
+        * the value is:
+        * - counted in bytes in the request
+        * - counted in UNICODE chars in the max reply
+        * - counted in bytes in the real size
+        *
+        * take a pause *before* coding not *during* coding
+        */
+        
+       *out_max_value_len=in_value_len/2;
+       *out_value=(uint16 *)malloc(in_value_len*sizeof(uint8));
+       ascii_to_unistr(*out_value, value, *out_max_value_len);
+       *out_value_len=2*(1+strlen(value));
+
+       *out_type=type;
+
+       /* the data is counted in bytes */
+       *out_max_data_len=in_data_len;
+       *data_out=(uint8 *)malloc(in_data_len*sizeof(uint8));
+       memcpy(*data_out, data, data_len);
+       *out_data_len=data_len;
+
+       safe_free(data);
        
        free_a_printer(printer, 2);
-
-       return status;
+       return NT_STATUS_NO_PROBLEMO;
 }
 
 /****************************************************************************
@@ -3195,28 +3815,22 @@ uint32 _spoolss_setprinterdata( const POLICY_HND *handle,
        NT_PRINTER_INFO_LEVEL printer;
        NT_PRINTER_PARAM *param = NULL;
                
-       int pnum=0;
        int snum=0;
        uint32 status = 0x0;
+       Printer_entry *Printer=find_printer_index_by_hnd(handle);
        
        DEBUG(5,("spoolss_setprinterdata\n"));
 
-       pnum = find_printer_index_by_hnd(handle);
        
-       if (!OPEN_HANDLE(pnum))
-       {
+       if (!OPEN_HANDLE(Printer))
                return NT_STATUS_INVALID_HANDLE;
-       }
+
        if (!get_printer_snum(handle, &snum))
-       {
                return NT_STATUS_INVALID_HANDLE;
-       }
 
        status = get_a_printer(&printer, 2, lp_servicename(snum));
        if (status != 0x0)
-       {
                return status;
-       }
 
        convert_specific_param(&param, value , type, data, real_len);
        unlink_specific_param_if_exist(printer.info_2, param);
@@ -3240,18 +3854,14 @@ uint32 _spoolss_addform( const POLICY_HND *handle,
                                uint32 level,
                                const FORM *form)
 {
-       int pnum=0;
        int count=0;
        nt_forms_struct *list=NULL;
+       Printer_entry *Printer = find_printer_index_by_hnd(handle);
 
        DEBUG(5,("spoolss_addform\n"));
 
-       pnum = find_printer_index_by_hnd(handle);
-
-       if (!OPEN_HANDLE(pnum))
-       {
+       if (!OPEN_HANDLE(Printer))
                return NT_STATUS_INVALID_HANDLE;
-       }
 
        count=get_ntforms(&list);
        add_a_form(&list, form, &count);
@@ -3269,14 +3879,13 @@ uint32 _spoolss_setform( const POLICY_HND *handle,
                                uint32 level,
                                const FORM *form)
 {
-       int pnum=0;
        int count=0;
        nt_forms_struct *list=NULL;
+       Printer_entry *Printer = find_printer_index_by_hnd(handle);
 
        DEBUG(5,("spoolss_setform\n"));
 
-       pnum = find_printer_index_by_hnd(handle);
-       if (!OPEN_HANDLE(pnum))
+       if (!OPEN_HANDLE(Printer))
        {
                return NT_STATUS_INVALID_HANDLE;
        }
@@ -3290,13 +3899,39 @@ uint32 _spoolss_setform( const POLICY_HND *handle,
 }
 
 /****************************************************************************
+ enumprintprocessors level 1.
 ****************************************************************************/
-uint32 _spoolss_enumprintprocessors(const UNISTR2 *name,
-                               const UNISTR2 *environment,
-                               uint32 level,
-                               PRINTPROCESSOR_1 **info_1,
-                               uint32 *offered,
-                               uint32 *numofprintprocessors)
+static uint32 enumprintprocessors_level_1(NEW_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+{
+       PRINTPROCESSOR_1 *info_1=NULL;
+       
+       info_1 = (PRINTPROCESSOR_1 *)malloc(sizeof(PRINTPROCESSOR_1));
+       (*returned) = 0x1;
+       
+       init_unistr(&(info_1->name), "winprint");
+
+       *needed += spoolss_size_printprocessor_info_1(info_1);
+
+       if (!alloc_buffer_size(buffer, *needed))
+               return ERROR_INSUFFICIENT_BUFFER;
+
+       smb_io_printprocessor_info_1("", buffer, info_1, 0);
+
+       safe_free(info_1);
+
+       if (*needed > offered) {
+               *returned=0;
+               return ERROR_INSUFFICIENT_BUFFER;
+       }
+       else
+               return NT_STATUS_NO_PROBLEMO;
+}
+
+/****************************************************************************
+****************************************************************************/
+uint32 _spoolss_enumprintprocessors(UNISTR2 *name, UNISTR2 *environment, uint32 level,
+                                   NEW_BUFFER *buffer, uint32 offered, 
+                                   uint32 *needed, uint32 *returned)
 {
        DEBUG(5,("spoolss_enumprintprocessors\n"));
 
@@ -3307,26 +3942,134 @@ uint32 _spoolss_enumprintprocessors(const UNISTR2 *name,
         * and I can use my nice printer checker.
         */
        
-       (*numofprintprocessors) = 0x1;
-       (*info_1) = (PRINTPROCESSOR_1 *)malloc(sizeof(PRINTPROCESSOR_1));
+       *returned=0;
+       *needed=0;
        
-       if ((*info_1) == NULL)
-       {
-               return NT_STATUS_NO_MEMORY;
+       switch (level) {
+       case 1:
+               return enumprintprocessors_level_1(buffer, offered, needed, returned);
+               break;
+       default:
+               return NT_STATUS_INVALID_INFO_CLASS;
+               break;
        }
+}
+
+/****************************************************************************
+ enumprintprocdatatypes level 1.
+****************************************************************************/
+static uint32 enumprintprocdatatypes_level_1(NEW_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+{
+       PRINTPROCDATATYPE_1 *info_1=NULL;
+       
+       info_1 = (PRINTPROCDATATYPE_1 *)malloc(sizeof(PRINTPROCDATATYPE_1));
+       (*returned) = 0x1;
+       
+       init_unistr(&(info_1->name), "RAW");
 
-       init_unistr(&((*info_1)->name), "winprint");
+       *needed += spoolss_size_printprocdatatype_info_1(info_1);
 
-       return 0x0;
+       if (!alloc_buffer_size(buffer, *needed))
+               return ERROR_INSUFFICIENT_BUFFER;
+
+       smb_io_printprocdatatype_info_1("", buffer, info_1, 0);
+
+       safe_free(info_1);
+
+       if (*needed > offered) {
+               *returned=0;
+               return ERROR_INSUFFICIENT_BUFFER;
+       }
+       else
+               return NT_STATUS_NO_PROBLEMO;
 }
 
 /****************************************************************************
 ****************************************************************************/
-uint32 _spoolss_enumprintmonitors( const UNISTR2 *name,
-                               uint32 level,
-                               PRINTMONITOR_1 **info_1,
-                               uint32 *offered,
-                               uint32 *numofprintmonitors)
+uint32 _spoolss_enumprintprocdatatypes(UNISTR2 *name, UNISTR2 *processor, uint32 level,
+                                       NEW_BUFFER *buffer, uint32 offered, 
+                                       uint32 *needed, uint32 *returned)
+{
+       DEBUG(5,("_spoolss_enumprintprocdatatypes\n"));
+       
+       *returned=0;
+       *needed=0;
+       
+       switch (level) {
+       case 1:
+               return enumprintprocdatatypes_level_1(buffer, offered, needed, returned);
+               break;
+       default:
+               return NT_STATUS_INVALID_INFO_CLASS;
+               break;
+       }
+}
+
+/****************************************************************************
+ enumprintmonitors level 1.
+****************************************************************************/
+static uint32 enumprintmonitors_level_1(NEW_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+{
+       PRINTMONITOR_1 *info_1=NULL;
+       
+       info_1 = (PRINTMONITOR_1 *)malloc(sizeof(PRINTMONITOR_1));
+       (*returned) = 0x1;
+       
+       init_unistr(&(info_1->name), "Local Port");
+
+       *needed += spoolss_size_printmonitor_info_1(info_1);
+
+       if (!alloc_buffer_size(buffer, *needed))
+               return ERROR_INSUFFICIENT_BUFFER;
+
+       smb_io_printmonitor_info_1("", buffer, info_1, 0);
+
+       safe_free(info_1);
+
+       if (*needed > offered) {
+               *returned=0;
+               return ERROR_INSUFFICIENT_BUFFER;
+       }
+       else
+               return NT_STATUS_NO_PROBLEMO;
+}
+
+/****************************************************************************
+ enumprintmonitors level 2.
+****************************************************************************/
+static uint32 enumprintmonitors_level_2(NEW_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+{
+       PRINTMONITOR_2 *info_2=NULL;
+       
+       info_2 = (PRINTMONITOR_2 *)malloc(sizeof(PRINTMONITOR_2));
+       (*returned) = 0x1;
+       
+       init_unistr(&(info_2->name), "Local Port");
+       init_unistr(&(info_2->environment), "Windows NT X86");
+       init_unistr(&(info_2->dll_name), "localmon.dll");
+
+       *needed += spoolss_size_printmonitor_info_2(info_2);
+
+       if (!alloc_buffer_size(buffer, *needed))
+               return ERROR_INSUFFICIENT_BUFFER;
+
+       smb_io_printmonitor_info_2("", buffer, info_2, 0);
+
+       safe_free(info_2);
+
+       if (*needed > offered) {
+               *returned=0;
+               return ERROR_INSUFFICIENT_BUFFER;
+       }
+       else
+               return NT_STATUS_NO_PROBLEMO;
+}
+
+/****************************************************************************
+****************************************************************************/
+uint32 _spoolss_enumprintmonitors(UNISTR2 *name,uint32 level,
+                                   NEW_BUFFER *buffer, uint32 offered, 
+                                   uint32 *needed, uint32 *returned)
 {
        DEBUG(5,("spoolss_enumprintmonitors\n"));
 
@@ -3337,98 +4080,148 @@ uint32 _spoolss_enumprintmonitors( const UNISTR2 *name,
         * and I can use my nice printer checker.
         */
        
-       (*numofprintmonitors) = 0x1;
-       (*info_1) = (PRINTMONITOR_1 *)malloc(sizeof(PRINTMONITOR_1));
-       if ((*info_1) == NULL)
-       {
+       *returned=0;
+       *needed=0;
+       
+       switch (level) {
+       case 1:
+               return enumprintmonitors_level_1(buffer, offered, needed, returned);
+               break;          
+       case 2:
+               return enumprintmonitors_level_2(buffer, offered, needed, returned);
+               break;
+       default:
+               return NT_STATUS_INVALID_INFO_CLASS;
+               break;
+       }
+}
+
+/****************************************************************************
+****************************************************************************/
+static uint32 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;
+       JOB_INFO_1 *info_1=NULL;
+       info_1=(JOB_INFO_1 *)malloc(sizeof(JOB_INFO_1));
+
+       if (info_1 == NULL) {
+               safe_free(queue);
                return NT_STATUS_NO_MEMORY;
        }
+               
+       for (i=0; i<count && found==False; i++) {
+               if (queue[i].job==(int)jobid)
+                       found=True;
+       }
+       
+       if (found==False) {
+               safe_free(queue);
+               /* I shoud reply something else ... I can't find the good one */
+               return NT_STATUS_NO_PROBLEMO;
+       }
        
-       init_unistr(&((*info_1)->name), "Local Port");
+       fill_job_info_1(info_1, &(queue[i]), i, snum);
+       
+       *needed += spoolss_size_job_info_1(info_1);
 
-       return 0x0;
+       if (!alloc_buffer_size(buffer, *needed))
+               return ERROR_INSUFFICIENT_BUFFER;
+
+       new_smb_io_job_info_1("", buffer, info_1, 0);
+
+       safe_free(info_1);
+
+       if (*needed > offered)
+               return ERROR_INSUFFICIENT_BUFFER;
+       else
+               return NT_STATUS_NO_PROBLEMO;
 }
 
+
 /****************************************************************************
 ****************************************************************************/
-uint32 _spoolss_getjob( const POLICY_HND *handle,
-                               uint32 jobid,
-                               uint32 level,
-                               PJOB_INFO *ctr,
-                               uint32 *offered)
+#if 0
+... Not yet used...
+static uint32 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;
+       JOB_INFO_2 *info_2=NULL;
+       info_2=(JOB_INFO_2 *)malloc(sizeof(JOB_INFO_2));
+
+       if (info_2 == NULL) {
+               safe_free(queue);
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       for (i=0; i<count && found==False; i++) {
+               if (queue[i].job==(int)jobid)
+                       found=True;
+       }
+       
+       if (found==False) {
+               safe_free(queue);
+               /* I shoud reply something else ... I can't find the good one */
+               return NT_STATUS_NO_PROBLEMO;
+       }
+       
+       fill_job_info_2(info_2, &(queue[i]), i, snum);
+       
+       *needed += spoolss_size_job_info_2(info_2);
+
+       if (!alloc_buffer_size(buffer, *needed))
+               return ERROR_INSUFFICIENT_BUFFER;
+
+       new_smb_io_job_info_2("", buffer, info_2, 0);
+
+       safe_free(info_2);
+
+       if (*needed > offered)
+               return ERROR_INSUFFICIENT_BUFFER;
+       else
+               return NT_STATUS_NO_PROBLEMO;
+}
+#endif
+
+/****************************************************************************
+****************************************************************************/
+uint32 _spoolss_getjob( POLICY_HND *handle, uint32 jobid, uint32 level,
+                       NEW_BUFFER *buffer, uint32 offered, 
+                       uint32 *needed)
 {
        int snum;
        int count;
-       int i;
        print_queue_struct *queue=NULL;
        print_status_struct prt_status;
 
-       DEBUG(4,("spoolss_getjob\n"));
+       DEBUG(5,("spoolss_getjob\n"));
        
-       bzero(&prt_status,sizeof(prt_status));
+       memset(&prt_status, 0, sizeof(prt_status));
 
+       *needed=0;
+       
        if (!get_printer_snum(handle, &snum))
        {
                return NT_STATUS_INVALID_HANDLE;
        }
+       
        count=get_printqueue(snum, NULL, &queue, &prt_status);
        
        DEBUGADD(4,("count:[%d], prt_status:[%d], [%s]\n",
                     count, prt_status.status, prt_status.message));
-       
-       switch (level)
-       {
-               case 1:
-               {
-                       JOB_INFO_1 *job_info_1=NULL;
-                       job_info_1=(JOB_INFO_1 *)malloc(sizeof(JOB_INFO_1));
-
-                       if (job_info_1 == NULL)
-                       {
-                               safe_free(queue);
-                               return NT_STATUS_NO_MEMORY;
-                       }
-
-                       for (i=0; i<count; i++)
-                       {
-                               if (queue[i].job==(int)jobid)
-                               {
-                                       fill_job_info_1(job_info_1,
-                                                      &(queue[i]), i, snum);
-                               }
-                       }
-                       ctr->job.job_info_1=job_info_1;
-                       break;
-               }
-               case 2:
-               {
-                       JOB_INFO_2 *job_info_2=NULL;
-                       job_info_2=(JOB_INFO_2 *)malloc(sizeof(JOB_INFO_2));
-
-                       if (job_info_2 == NULL)
-                       {
-                               safe_free(queue);
-                               return NT_STATUS_NO_MEMORY;
-                       }
-
-                       for (i=0; i<count; i++)
-                       {
-                               if (queue[i].job==(int)jobid)
-                               {
-                                       fill_job_info_2(job_info_2,
-                                                       &(queue[i]), i, snum);
-                               }
-                       }
-                       ctr->job.job_info_2=job_info_2;
-                       break;
-               }
-               default:
-               {
-                       safe_free(queue);
-                       return NT_STATUS_INVALID_INFO_CLASS;
-               }
+               
+       switch (level) {
+       case 1:
+               return getjob_level_1(queue, count, snum, jobid, buffer, offered, needed);
+               break;
+       case 2:
+               return getjob_level_1(queue, count, snum, jobid, buffer, offered, needed);
+               break;
+       default:
+               safe_free(queue);
+               return NT_STATUS_INVALID_INFO_CLASS;
+               break;
        }
-
-       safe_free(queue);
-       return 0x0;
 }
+