s3-spoolss: use pidl for _spoolss_EnumPrinterKey.
[ira/wip.git] / source3 / rpc_server / srv_spoolss_nt.c
index 8f43793a5371a9c6a17ccb4661aa13f96f919097..84064a308f4c607c0d028b4bd4ad61a973cccbb9 100644 (file)
 
 #include "includes.h"
 
+/* macros stolen from s4 spoolss server */
+#define SPOOLSS_BUFFER_UNION(fn,ic,info,level) \
+       ((info)?ndr_size_##fn(info, level, ic, 0):0)
+
+#define SPOOLSS_BUFFER_UNION_ARRAY(mem_ctx,fn,ic,info,level,count) \
+       ((info)?ndr_size_##fn##_info(mem_ctx, ic, level, count, info):0)
+
+#define SPOOLSS_BUFFER_OK(val_true,val_false) ((r->in.offered >= *r->out.needed)?val_true:val_false)
+
+
 extern userdom_struct current_user_info;
 
 #undef DBGC_CLASS
@@ -69,7 +79,7 @@ extern struct standard_mapping printer_std_mapping, printserver_std_mapping;
 
 struct xcv_api_table {
        const char *name;
-       WERROR(*fn) (NT_USER_TOKEN *token, RPC_BUFFER *in, RPC_BUFFER *out, uint32 *needed);
+       WERROR(*fn) (TALLOC_CTX *mem_ctx, NT_USER_TOKEN *token, DATA_BLOB *in, DATA_BLOB *out, uint32_t *needed);
 };
 
 /********************************************************************
@@ -110,7 +120,7 @@ static int nt_printj_status(int v)
        case LPQ_DELETED:
                return JOB_STATUS_DELETED;
        case LPQ_BLOCKED:
-               return JOB_STATUS_BLOCKED;
+               return JOB_STATUS_BLOCKED_DEVQ;
        case LPQ_USER_INTERVENTION:
                return JOB_STATUS_USER_INTERVENTION;
        }
@@ -130,19 +140,6 @@ static int nt_printq_status(int v)
        return 0;
 }
 
-/****************************************************************************
- Functions to handle SPOOL_NOTIFY_OPTION struct stored in Printer_entry.
-****************************************************************************/
-
-static void free_spool_notify_option(SPOOL_NOTIFY_OPTION **pp)
-{
-       if (*pp == NULL)
-               return;
-
-       SAFE_FREE((*pp)->ctr.type);
-       SAFE_FREE(*pp);
-}
-
 /***************************************************************************
  Disconnect from the client
 ****************************************************************************/
@@ -215,8 +212,7 @@ static int printer_entry_destructor(Printer_entry *Printer)
        Printer->notify.options=0;
        Printer->notify.localmachine[0]='\0';
        Printer->notify.printerlocal=0;
-       free_spool_notify_option(&Printer->notify.option);
-       Printer->notify.option=NULL;
+       TALLOC_FREE(Printer->notify.option);
        Printer->notify.client_connected=False;
 
        free_nt_devicemode( &Printer->nt_devmode );
@@ -227,35 +223,6 @@ static int printer_entry_destructor(Printer_entry *Printer)
        return 0;
 }
 
-/****************************************************************************
- Functions to duplicate a SPOOL_NOTIFY_OPTION struct stored in Printer_entry.
-****************************************************************************/
-
-static SPOOL_NOTIFY_OPTION *dup_spool_notify_option(SPOOL_NOTIFY_OPTION *sp)
-{
-       SPOOL_NOTIFY_OPTION *new_sp = NULL;
-
-       if (!sp)
-               return NULL;
-
-       new_sp = SMB_MALLOC_P(SPOOL_NOTIFY_OPTION);
-       if (!new_sp)
-               return NULL;
-
-       *new_sp = *sp;
-
-       if (sp->ctr.count) {
-               new_sp->ctr.type = (SPOOL_NOTIFY_OPTION_TYPE *)memdup(sp->ctr.type, sizeof(SPOOL_NOTIFY_OPTION_TYPE) * sp->ctr.count);
-
-               if (!new_sp->ctr.type) {
-                       SAFE_FREE(new_sp);
-                       return NULL;
-               }
-       }
-
-       return new_sp;
-}
-
 /****************************************************************************
   find printer index by handle
 ****************************************************************************/
@@ -633,7 +600,7 @@ static bool is_monitoring_event_flags(uint32 flags, uint16 notify_type,
 static bool is_monitoring_event(Printer_entry *p, uint16 notify_type,
                                uint16 notify_field)
 {
-       SPOOL_NOTIFY_OPTION *option = p->notify.option;
+       struct spoolss_NotifyOption *option = p->notify.option;
        uint32 i, j;
 
        /*
@@ -655,13 +622,13 @@ static bool is_monitoring_event(Printer_entry *p, uint16 notify_type,
 
                /* Check match for notify_type */
 
-               if (option->ctr.type[i].type != notify_type)
+               if (option->types[i].type != notify_type)
                        continue;
 
                /* Check match for field */
 
-               for (j = 0; j < option->ctr.type[i].count; j++) {
-                       if (option->ctr.type[i].fields[j] == notify_field) {
+               for (j = 0; j < option->types[i].count; j++) {
+                       if (option->types[i].fields[j] == notify_field) {
                                return True;
                        }
                }
@@ -673,43 +640,93 @@ static bool is_monitoring_event(Printer_entry *p, uint16 notify_type,
        return False;
 }
 
-/* Convert a notification message to a SPOOL_NOTIFY_INFO_DATA struct */
+#define SETUP_SPOOLSS_NOTIFY_DATA_INTEGER(_data, _integer) \
+       _data->data.integer[0] = _integer; \
+       _data->data.integer[1] = 0;
+
+
+#define SETUP_SPOOLSS_NOTIFY_DATA_STRING(_data, _p) \
+       _data->data.string.string = talloc_strdup(mem_ctx, _p); \
+       if (!_data->data.string.string) {\
+               _data->data.string.size = 0; \
+       } \
+       _data->data.string.size = strlen_m_term(_p) * 2;
+
+#define SETUP_SPOOLSS_NOTIFY_DATA_DEVMODE(_data, _devmode) \
+       _data->data.devmode.devmode = _devmode;
+
+#define SETUP_SPOOLSS_NOTIFY_DATA_SECDESC(_data, _size, _sd) \
+       _data->data.sd.sd = dup_sec_desc(mem_ctx, _sd); \
+       if (!_data->data.sd.sd) { \
+               _data->data.sd.sd_size = 0; \
+       } \
+       _data->data.sd.sd_size = _size;
+
+static void init_systemtime_buffer(TALLOC_CTX *mem_ctx,
+                                  struct tm *t,
+                                  const char **pp,
+                                  uint32_t *plen)
+{
+       struct spoolss_Time st;
+       uint32_t len = 16;
+       char *p;
+
+       if (!init_systemtime(&st, t)) {
+               return;
+       }
+
+       p = talloc_array(mem_ctx, char, len);
+       if (!p) {
+               return;
+       }
+
+       /*
+        * Systemtime must be linearized as a set of UINT16's.
+        * Fix from Benjamin (Bj) Kuit bj@it.uts.edu.au
+        */
+
+       SSVAL(p, 0, st.year);
+       SSVAL(p, 2, st.month);
+       SSVAL(p, 4, st.day_of_week);
+       SSVAL(p, 6, st.day);
+       SSVAL(p, 8, st.hour);
+       SSVAL(p, 10, st.minute);
+       SSVAL(p, 12, st.second);
+       SSVAL(p, 14, st.millisecond);
+
+       *pp = p;
+       *plen = len;
+}
+
+/* Convert a notification message to a struct spoolss_Notify */
 
 static void notify_one_value(struct spoolss_notify_msg *msg,
-                            SPOOL_NOTIFY_INFO_DATA *data,
+                            struct spoolss_Notify *data,
                             TALLOC_CTX *mem_ctx)
 {
-       data->notify_data.value[0] = msg->notify.value[0];
-       data->notify_data.value[1] = 0;
+       SETUP_SPOOLSS_NOTIFY_DATA_INTEGER(data, msg->notify.value[0]);
 }
 
 static void notify_string(struct spoolss_notify_msg *msg,
-                         SPOOL_NOTIFY_INFO_DATA *data,
+                         struct spoolss_Notify *data,
                          TALLOC_CTX *mem_ctx)
 {
-       UNISTR2 unistr;
-
        /* The length of the message includes the trailing \0 */
 
-       init_unistr2(&unistr, msg->notify.data, UNI_STR_TERMINATE);
-
-       data->notify_data.data.length = msg->len * 2;
-       data->notify_data.data.string = TALLOC_ARRAY(mem_ctx, uint16, msg->len);
-
-       if (!data->notify_data.data.string) {
-               data->notify_data.data.length = 0;
+       data->data.string.size = msg->len * 2;
+       data->data.string.string = talloc_strdup(mem_ctx, msg->notify.data);
+       if (!data->data.string.string) {
+               data->data.string.size = 0;
                return;
        }
-
-       memcpy(data->notify_data.data.string, unistr.buffer, msg->len * 2);
 }
 
 static void notify_system_time(struct spoolss_notify_msg *msg,
-                              SPOOL_NOTIFY_INFO_DATA *data,
+                              struct spoolss_Notify *data,
                               TALLOC_CTX *mem_ctx)
 {
-       SYSTEMTIME systime;
-       prs_struct ps;
+       data->data.string.string = NULL;
+       data->data.string.size = 0;
 
        if (msg->len != sizeof(time_t)) {
                DEBUG(5, ("notify_system_time: received wrong sized message (%d)\n",
@@ -717,42 +734,15 @@ static void notify_system_time(struct spoolss_notify_msg *msg,
                return;
        }
 
-       if (!prs_init(&ps, RPC_MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL)) {
-               DEBUG(5, ("notify_system_time: prs_init() failed\n"));
-               return;
-       }
-
-       if (!make_systemtime(&systime, gmtime((time_t *)msg->notify.data))) {
-               DEBUG(5, ("notify_system_time: unable to make systemtime\n"));
-               prs_mem_free(&ps);
-               return;
-       }
-
-       if (!spoolss_io_system_time("", &ps, 0, &systime)) {
-               prs_mem_free(&ps);
-               return;
-       }
-
-       data->notify_data.data.length = prs_offset(&ps);
-       if (prs_offset(&ps)) {
-               data->notify_data.data.string = (uint16 *)
-                       TALLOC(mem_ctx, prs_offset(&ps));
-               if (!data->notify_data.data.string) {
-                       prs_mem_free(&ps);
-                       return;
-               }
-               prs_copy_all_data_out((char *)data->notify_data.data.string, &ps);
-       } else {
-               data->notify_data.data.string = NULL;
-       }
-
-       prs_mem_free(&ps);
+       init_systemtime_buffer(mem_ctx, gmtime((time_t *)msg->notify.data),
+                              &data->data.string.string,
+                              &data->data.string.size);
 }
 
 struct notify2_message_table {
        const char *name;
        void (*fn)(struct spoolss_notify_msg *msg,
-                  SPOOL_NOTIFY_INFO_DATA *data, TALLOC_CTX *mem_ctx);
+                  struct spoolss_Notify *data, TALLOC_CTX *mem_ctx);
 };
 
 static struct notify2_message_table printer_notify_table[] = {
@@ -966,9 +956,9 @@ static void send_notify2_changes( SPOOLSS_NOTIFY_MSG_CTR *ctr, uint32 idx )
        /* loop over all printers */
 
        for (p = printers_list; p; p = p->next) {
-               SPOOL_NOTIFY_INFO_DATA *data;
-               uint32  data_len = 0;
-               uint32  id;
+               struct spoolss_Notify *notifies;
+               uint32_t count = 0;
+               uint32_t id;
                int     i;
 
                /* Is there notification on this handle? */
@@ -989,13 +979,11 @@ static void send_notify2_changes( SPOOLSS_NOTIFY_MSG_CTR *ctr, uint32 idx )
 
                /* allocate the max entries possible */
 
-               data = TALLOC_ARRAY( mem_ctx, SPOOL_NOTIFY_INFO_DATA, msg_group->num_msgs);
-               if (!data) {
+               notifies = TALLOC_ZERO_ARRAY(mem_ctx, struct spoolss_Notify, msg_group->num_msgs);
+               if (!notifies) {
                        return;
                }
 
-               ZERO_STRUCTP(data);
-
                /* build the array of change notifications */
 
                sending_msg_count = 0;
@@ -1044,17 +1032,17 @@ static void send_notify2_changes( SPOOLSS_NOTIFY_MSG_CTR *ctr, uint32 idx )
                                }
                        }
 
-                       construct_info_data( &data[data_len], msg->type, msg->field, id );
+                       construct_info_data( &notifies[count], msg->type, msg->field, id );
 
                        switch(msg->type) {
                        case PRINTER_NOTIFY_TYPE:
                                if ( printer_notify_table[msg->field].fn )
-                                       printer_notify_table[msg->field].fn(msg, &data[data_len], mem_ctx);
+                                       printer_notify_table[msg->field].fn(msg, &notifies[count], mem_ctx);
                                break;
 
                        case JOB_NOTIFY_TYPE:
                                if ( job_notify_table[msg->field].fn )
-                                       job_notify_table[msg->field].fn(msg, &data[data_len], mem_ctx);
+                                       job_notify_table[msg->field].fn(msg, &notifies[count], mem_ctx);
                                break;
 
                        default:
@@ -1062,12 +1050,46 @@ static void send_notify2_changes( SPOOLSS_NOTIFY_MSG_CTR *ctr, uint32 idx )
                                goto done;
                        }
 
-                       data_len++;
+                       count++;
                }
 
                if ( sending_msg_count ) {
-                       rpccli_spoolss_rrpcn( notify_cli_pipe, mem_ctx, &p->notify.client_hnd,
-                                       data_len, data, p->notify.change, 0 );
+                       NTSTATUS status;
+                       WERROR werr;
+                       union spoolss_ReplyPrinterInfo info;
+                       struct spoolss_NotifyInfo info0;
+                       uint32_t reply_result;
+
+                       info0.version   = 0x2;
+                       info0.flags     = count ? 0x00020000 /* ??? */ : PRINTER_NOTIFY_INFO_DISCARDED;
+                       info0.count     = count;
+                       info0.notifies  = notifies;
+
+                       info.info0 = &info0;
+
+                       status = rpccli_spoolss_RouterReplyPrinterEx(notify_cli_pipe, mem_ctx,
+                                                                    &p->notify.client_hnd,
+                                                                    p->notify.change, /* color */
+                                                                    p->notify.flags,
+                                                                    &reply_result,
+                                                                    0, /* reply_type, must be 0 */
+                                                                    info,
+                                                                    &werr);
+                       if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(werr)) {
+                               DEBUG(1,("RouterReplyPrinterEx to client: %s failed: %s\n",
+                                       notify_cli_pipe->srv_name_slash,
+                                       win_errstr(werr)));
+                       }
+                       switch (reply_result) {
+                               case 0:
+                                       break;
+                               case PRINTER_NOTIFY_INFO_DISCARDED:
+                               case PRINTER_NOTIFY_INFO_DISCARDNOTED:
+                               case PRINTER_NOTIFY_INFO_COLOR_MISMATCH:
+                                       break;
+                               default:
+                                       break;
+                       }
                }
        }
 
@@ -1399,153 +1421,37 @@ void reset_all_printerdata(struct messaging_context *msg,
        return;
 }
 
-/********************************************************************
- Copy routines used by convert_to_openprinterex()
- *******************************************************************/
-
-static DEVICEMODE* dup_devicemode(TALLOC_CTX *ctx, DEVICEMODE *devmode)
-{
-       DEVICEMODE *d;
-       int len;
-
-       if (!devmode)
-               return NULL;
-
-       DEBUG (8,("dup_devmode\n"));
-
-       /* bulk copy first */
-
-       d = (DEVICEMODE *)TALLOC_MEMDUP(ctx, devmode, sizeof(DEVICEMODE));
-       if (!d)
-               return NULL;
-
-       /* dup the pointer members separately */
-
-       len = unistrlen(devmode->devicename.buffer);
-       if (len != -1) {
-               d->devicename.buffer = TALLOC_ARRAY(ctx, uint16, len);
-               if (!d->devicename.buffer) {
-                       return NULL;
-               }
-               if (unistrcpy(d->devicename.buffer, devmode->devicename.buffer) != len)
-                       return NULL;
-       }
-
-
-       len = unistrlen(devmode->formname.buffer);
-       if (len != -1) {
-               d->formname.buffer = TALLOC_ARRAY(ctx, uint16, len);
-               if (!d->formname.buffer) {
-                       return NULL;
-               }
-               if (unistrcpy(d->formname.buffer, devmode->formname.buffer) != len)
-                       return NULL;
-       }
-
-       if (devmode->driverextra) {
-               d->dev_private = (uint8 *)TALLOC_MEMDUP(ctx, devmode->dev_private,
-                                               devmode->driverextra);
-               if (!d->dev_private) {
-                       return NULL;
-               }
-       } else {
-               d->dev_private = NULL;
-       }
-       return d;
-}
-
-static void copy_devmode_ctr(TALLOC_CTX *ctx, DEVMODE_CTR *new_ctr, DEVMODE_CTR *ctr)
-{
-       if (!new_ctr || !ctr)
-               return;
-
-       DEBUG(8,("copy_devmode_ctr\n"));
-
-       new_ctr->size = ctr->size;
-       new_ctr->devmode_ptr = ctr->devmode_ptr;
-
-       if(ctr->devmode_ptr)
-               new_ctr->devmode = dup_devicemode(ctx, ctr->devmode);
-}
-
-static void copy_printer_default(TALLOC_CTX *ctx, PRINTER_DEFAULT *new_def, PRINTER_DEFAULT *def)
-{
-       if (!new_def || !def)
-               return;
-
-       DEBUG(8,("copy_printer_defaults\n"));
-
-       new_def->datatype_ptr = def->datatype_ptr;
-
-       if (def->datatype_ptr)
-               copy_unistr2(&new_def->datatype, &def->datatype);
-
-       copy_devmode_ctr(ctx, &new_def->devmode_cont, &def->devmode_cont);
-
-       new_def->access_required = def->access_required;
-}
-
-/********************************************************************
- * Convert a SPOOL_Q_OPEN_PRINTER structure to a
- * SPOOL_Q_OPEN_PRINTER_EX structure
- ********************************************************************/
-
-static WERROR convert_to_openprinterex(TALLOC_CTX *ctx, SPOOL_Q_OPEN_PRINTER_EX *q_u_ex, SPOOL_Q_OPEN_PRINTER *q_u)
-{
-       if (!q_u_ex || !q_u)
-               return WERR_OK;
-
-       DEBUG(8,("convert_to_openprinterex\n"));
-
-       if ( q_u->printername ) {
-               q_u_ex->printername = TALLOC_ZERO_P( ctx, UNISTR2 );
-               if (q_u_ex->printername == NULL)
-                       return WERR_NOMEM;
-               copy_unistr2(q_u_ex->printername, q_u->printername);
-       }
-
-       copy_printer_default(ctx, &q_u_ex->printer_default, &q_u->printer_default);
-
-       return WERR_OK;
-}
-
-/********************************************************************
- * spoolss_open_printer
- *
- * called from the spoolss dispatcher
- ********************************************************************/
+/****************************************************************
+ _spoolss_OpenPrinter
+****************************************************************/
 
-WERROR _spoolss_open_printer(pipes_struct *p, SPOOL_Q_OPEN_PRINTER *q_u, SPOOL_R_OPEN_PRINTER *r_u)
+WERROR _spoolss_OpenPrinter(pipes_struct *p,
+                           struct spoolss_OpenPrinter *r)
 {
-       SPOOL_Q_OPEN_PRINTER_EX q_u_ex;
-       SPOOL_R_OPEN_PRINTER_EX r_u_ex;
-
-       if (!q_u || !r_u)
-               return WERR_NOMEM;
-
-       ZERO_STRUCT(q_u_ex);
-       ZERO_STRUCT(r_u_ex);
+       struct spoolss_OpenPrinterEx e;
+       WERROR werr;
 
-       /* convert the OpenPrinter() call to OpenPrinterEx() */
+       ZERO_STRUCT(e.in.userlevel);
 
-       r_u_ex.status = convert_to_openprinterex(p->mem_ctx, &q_u_ex, q_u);
-       if (!W_ERROR_IS_OK(r_u_ex.status))
-               return r_u_ex.status;
+       e.in.printername        = r->in.printername;
+       e.in.datatype           = r->in.datatype;
+       e.in.devmode_ctr        = r->in.devmode_ctr;
+       e.in.access_mask        = r->in.access_mask;
+       e.in.level              = 0;
 
-       r_u_ex.status = _spoolss_open_printer_ex(p, &q_u_ex, &r_u_ex);
+       e.out.handle            = r->out.handle;
 
-       /* convert back to OpenPrinter() */
+       werr = _spoolss_OpenPrinterEx(p, &e);
 
-       memcpy(r_u, &r_u_ex, sizeof(*r_u));
-
-       if (W_ERROR_EQUAL(r_u->status, WERR_INVALID_PARAM)) {
+       if (W_ERROR_EQUAL(werr, WERR_INVALID_PARAM)) {
                /* OpenPrinterEx returns this for a bad
                 * printer name. We must return WERR_INVALID_PRINTER_NAME
                 * instead.
                 */
-               r_u->status = WERR_INVALID_PRINTER_NAME;
+               werr = WERR_INVALID_PRINTER_NAME;
        }
-       return r_u->status;
+
+       return werr;
 }
 
 /********************************************************************
@@ -1645,6 +1551,7 @@ WERROR _spoolss_OpenPrinterEx(pipes_struct *p,
        DEBUGADD(3,("checking name: %s\n",name));
 
        if (!open_printer_hnd(p, handle, name, 0)) {
+               ZERO_STRUCTP(r->out.handle);
                return WERR_INVALID_PARAM;
        }
 
@@ -1653,6 +1560,7 @@ WERROR _spoolss_OpenPrinterEx(pipes_struct *p,
                DEBUG(0,("_spoolss_OpenPrinterEx: logic error.  Can't find printer "
                        "handle we created for printer %s\n", name ));
                close_printer_handle(p,handle);
+               ZERO_STRUCTP(r->out.handle);
                return WERR_INVALID_PARAM;
        }
 
@@ -1703,6 +1611,7 @@ WERROR _spoolss_OpenPrinterEx(pipes_struct *p,
                    ~(SERVER_ACCESS_ADMINISTER | SERVER_ACCESS_ENUMERATE)) {
                        DEBUG(3, ("access DENIED for non-printserver bits\n"));
                        close_printer_handle(p, handle);
+                       ZERO_STRUCTP(r->out.handle);
                        return WERR_ACCESS_DENIED;
                }
 
@@ -1714,6 +1623,7 @@ WERROR _spoolss_OpenPrinterEx(pipes_struct *p,
 
                        if (!lp_ms_add_printer_wizard()) {
                                close_printer_handle(p, handle);
+                               ZERO_STRUCTP(r->out.handle);
                                return WERR_ACCESS_DENIED;
                        }
 
@@ -1729,6 +1639,7 @@ WERROR _spoolss_OpenPrinterEx(pipes_struct *p,
                                    p->server_info->ptok,
                                    lp_printer_admin(snum))) {
                                close_printer_handle(p, handle);
+                               ZERO_STRUCTP(r->out.handle);
                                return WERR_ACCESS_DENIED;
                        }
 
@@ -1751,6 +1662,7 @@ WERROR _spoolss_OpenPrinterEx(pipes_struct *p,
 
                if (!get_printer_snum(p, handle, &snum, NULL)) {
                        close_printer_handle(p, handle);
+                       ZERO_STRUCTP(r->out.handle);
                        return WERR_BADFID;
                }
 
@@ -1776,6 +1688,7 @@ WERROR _spoolss_OpenPrinterEx(pipes_struct *p,
 
                if ( !check_access(get_client_fd(), lp_hostsallow(snum), lp_hostsdeny(snum)) ) {
                        DEBUG(3, ("access DENIED (hosts allow/deny) for printer open\n"));
+                       ZERO_STRUCTP(r->out.handle);
                        return WERR_ACCESS_DENIED;
                }
 
@@ -1785,12 +1698,14 @@ WERROR _spoolss_OpenPrinterEx(pipes_struct *p,
                                        r->in.access_mask)) {
                        DEBUG(3, ("access DENIED for printer open\n"));
                        close_printer_handle(p, handle);
+                       ZERO_STRUCTP(r->out.handle);
                        return WERR_ACCESS_DENIED;
                }
 
                if ((r->in.access_mask & SPECIFIC_RIGHTS_MASK)& ~(PRINTER_ACCESS_ADMINISTER|PRINTER_ACCESS_USE)) {
                        DEBUG(3, ("access DENIED for printer open - unknown bits\n"));
                        close_printer_handle(p, handle);
+                       ZERO_STRUCTP(r->out.handle);
                        return WERR_ACCESS_DENIED;
                }
 
@@ -1806,6 +1721,7 @@ WERROR _spoolss_OpenPrinterEx(pipes_struct *p,
 
        default:
                /* sanity check to prevent programmer error */
+               ZERO_STRUCTP(r->out.handle);
                return WERR_BADFID;
        }
 
@@ -1842,55 +1758,239 @@ WERROR _spoolss_OpenPrinterEx(pipes_struct *p,
 /****************************************************************************
 ****************************************************************************/
 
-static bool convert_printer_info(const SPOOL_PRINTER_INFO_LEVEL *uni,
-                               NT_PRINTER_INFO_LEVEL *printer, uint32 level)
+static bool printer_info2_to_nt_printer_info2(struct spoolss_SetPrinterInfo2 *r,
+                                             NT_PRINTER_INFO_LEVEL_2 *d)
+{
+       DEBUG(7,("printer_info2_to_nt_printer_info2\n"));
+
+       if (!r || !d) {
+               return false;
+       }
+
+       d->attributes           = r->attributes;
+       d->priority             = r->priority;
+       d->default_priority     = r->defaultpriority;
+       d->starttime            = r->starttime;
+       d->untiltime            = r->untiltime;
+       d->status               = r->status;
+       d->cjobs                = r->cjobs;
+
+       fstrcpy(d->servername,  r->servername);
+       fstrcpy(d->printername, r->printername);
+       fstrcpy(d->sharename,   r->sharename);
+       fstrcpy(d->portname,    r->portname);
+       fstrcpy(d->drivername,  r->drivername);
+       slprintf(d->comment, sizeof(d->comment)-1, "%s", r->comment);
+       fstrcpy(d->location,    r->location);
+       fstrcpy(d->sepfile,     r->sepfile);
+       fstrcpy(d->printprocessor, r->printprocessor);
+       fstrcpy(d->datatype,    r->datatype);
+       fstrcpy(d->parameters,  r->parameters);
+
+       return true;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static bool convert_printer_info_new(struct spoolss_SetPrinterInfoCtr *info_ctr,
+                                    NT_PRINTER_INFO_LEVEL *printer)
 {
        bool ret;
 
-       switch (level) {
-               case 2:
-                       /* allocate memory if needed.  Messy because
-                          convert_printer_info is used to update an existing
-                          printer or build a new one */
-
-                       if ( !printer->info_2 ) {
-                               printer->info_2 = TALLOC_ZERO_P( printer, NT_PRINTER_INFO_LEVEL_2 );
-                               if ( !printer->info_2 ) {
-                                       DEBUG(0,("convert_printer_info: talloc() failed!\n"));
-                                       return False;
-                               }
+       switch (info_ctr->level) {
+       case 2:
+               /* allocate memory if needed.  Messy because
+                  convert_printer_info is used to update an existing
+                  printer or build a new one */
+
+               if (!printer->info_2) {
+                       printer->info_2 = TALLOC_ZERO_P(printer, NT_PRINTER_INFO_LEVEL_2);
+                       if (!printer->info_2) {
+                               DEBUG(0,("convert_printer_info_new: "
+                                       "talloc() failed!\n"));
+                               return false;
                        }
+               }
+
+               ret = printer_info2_to_nt_printer_info2(info_ctr->info.info2,
+                                                       printer->info_2);
+               printer->info_2->setuptime = time(NULL);
+               return ret;
+       }
+
+       return false;
+}
+
+/*******************************************************************
+********************************************************************/
+
+static bool string_array_to_fstring_array(const char **sarray, fstring **farray)
+{
+       int i;
 
-                       ret = uni_2_asc_printer_info_2(uni->info_2, printer->info_2);
-                       printer->info_2->setuptime = time(NULL);
+       if (!sarray) {
+               *farray = NULL;
+               return true;
+       }
 
-                       return ret;
+       *farray = SMB_MALLOC_ARRAY(fstring, 1);
+       if (!*farray) {
+               return false;
        }
 
-       return False;
+       for (i=0; sarray[i] != NULL; i++) {
+               *farray = SMB_REALLOC_ARRAY(*farray, fstring, i+2);
+               if (!*farray) {
+                       return false;
+               }
+               fstrcpy((*farray)[i], sarray[i]);
+       }
+
+       fstrcpy((*farray)[i], "");
+
+       return true;
+}
+
+/*******************************************************************
+********************************************************************/
+
+static bool driver_info3_to_nt_driver_info3(struct spoolss_AddDriverInfo3 *r,
+                                           NT_PRINTER_DRIVER_INFO_LEVEL_3 **p)
+{
+       NT_PRINTER_DRIVER_INFO_LEVEL_3 *d;
+
+       DEBUG(7,("driver_info3_to_nt_driver_info3: Converting from UNICODE to ASCII\n"));
+
+       if (*p == NULL) {
+               *p = SMB_MALLOC_P(NT_PRINTER_DRIVER_INFO_LEVEL_3);
+               if (*p == NULL) {
+                       return false;
+               }
+               ZERO_STRUCTP(*p);
+       }
+
+       d = *p;
+
+       d->cversion =                   r->version;
+
+       fstrcpy(d->name,                r->driver_name);
+       fstrcpy(d->environment,         r->architecture);
+       fstrcpy(d->driverpath,          r->driver_path);
+       fstrcpy(d->datafile,            r->data_file);
+       fstrcpy(d->configfile,          r->config_file);
+       fstrcpy(d->helpfile,            r->help_file);
+       fstrcpy(d->monitorname,         r->monitor_name);
+       fstrcpy(d->defaultdatatype,     r->default_datatype);
+
+       DEBUGADD(8,( "version:         %d\n", d->cversion));
+       DEBUGADD(8,( "name:            %s\n", d->name));
+       DEBUGADD(8,( "environment:     %s\n", d->environment));
+       DEBUGADD(8,( "driverpath:      %s\n", d->driverpath));
+       DEBUGADD(8,( "datafile:        %s\n", d->datafile));
+       DEBUGADD(8,( "configfile:      %s\n", d->configfile));
+       DEBUGADD(8,( "helpfile:        %s\n", d->helpfile));
+       DEBUGADD(8,( "monitorname:     %s\n", d->monitorname));
+       DEBUGADD(8,( "defaultdatatype: %s\n", d->defaultdatatype));
+
+       if (r->dependent_files) {
+               if (!string_array_to_fstring_array(r->dependent_files->string,
+                                                  &d->dependentfiles)) {
+                       SAFE_FREE(*p);
+                       return false;
+               }
+       }
+
+       return true;
 }
 
-static bool convert_printer_driver_info(const SPOOL_PRINTER_DRIVER_INFO_LEVEL *uni,
-                                       NT_PRINTER_DRIVER_INFO_LEVEL *printer, uint32 level)
+/*******************************************************************
+********************************************************************/
+
+static bool driver_info6_to_nt_driver_info6(struct spoolss_AddDriverInfo6 *r,
+                                           NT_PRINTER_DRIVER_INFO_LEVEL_6 **p)
 {
-       bool result = True;
+       NT_PRINTER_DRIVER_INFO_LEVEL_6 *d;
+
+       DEBUG(7,("driver_info6_to_nt_driver_info6: Converting from UNICODE to ASCII\n"));
+
+       if (*p == NULL) {
+               *p = SMB_MALLOC_P(NT_PRINTER_DRIVER_INFO_LEVEL_6);
+               if (*p == NULL) {
+                       return false;
+               }
+               ZERO_STRUCTP(*p);
+       }
+
+       d = *p;
+
+       d->version =                    r->version;
+
+       fstrcpy(d->name,                r->driver_name);
+       fstrcpy(d->environment,         r->architecture);
+       fstrcpy(d->driverpath,          r->driver_path);
+       fstrcpy(d->datafile,            r->data_file);
+       fstrcpy(d->configfile,          r->config_file);
+       fstrcpy(d->helpfile,            r->help_file);
+       fstrcpy(d->monitorname,         r->monitor_name);
+       fstrcpy(d->defaultdatatype,     r->default_datatype);
+
+       DEBUGADD(8,( "version:         %d\n", d->version));
+       DEBUGADD(8,( "name:            %s\n", d->name));
+       DEBUGADD(8,( "environment:     %s\n", d->environment));
+       DEBUGADD(8,( "driverpath:      %s\n", d->driverpath));
+       DEBUGADD(8,( "datafile:        %s\n", d->datafile));
+       DEBUGADD(8,( "configfile:      %s\n", d->configfile));
+       DEBUGADD(8,( "helpfile:        %s\n", d->helpfile));
+       DEBUGADD(8,( "monitorname:     %s\n", d->monitorname));
+       DEBUGADD(8,( "defaultdatatype: %s\n", d->defaultdatatype));
+
+       if (r->dependent_files) {
+               if (!string_array_to_fstring_array(r->dependent_files->string,
+                                                  &d->dependentfiles)) {
+                       goto error;
+               }
+       }
+
+       if (r->previous_names) {
+               if (!string_array_to_fstring_array(r->previous_names->string,
+                                                  &d->previousnames)) {
+                       goto error;
+               }
+       }
+
+       return true;
+
+ error:
+       SAFE_FREE(*p);
+       return false;
+}
+
+/********************************************************************
+ ********************************************************************/
 
+static bool convert_printer_driver_info(const struct spoolss_AddDriverInfoCtr *r,
+                                       NT_PRINTER_DRIVER_INFO_LEVEL *printer,
+                                       uint32_t level)
+{
        switch (level) {
-               case 3:
-                       printer->info_3=NULL;
-                       if (!uni_2_asc_printer_driver_3(uni->info_3, &printer->info_3))
-                               result = False;
-                       break;
-               case 6:
-                       printer->info_6=NULL;
-                       if (!uni_2_asc_printer_driver_6(uni->info_6, &printer->info_6))
-                               result = False;
-                       break;
-               default:
-                       break;
+       case 3:
+               printer->info_3 = NULL;
+               if (!driver_info3_to_nt_driver_info3(r->info.info3, &printer->info_3)) {
+                       return false;
+               }
+               break;
+       case 6:
+               printer->info_6 = NULL;
+               if (!driver_info6_to_nt_driver_info6(r->info.info6, &printer->info_6)) {
+                       return false;
+               }
+               break;
+       default:
+               return false;
        }
 
-       return result;
+       return true;
 }
 
 bool convert_devicemode(const char *printername, const DEVICEMODE *devmode,
@@ -2365,74 +2465,58 @@ WERROR set_printer_dataex( NT_PRINTER_INFO_LEVEL *printer, const char *key, cons
  GetPrinterData on a printer server Handle.
 ********************************************************************/
 
-static WERROR getprinterdata_printer_server(TALLOC_CTX *ctx, fstring value, uint32 *type, uint8 **data, uint32 *needed, uint32 in_size)
+static WERROR getprinterdata_printer_server(TALLOC_CTX *mem_ctx,
+                                           const char *value,
+                                           enum winreg_Type *type,
+                                           union spoolss_PrinterData *data)
 {
-       int i;
-
        DEBUG(8,("getprinterdata_printer_server:%s\n", value));
 
        if (!StrCaseCmp(value, "W3SvcInstalled")) {
                *type = REG_DWORD;
-               if ( !(*data = TALLOC_ARRAY(ctx, uint8, sizeof(uint32) )) )
-                       return WERR_NOMEM;
-               SIVAL(*data, 0, 0x00);
-               *needed = 0x4;
+               data->value = 0x00;
                return WERR_OK;
        }
 
        if (!StrCaseCmp(value, "BeepEnabled")) {
                *type = REG_DWORD;
-               if ( !(*data = TALLOC_ARRAY(ctx, uint8, sizeof(uint32) )) )
-                       return WERR_NOMEM;
-               SIVAL(*data, 0, 0x00);
-               *needed = 0x4;
+               data->value = 0x00;
                return WERR_OK;
        }
 
        if (!StrCaseCmp(value, "EventLog")) {
                *type = REG_DWORD;
-               if ( !(*data = TALLOC_ARRAY(ctx, uint8, sizeof(uint32) )) )
-                       return WERR_NOMEM;
                /* formally was 0x1b */
-               SIVAL(*data, 0, 0x0);
-               *needed = 0x4;
+               data->value = 0x00;
                return WERR_OK;
        }
 
        if (!StrCaseCmp(value, "NetPopup")) {
                *type = REG_DWORD;
-               if ( !(*data = TALLOC_ARRAY(ctx, uint8, sizeof(uint32) )) )
-                       return WERR_NOMEM;
-               SIVAL(*data, 0, 0x00);
-               *needed = 0x4;
+               data->value = 0x00;
                return WERR_OK;
        }
 
        if (!StrCaseCmp(value, "MajorVersion")) {
                *type = REG_DWORD;
-               if ( !(*data = TALLOC_ARRAY(ctx, uint8, sizeof(uint32) )) )
-                       return WERR_NOMEM;
 
                /* Windows NT 4.0 seems to not allow uploading of drivers
                   to a server that reports 0x3 as the MajorVersion.
                   need to investigate more how Win2k gets around this .
                   -- jerry */
 
-               if ( RA_WINNT == get_remote_arch() )
-                       SIVAL(*data, 0, 2);
-               else
-                       SIVAL(*data, 0, 3);
+               if (RA_WINNT == get_remote_arch()) {
+                       data->value = 0x02;
+               } else {
+                       data->value = 0x03;
+               }
 
-               *needed = 0x4;
                return WERR_OK;
        }
 
        if (!StrCaseCmp(value, "MinorVersion")) {
                *type = REG_DWORD;
-               if ( !(*data = TALLOC_ARRAY(ctx, uint8, sizeof(uint32) )) )
-                       return WERR_NOMEM;
-               SIVAL(*data, 0, 0);
-               *needed = 0x4;
+               data->value = 0x00;
                return WERR_OK;
        }
 
@@ -2444,109 +2528,88 @@ static WERROR getprinterdata_printer_server(TALLOC_CTX *ctx, fstring value, uint
         *  extra unicode string = e.g. "Service Pack 3"
         */
        if (!StrCaseCmp(value, "OSVersion")) {
+               DATA_BLOB blob;
+               enum ndr_err_code ndr_err;
+               struct spoolss_OSVersion os;
+
+               os.major                = 5;    /* Windows 2000 == 5.0 */
+               os.minor                = 0;
+               os.build                = 2195; /* build */
+               os.extra_string         = "";   /* leave extra string empty */
+
+               ndr_err = ndr_push_struct_blob(&blob, mem_ctx, NULL, &os,
+                       (ndr_push_flags_fn_t)ndr_push_spoolss_OSVersion);
+               if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+                       return WERR_GENERAL_FAILURE;
+               }
+
                *type = REG_BINARY;
-               *needed = 0x114;
-
-               if ( !(*data = TALLOC_ZERO_ARRAY(ctx, uint8, (*needed > in_size) ? *needed:in_size )) )
-                       return WERR_NOMEM;
-
-               SIVAL(*data, 0, *needed);       /* size */
-               SIVAL(*data, 4, 5);             /* Windows 2000 == 5.0 */
-               SIVAL(*data, 8, 0);
-               SIVAL(*data, 12, 2195);         /* build */
-
-               /* leave extra string empty */
+               data->binary = blob;
 
                return WERR_OK;
        }
 
 
        if (!StrCaseCmp(value, "DefaultSpoolDirectory")) {
-               const char *string="C:\\PRINTERS";
                *type = REG_SZ;
-               *needed = 2*(strlen(string)+1);
-               if((*data  = (uint8 *)TALLOC(ctx, (*needed > in_size) ? *needed:in_size )) == NULL)
-                       return WERR_NOMEM;
-               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(string); i++) {
-                       (*data)[2*i]=string[i];
-                       (*data)[2*i+1]='\0';
-               }
+               data->string = talloc_strdup(mem_ctx, "C:\\PRINTERS");
+               W_ERROR_HAVE_NO_MEMORY(data->string);
+
                return WERR_OK;
        }
 
        if (!StrCaseCmp(value, "Architecture")) {
-               const char *string="Windows NT x86";
                *type = REG_SZ;
-               *needed = 2*(strlen(string)+1);
-               if((*data  = (uint8 *)TALLOC(ctx, (*needed > in_size) ? *needed:in_size )) == NULL)
-                       return WERR_NOMEM;
-               memset(*data, 0, (*needed > in_size) ? *needed:in_size);
-               for (i=0; i<strlen(string); i++) {
-                       (*data)[2*i]=string[i];
-                       (*data)[2*i+1]='\0';
-               }
+
+               data->string = talloc_strdup(mem_ctx, "Windows NT x86");
+               W_ERROR_HAVE_NO_MEMORY(data->string);
+
                return WERR_OK;
        }
 
        if (!StrCaseCmp(value, "DsPresent")) {
                *type = REG_DWORD;
-               if ( !(*data = TALLOC_ARRAY(ctx, uint8, sizeof(uint32) )) )
-                       return WERR_NOMEM;
 
                /* only show the publish check box if we are a
-                  memeber of a AD domain */
-
-               if ( lp_security() == SEC_ADS )
-                       SIVAL(*data, 0, 0x01);
-               else
-                       SIVAL(*data, 0, 0x00);
+                  member of a AD domain */
 
-               *needed = 0x4;
+               if (lp_security() == SEC_ADS) {
+                       data->value = 0x01;
+               } else {
+                       data->value = 0x00;
+               }
                return WERR_OK;
        }
 
        if (!StrCaseCmp(value, "DNSMachineName")) {
                const char *hostname = get_mydnsfullname();
 
-               if (!hostname)
+               if (!hostname) {
                        return WERR_BADFILE;
-               *type = REG_SZ;
-               *needed = 2*(strlen(hostname)+1);
-               if((*data  = (uint8 *)TALLOC(ctx, (*needed > in_size) ? *needed:in_size )) == NULL)
-                       return WERR_NOMEM;
-               memset(*data, 0, (*needed > in_size) ? *needed:in_size);
-               for (i=0; i<strlen(hostname); i++) {
-                       (*data)[2*i]=hostname[i];
-                       (*data)[2*i+1]='\0';
                }
+
+               *type = REG_SZ;
+               data->string = talloc_strdup(mem_ctx, hostname);
+               W_ERROR_HAVE_NO_MEMORY(data->string);
+
                return WERR_OK;
        }
 
-
        return WERR_BADFILE;
 }
 
-/********************************************************************
* spoolss_getprinterdata
- ********************************************************************/
+/****************************************************************
_spoolss_GetPrinterData
+****************************************************************/
 
-WERROR _spoolss_getprinterdata(pipes_struct *p, SPOOL_Q_GETPRINTERDATA *q_u, SPOOL_R_GETPRINTERDATA *r_u)
+WERROR _spoolss_GetPrinterData(pipes_struct *p,
+                              struct spoolss_GetPrinterData *r)
 {
-       POLICY_HND      *handle = &q_u->handle;
-       UNISTR2         *valuename = &q_u->valuename;
-       uint32          in_size = q_u->size;
-       uint32          *type = &r_u->type;
-       uint32          *out_size = &r_u->size;
-       uint8           **data = &r_u->data;
-       uint32          *needed = &r_u->needed;
-       WERROR          status;
-       fstring         value;
-       Printer_entry   *Printer = find_printer_index_by_hnd(p, handle);
-       NT_PRINTER_INFO_LEVEL   *printer = NULL;
-       int             snum = 0;
+       WERROR result;
+       Printer_entry *Printer = find_printer_index_by_hnd(p, r->in.handle);
+       NT_PRINTER_INFO_LEVEL *printer = NULL;
+       int snum = 0;
 
        /*
         * Reminder: when it's a string, the length is in BYTES
@@ -2555,79 +2618,80 @@ WERROR _spoolss_getprinterdata(pipes_struct *p, SPOOL_Q_GETPRINTERDATA *q_u, SPO
         * JFM, 4/19/1999
         */
 
-       *out_size = in_size;
-
        /* in case of problem, return some default values */
 
-       *needed = 0;
-       *type   = 0;
+       *r->out.needed  = 0;
+       *r->out.type    = 0;
 
-       DEBUG(4,("_spoolss_getprinterdata\n"));
+       DEBUG(4,("_spoolss_GetPrinterData\n"));
 
-       if ( !Printer ) {
-               DEBUG(2,("_spoolss_getprinterdata: Invalid handle (%s:%u:%u).\n", OUR_HANDLE(handle)));
-               status = WERR_BADFID;
+       if (!Printer) {
+               DEBUG(2,("_spoolss_GetPrinterData: Invalid handle (%s:%u:%u).\n",
+                       OUR_HANDLE(r->in.handle)));
+               result = WERR_BADFID;
                goto done;
        }
 
-       unistr2_to_ascii(value, valuename, sizeof(value));
-
-       if ( Printer->printer_type == SPLHND_SERVER )
-               status = getprinterdata_printer_server( p->mem_ctx, value, type, data, needed, *out_size );
-       else
-       {
-               if ( !get_printer_snum(p,handle, &snum, NULL) ) {
-                       status = WERR_BADFID;
+       if (Printer->printer_type == SPLHND_SERVER) {
+               result = getprinterdata_printer_server(p->mem_ctx,
+                                                      r->in.value_name,
+                                                      r->out.type,
+                                                      r->out.data);
+       } else {
+               if (!get_printer_snum(p, r->in.handle, &snum, NULL)) {
+                       result = WERR_BADFID;
                        goto done;
                }
 
-               status = get_a_printer(Printer, &printer, 2, lp_servicename(snum));
-               if ( !W_ERROR_IS_OK(status) )
+               result = get_a_printer(Printer, &printer, 2, lp_servicename(snum));
+               if (!W_ERROR_IS_OK(result)) {
                        goto done;
+               }
 
                /* XP sends this and wants to change id value from the PRINTER_INFO_0 */
 
-               if ( strequal(value, "ChangeId") ) {
-                       *type = REG_DWORD;
-                       *needed = sizeof(uint32);
-                       if ( (*data = (uint8*)TALLOC(p->mem_ctx, sizeof(uint32))) == NULL) {
-                               status = WERR_NOMEM;
+               if (strequal(r->in.value_name, "ChangeId")) {
+                       *r->out.type = REG_DWORD;
+                       r->out.data->value = printer->info_2->changeid;
+                       result = WERR_OK;
+               } else {
+                       REGISTRY_VALUE *v;
+                       DATA_BLOB blob;
+
+                       v = get_printer_data(printer->info_2,
+                                            SPOOL_PRINTERDATA_KEY,
+                                            r->in.value_name);
+                       if (!v) {
+                               result = WERR_BADFILE;
                                goto done;
                        }
-                       SIVAL( *data, 0, printer->info_2->changeid );
-                       status = WERR_OK;
-               }
-               else
-                       status = get_printer_dataex( p->mem_ctx, printer, SPOOL_PRINTERDATA_KEY, value, type, data, needed, *out_size );
-       }
 
-       if (*needed > *out_size)
-               status = WERR_MORE_DATA;
+                       *r->out.type = v->type;
 
-done:
-       if ( !W_ERROR_IS_OK(status) )
-       {
-               DEBUG(5, ("error %d: allocating %d\n", W_ERROR_V(status),*out_size));
-
-               /* reply this param doesn't exist */
+                       blob = data_blob_const(v->data_p, v->size);
 
-               if ( *out_size ) {
-                       if((*data=(uint8 *)TALLOC_ZERO_ARRAY(p->mem_ctx, uint8, *out_size)) == NULL) {
-                               if ( printer )
-                                       free_a_printer( &printer, 2 );
-                               return WERR_NOMEM;
-                       }
-               } else {
-                       *data = NULL;
+                       result = pull_spoolss_PrinterData(p->mem_ctx, &blob,
+                                                         r->out.data,
+                                                         *r->out.type);
                }
        }
 
+ done:
        /* cleanup & exit */
 
-       if ( printer )
-               free_a_printer( &printer, 2 );
+       if (printer) {
+               free_a_printer(&printer, 2);
+       }
 
-       return status;
+       if (!W_ERROR_IS_OK(result)) {
+               return result;
+       }
+
+       *r->out.needed  = ndr_size_spoolss_PrinterData(r->out.data, *r->out.type, NULL, 0);
+       *r->out.type    = SPOOLSS_BUFFER_OK(*r->out.type, REG_NONE);
+       r->out.data     = SPOOLSS_BUFFER_OK(r->out.data, r->out.data);
+
+       return SPOOLSS_BUFFER_OK(WERR_OK, WERR_MORE_DATA);
 }
 
 /*********************************************************
@@ -2705,6 +2769,7 @@ static bool srv_spoolss_replyopenprinter(int snum, const char *printer,
                                        POLICY_HND *handle, struct sockaddr_storage *client_ss)
 {
        WERROR result;
+       NTSTATUS status;
 
        /*
         * If it's the first connection, contact the client
@@ -2736,40 +2801,88 @@ static bool srv_spoolss_replyopenprinter(int snum, const char *printer,
 
        smb_connections++;
 
-       result = rpccli_spoolss_reply_open_printer(notify_cli_pipe,
-                       talloc_tos(),
-                       printer,
-                       localprinter,
-                       type,
-                       handle);
-
-       if (!W_ERROR_IS_OK(result))
+       status = rpccli_spoolss_ReplyOpenPrinter(notify_cli_pipe, talloc_tos(),
+                                                printer,
+                                                localprinter,
+                                                type,
+                                                0,
+                                                NULL,
+                                                handle,
+                                                &result);
+       if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(result))
                DEBUG(5,("srv_spoolss_reply_open_printer: Client RPC returned [%s]\n",
                        win_errstr(result)));
 
        return (W_ERROR_IS_OK(result));
 }
 
-/********************************************************************
- * _spoolss_rffpcnex
- * ReplyFindFirstPrinterChangeNotifyEx
+/****************************************************************
+ ****************************************************************/
+
+static struct spoolss_NotifyOption *dup_spoolss_NotifyOption(TALLOC_CTX *mem_ctx,
+                                                            const struct spoolss_NotifyOption *r)
+{
+       struct spoolss_NotifyOption *option;
+       uint32_t i,k;
+
+       if (!r) {
+               return NULL;
+       }
+
+       option = talloc_zero(mem_ctx, struct spoolss_NotifyOption);
+       if (!option) {
+               return NULL;
+       }
+
+       *option = *r;
+
+       if (!option->count) {
+               return option;
+       }
+
+       option->types = talloc_zero_array(option,
+               struct spoolss_NotifyOptionType, option->count);
+       if (!option->types) {
+               talloc_free(option);
+               return NULL;
+       }
+
+       for (i=0; i < option->count; i++) {
+               option->types[i] = r->types[i];
+
+               if (option->types[i].count) {
+                       option->types[i].fields = talloc_zero_array(option,
+                               enum spoolss_Field, option->types[i].count);
+                       if (!option->types[i].fields) {
+                               talloc_free(option);
+                               return NULL;
+                       }
+                       for (k=0; k<option->types[i].count; k++) {
+                               option->types[i].fields[k] =
+                                       r->types[i].fields[k];
+                       }
+               }
+       }
+
+       return option;
+}
+
+/****************************************************************
+ * _spoolss_RemoteFindFirstPrinterChangeNotifyEx
  *
  * before replying OK: status=0 a rpc call is made to the workstation
  * asking ReplyOpenPrinter
  *
  * in fact ReplyOpenPrinter is the changenotify equivalent on the spoolss pipe
  * called from api_spoolss_rffpcnex
- ********************************************************************/
+****************************************************************/
 
-WERROR _spoolss_rffpcnex(pipes_struct *p, SPOOL_Q_RFFPCNEX *q_u, SPOOL_R_RFFPCNEX *r_u)
+WERROR _spoolss_RemoteFindFirstPrinterChangeNotifyEx(pipes_struct *p,
+                                                    struct spoolss_RemoteFindFirstPrinterChangeNotifyEx *r)
 {
-       POLICY_HND *handle = &q_u->handle;
-       uint32 flags = q_u->flags;
-       uint32 options = q_u->options;
-       UNISTR2 *localmachine = &q_u->localmachine;
-       uint32 printerlocal = q_u->printerlocal;
+       POLICY_HND *handle = r->in.handle;
        int snum = -1;
-       SPOOL_NOTIFY_OPTION *option = q_u->option;
+       struct spoolss_NotifyOption *option = r->in.notify_options;
        struct sockaddr_storage client_ss;
 
        /* store the notify value in the printer struct */
@@ -2777,21 +2890,19 @@ WERROR _spoolss_rffpcnex(pipes_struct *p, SPOOL_Q_RFFPCNEX *q_u, SPOOL_R_RFFPCNE
        Printer_entry *Printer=find_printer_index_by_hnd(p, handle);
 
        if (!Printer) {
-               DEBUG(2,("_spoolss_rffpcnex: Invalid handle (%s:%u:%u).\n", OUR_HANDLE(handle)));
+               DEBUG(2,("_spoolss_RemoteFindFirstPrinterChangeNotifyEx: "
+                       "Invalid handle (%s:%u:%u).\n", OUR_HANDLE(handle)));
                return WERR_BADFID;
        }
 
-       Printer->notify.flags=flags;
-       Printer->notify.options=options;
-       Printer->notify.printerlocal=printerlocal;
+       Printer->notify.flags           = r->in.flags;
+       Printer->notify.options         = r->in.options;
+       Printer->notify.printerlocal    = r->in.printer_local;
 
-       if (Printer->notify.option)
-               free_spool_notify_option(&Printer->notify.option);
+       TALLOC_FREE(Printer->notify.option);
+       Printer->notify.option = dup_spoolss_NotifyOption(Printer, option);
 
-       Printer->notify.option=dup_spool_notify_option(option);
-
-       unistr2_to_ascii(Printer->notify.localmachine, localmachine,
-                      sizeof(Printer->notify.localmachine));
+       fstrcpy(Printer->notify.localmachine, r->in.local_machine);
 
        /* Connect to the client machine and send a ReplyOpenPrinter */
 
@@ -2821,25 +2932,12 @@ WERROR _spoolss_rffpcnex(pipes_struct *p, SPOOL_Q_RFFPCNEX *q_u, SPOOL_R_RFFPCNE
  ********************************************************************/
 
 void spoolss_notify_server_name(int snum,
-                                      SPOOL_NOTIFY_INFO_DATA *data,
+                                      struct spoolss_Notify *data,
                                       print_queue_struct *queue,
                                       NT_PRINTER_INFO_LEVEL *printer,
                                       TALLOC_CTX *mem_ctx)
 {
-       smb_ucs2_t *temp = NULL;
-       uint32 len;
-
-       len = rpcstr_push_talloc(mem_ctx, &temp, printer->info_2->servername);
-       if (len == (uint32)-1) {
-               len = 0;
-       }
-
-       data->notify_data.data.length = len;
-       if (len) {
-               data->notify_data.data.string = (uint16 *)temp;
-       } else {
-               data->notify_data.data.string = NULL;
-       }
+       SETUP_SPOOLSS_NOTIFY_DATA_STRING(data, printer->info_2->servername);
 }
 
 /*******************************************************************
@@ -2847,14 +2945,11 @@ void spoolss_notify_server_name(int snum,
  ********************************************************************/
 
 void spoolss_notify_printer_name(int snum,
-                                       SPOOL_NOTIFY_INFO_DATA *data,
+                                       struct spoolss_Notify *data,
                                        print_queue_struct *queue,
                                        NT_PRINTER_INFO_LEVEL *printer,
                                        TALLOC_CTX *mem_ctx)
 {
-       smb_ucs2_t *temp = NULL;
-       uint32 len;
-
        /* the notify name should not contain the \\server\ part */
        char *p = strrchr(printer->info_2->printername, '\\');
 
@@ -2864,17 +2959,7 @@ void spoolss_notify_printer_name(int snum,
                p++;
        }
 
-       len = rpcstr_push_talloc(mem_ctx, &temp, p);
-       if (len == (uint32)-1) {
-               len = 0;
-       }
-
-       data->notify_data.data.length = len;
-       if (len) {
-               data->notify_data.data.string = (uint16 *)temp;
-       } else {
-               data->notify_data.data.string = NULL;
-       }
+       SETUP_SPOOLSS_NOTIFY_DATA_STRING(data, p);
 }
 
 /*******************************************************************
@@ -2882,26 +2967,12 @@ void spoolss_notify_printer_name(int snum,
  ********************************************************************/
 
 void spoolss_notify_share_name(int snum,
-                                     SPOOL_NOTIFY_INFO_DATA *data,
+                                     struct spoolss_Notify *data,
                                      print_queue_struct *queue,
                                      NT_PRINTER_INFO_LEVEL *printer,
                                      TALLOC_CTX *mem_ctx)
 {
-       smb_ucs2_t *temp = NULL;
-       uint32 len;
-
-       len = rpcstr_push_talloc(mem_ctx, &temp, lp_servicename(snum));
-       if (len == (uint32)-1) {
-               len = 0;
-       }
-
-       data->notify_data.data.length = len;
-       if (len) {
-               data->notify_data.data.string = (uint16 *)temp;
-       } else {
-               data->notify_data.data.string = NULL;
-       }
-
+       SETUP_SPOOLSS_NOTIFY_DATA_STRING(data, lp_servicename(snum));
 }
 
 /*******************************************************************
@@ -2909,27 +2980,12 @@ void spoolss_notify_share_name(int snum,
  ********************************************************************/
 
 void spoolss_notify_port_name(int snum,
-                                    SPOOL_NOTIFY_INFO_DATA *data,
+                                    struct spoolss_Notify *data,
                                     print_queue_struct *queue,
                                     NT_PRINTER_INFO_LEVEL *printer,
                                     TALLOC_CTX *mem_ctx)
 {
-       smb_ucs2_t *temp = NULL;
-       uint32 len;
-
-       /* even if it's strange, that's consistant in all the code */
-
-       len = rpcstr_push_talloc(mem_ctx, &temp, printer->info_2->portname);
-       if (len == (uint32)-1) {
-               len = 0;
-       }
-
-       data->notify_data.data.length = len;
-       if (len) {
-               data->notify_data.data.string = (uint16 *)temp;
-       } else {
-               data->notify_data.data.string = NULL;
-       }
+       SETUP_SPOOLSS_NOTIFY_DATA_STRING(data, printer->info_2->portname);
 }
 
 /*******************************************************************
@@ -2938,25 +2994,12 @@ void spoolss_notify_port_name(int snum,
  ********************************************************************/
 
 void spoolss_notify_driver_name(int snum,
-                                      SPOOL_NOTIFY_INFO_DATA *data,
+                                      struct spoolss_Notify *data,
                                       print_queue_struct *queue,
                                       NT_PRINTER_INFO_LEVEL *printer,
                                       TALLOC_CTX *mem_ctx)
 {
-       smb_ucs2_t *temp = NULL;
-       uint32 len;
-
-       len = rpcstr_push_talloc(mem_ctx, &temp, printer->info_2->drivername);
-       if (len == (uint32)-1) {
-               len = 0;
-       }
-
-       data->notify_data.data.length = len;
-       if (len) {
-               data->notify_data.data.string = (uint16 *)temp;
-       } else {
-               data->notify_data.data.string = NULL;
-       }
+       SETUP_SPOOLSS_NOTIFY_DATA_STRING(data, printer->info_2->drivername);
 }
 
 /*******************************************************************
@@ -2964,28 +3007,20 @@ void spoolss_notify_driver_name(int snum,
  ********************************************************************/
 
 void spoolss_notify_comment(int snum,
-                                  SPOOL_NOTIFY_INFO_DATA *data,
+                                  struct spoolss_Notify *data,
                                   print_queue_struct *queue,
                                   NT_PRINTER_INFO_LEVEL *printer,
                                   TALLOC_CTX *mem_ctx)
 {
-       smb_ucs2_t *temp = NULL;
-       uint32 len;
-
-       if (*printer->info_2->comment == '\0')
-               len = rpcstr_push_talloc(mem_ctx, &temp, lp_comment(snum));
-       else
-               len = rpcstr_push_talloc(mem_ctx, &temp, printer->info_2->comment);
+       char *p;
 
-       if (len == (uint32)-1) {
-               len = 0;
-       }
-       data->notify_data.data.length = len;
-       if (len) {
-               data->notify_data.data.string = (uint16 *)temp;
+       if (*printer->info_2->comment == '\0') {
+               p = lp_comment(snum);
        } else {
-               data->notify_data.data.string = NULL;
+               p = printer->info_2->comment;
        }
+
+       SETUP_SPOOLSS_NOTIFY_DATA_STRING(data, printer->info_2->comment);
 }
 
 /*******************************************************************
@@ -2994,25 +3029,12 @@ void spoolss_notify_comment(int snum,
  ********************************************************************/
 
 void spoolss_notify_location(int snum,
-                                   SPOOL_NOTIFY_INFO_DATA *data,
+                                   struct spoolss_Notify *data,
                                    print_queue_struct *queue,
                                    NT_PRINTER_INFO_LEVEL *printer,
                                    TALLOC_CTX *mem_ctx)
 {
-       smb_ucs2_t *temp = NULL;
-       uint32 len;
-
-       len = rpcstr_push_talloc(mem_ctx, &temp, printer->info_2->location);
-       if (len == (uint32)-1) {
-               len = 0;
-       }
-
-       data->notify_data.data.length = len;
-       if (len) {
-               data->notify_data.data.string = (uint16 *)temp;
-       } else {
-               data->notify_data.data.string = NULL;
-       }
+       SETUP_SPOOLSS_NOTIFY_DATA_STRING(data, printer->info_2->location);
 }
 
 /*******************************************************************
@@ -3021,14 +3043,13 @@ void spoolss_notify_location(int snum,
  ********************************************************************/
 
 static void spoolss_notify_devmode(int snum,
-                                  SPOOL_NOTIFY_INFO_DATA *data,
+                                  struct spoolss_Notify *data,
                                   print_queue_struct *queue,
                                   NT_PRINTER_INFO_LEVEL *printer,
                                   TALLOC_CTX *mem_ctx)
 {
        /* for a dummy implementation we have to zero the fields */
-       data->notify_data.data.length = 0;
-       data->notify_data.data.string = NULL;
+       SETUP_SPOOLSS_NOTIFY_DATA_DEVMODE(data, NULL);
 }
 
 /*******************************************************************
@@ -3036,25 +3057,12 @@ static void spoolss_notify_devmode(int snum,
  ********************************************************************/
 
 void spoolss_notify_sepfile(int snum,
-                                  SPOOL_NOTIFY_INFO_DATA *data,
+                                  struct spoolss_Notify *data,
                                   print_queue_struct *queue,
                                   NT_PRINTER_INFO_LEVEL *printer,
                                   TALLOC_CTX *mem_ctx)
 {
-       smb_ucs2_t *temp = NULL;
-       uint32 len;
-
-       len = rpcstr_push_talloc(mem_ctx, &temp, printer->info_2->sepfile);
-       if (len == (uint32)-1) {
-               len = 0;
-       }
-
-       data->notify_data.data.length = len;
-       if (len) {
-               data->notify_data.data.string = (uint16 *)temp;
-       } else {
-               data->notify_data.data.string = NULL;
-       }
+       SETUP_SPOOLSS_NOTIFY_DATA_STRING(data, printer->info_2->sepfile);
 }
 
 /*******************************************************************
@@ -3063,25 +3071,12 @@ void spoolss_notify_sepfile(int snum,
  ********************************************************************/
 
 void spoolss_notify_print_processor(int snum,
-                                          SPOOL_NOTIFY_INFO_DATA *data,
+                                          struct spoolss_Notify *data,
                                           print_queue_struct *queue,
                                           NT_PRINTER_INFO_LEVEL *printer,
                                           TALLOC_CTX *mem_ctx)
 {
-       smb_ucs2_t *temp = NULL;
-       uint32 len;
-
-       len = rpcstr_push_talloc(mem_ctx, &temp, printer->info_2->printprocessor);
-       if (len == (uint32)-1) {
-               len = 0;
-       }
-
-       data->notify_data.data.length = len;
-       if (len) {
-               data->notify_data.data.string = (uint16 *)temp;
-       } else {
-               data->notify_data.data.string = NULL;
-       }
+       SETUP_SPOOLSS_NOTIFY_DATA_STRING(data, printer->info_2->printprocessor);
 }
 
 /*******************************************************************
@@ -3090,25 +3085,12 @@ void spoolss_notify_print_processor(int snum,
  ********************************************************************/
 
 void spoolss_notify_parameters(int snum,
-                                     SPOOL_NOTIFY_INFO_DATA *data,
+                                     struct spoolss_Notify *data,
                                      print_queue_struct *queue,
                                      NT_PRINTER_INFO_LEVEL *printer,
                                      TALLOC_CTX *mem_ctx)
 {
-       smb_ucs2_t *temp = NULL;
-       uint32 len;
-
-       len = rpcstr_push_talloc(mem_ctx, &temp, printer->info_2->parameters);
-       if (len == (uint32)-1) {
-               len = 0;
-       }
-
-       data->notify_data.data.length = len;
-       if (len) {
-               data->notify_data.data.string = (uint16 *)temp;
-       } else {
-               data->notify_data.data.string = NULL;
-       }
+       SETUP_SPOOLSS_NOTIFY_DATA_STRING(data, printer->info_2->parameters);
 }
 
 /*******************************************************************
@@ -3117,25 +3099,12 @@ void spoolss_notify_parameters(int snum,
  ********************************************************************/
 
 void spoolss_notify_datatype(int snum,
-                                   SPOOL_NOTIFY_INFO_DATA *data,
+                                   struct spoolss_Notify *data,
                                    print_queue_struct *queue,
                                    NT_PRINTER_INFO_LEVEL *printer,
                                    TALLOC_CTX *mem_ctx)
 {
-       smb_ucs2_t *temp = NULL;
-       uint32 len;
-
-       len = rpcstr_push_talloc(mem_ctx, &temp, printer->info_2->datatype);
-       if (len == (uint32)-1) {
-               len = 0;
-       }
-
-       data->notify_data.data.length = len;
-       if (len) {
-               data->notify_data.data.string = (uint16 *)temp;
-       } else {
-               data->notify_data.data.string = NULL;
-       }
+       SETUP_SPOOLSS_NOTIFY_DATA_STRING(data, printer->info_2->datatype);
 }
 
 /*******************************************************************
@@ -3145,13 +3114,14 @@ void spoolss_notify_datatype(int snum,
  ********************************************************************/
 
 static void spoolss_notify_security_desc(int snum,
-                                        SPOOL_NOTIFY_INFO_DATA *data,
+                                        struct spoolss_Notify *data,
                                         print_queue_struct *queue,
                                         NT_PRINTER_INFO_LEVEL *printer,
                                         TALLOC_CTX *mem_ctx)
 {
-       data->notify_data.sd.size = printer->info_2->secdesc_buf->sd_size;
-       data->notify_data.sd.desc = dup_sec_desc( mem_ctx, printer->info_2->secdesc_buf->sd ) ;
+       SETUP_SPOOLSS_NOTIFY_DATA_SECDESC(data,
+                                         printer->info_2->secdesc_buf->sd_size,
+                                         printer->info_2->secdesc_buf->sd);
 }
 
 /*******************************************************************
@@ -3160,13 +3130,12 @@ static void spoolss_notify_security_desc(int snum,
  ********************************************************************/
 
 void spoolss_notify_attributes(int snum,
-                                     SPOOL_NOTIFY_INFO_DATA *data,
+                                     struct spoolss_Notify *data,
                                      print_queue_struct *queue,
                                      NT_PRINTER_INFO_LEVEL *printer,
                                      TALLOC_CTX *mem_ctx)
 {
-       data->notify_data.value[0] = printer->info_2->attributes;
-       data->notify_data.value[1] = 0;
+       SETUP_SPOOLSS_NOTIFY_DATA_INTEGER(data, printer->info_2->attributes);
 }
 
 /*******************************************************************
@@ -3174,13 +3143,12 @@ void spoolss_notify_attributes(int snum,
  ********************************************************************/
 
 static void spoolss_notify_priority(int snum,
-                                   SPOOL_NOTIFY_INFO_DATA *data,
+                                   struct spoolss_Notify *data,
                                    print_queue_struct *queue,
                                    NT_PRINTER_INFO_LEVEL *printer,
                                    TALLOC_CTX *mem_ctx)
 {
-       data->notify_data.value[0] = printer->info_2->priority;
-       data->notify_data.value[1] = 0;
+       SETUP_SPOOLSS_NOTIFY_DATA_INTEGER(data, printer->info_2->priority);
 }
 
 /*******************************************************************
@@ -3188,13 +3156,12 @@ static void spoolss_notify_priority(int snum,
  ********************************************************************/
 
 static void spoolss_notify_default_priority(int snum,
-                                           SPOOL_NOTIFY_INFO_DATA *data,
+                                           struct spoolss_Notify *data,
                                            print_queue_struct *queue,
                                            NT_PRINTER_INFO_LEVEL *printer,
                                            TALLOC_CTX *mem_ctx)
 {
-       data->notify_data.value[0] = printer->info_2->default_priority;
-       data->notify_data.value[1] = 0;
+       SETUP_SPOOLSS_NOTIFY_DATA_INTEGER(data, printer->info_2->default_priority);
 }
 
 /*******************************************************************
@@ -3202,13 +3169,12 @@ static void spoolss_notify_default_priority(int snum,
  ********************************************************************/
 
 static void spoolss_notify_start_time(int snum,
-                                     SPOOL_NOTIFY_INFO_DATA *data,
+                                     struct spoolss_Notify *data,
                                      print_queue_struct *queue,
                                      NT_PRINTER_INFO_LEVEL *printer,
                                      TALLOC_CTX *mem_ctx)
 {
-       data->notify_data.value[0] = printer->info_2->starttime;
-       data->notify_data.value[1] = 0;
+       SETUP_SPOOLSS_NOTIFY_DATA_INTEGER(data, printer->info_2->starttime);
 }
 
 /*******************************************************************
@@ -3216,13 +3182,12 @@ static void spoolss_notify_start_time(int snum,
  ********************************************************************/
 
 static void spoolss_notify_until_time(int snum,
-                                     SPOOL_NOTIFY_INFO_DATA *data,
+                                     struct spoolss_Notify *data,
                                      print_queue_struct *queue,
                                      NT_PRINTER_INFO_LEVEL *printer,
                                      TALLOC_CTX *mem_ctx)
 {
-       data->notify_data.value[0] = printer->info_2->untiltime;
-       data->notify_data.value[1] = 0;
+       SETUP_SPOOLSS_NOTIFY_DATA_INTEGER(data, printer->info_2->untiltime);
 }
 
 /*******************************************************************
@@ -3230,7 +3195,7 @@ static void spoolss_notify_until_time(int snum,
  ********************************************************************/
 
 static void spoolss_notify_status(int snum,
-                                 SPOOL_NOTIFY_INFO_DATA *data,
+                                 struct spoolss_Notify *data,
                                  print_queue_struct *queue,
                                  NT_PRINTER_INFO_LEVEL *printer,
                                  TALLOC_CTX *mem_ctx)
@@ -3238,8 +3203,7 @@ static void spoolss_notify_status(int snum,
        print_status_struct status;
 
        print_queue_length(snum, &status);
-       data->notify_data.value[0]=(uint32) status.status;
-       data->notify_data.value[1] = 0;
+       SETUP_SPOOLSS_NOTIFY_DATA_INTEGER(data, status.status);
 }
 
 /*******************************************************************
@@ -3247,13 +3211,12 @@ static void spoolss_notify_status(int snum,
  ********************************************************************/
 
 void spoolss_notify_cjobs(int snum,
-                                SPOOL_NOTIFY_INFO_DATA *data,
+                                struct spoolss_Notify *data,
                                 print_queue_struct *queue,
                                 NT_PRINTER_INFO_LEVEL *printer,
                                 TALLOC_CTX *mem_ctx)
 {
-       data->notify_data.value[0] = print_queue_length(snum, NULL);
-       data->notify_data.value[1] = 0;
+       SETUP_SPOOLSS_NOTIFY_DATA_INTEGER(data, print_queue_length(snum, NULL));
 }
 
 /*******************************************************************
@@ -3261,15 +3224,14 @@ void spoolss_notify_cjobs(int snum,
  ********************************************************************/
 
 static void spoolss_notify_average_ppm(int snum,
-                                      SPOOL_NOTIFY_INFO_DATA *data,
+                                      struct spoolss_Notify *data,
                                       print_queue_struct *queue,
                                       NT_PRINTER_INFO_LEVEL *printer,
                                       TALLOC_CTX *mem_ctx)
 {
        /* always respond 8 pages per minutes */
        /* a little hard ! */
-       data->notify_data.value[0] = printer->info_2->averageppm;
-       data->notify_data.value[1] = 0;
+       SETUP_SPOOLSS_NOTIFY_DATA_INTEGER(data, printer->info_2->averageppm);
 }
 
 /*******************************************************************
@@ -3277,25 +3239,12 @@ static void spoolss_notify_average_ppm(int snum,
  ********************************************************************/
 
 static void spoolss_notify_username(int snum,
-                                   SPOOL_NOTIFY_INFO_DATA *data,
+                                   struct spoolss_Notify *data,
                                    print_queue_struct *queue,
                                    NT_PRINTER_INFO_LEVEL *printer,
                                    TALLOC_CTX *mem_ctx)
 {
-       smb_ucs2_t *temp = NULL;
-       uint32 len;
-
-       len = rpcstr_push_talloc(mem_ctx, &temp, queue->fs_user);
-       if (len == (uint32)-1) {
-               len = 0;
-       }
-
-       data->notify_data.data.length = len;
-       if (len) {
-               data->notify_data.data.string = (uint16 *)temp;
-       } else {
-               data->notify_data.data.string = NULL;
-       }
+       SETUP_SPOOLSS_NOTIFY_DATA_STRING(data, queue->fs_user);
 }
 
 /*******************************************************************
@@ -3303,13 +3252,12 @@ static void spoolss_notify_username(int snum,
  ********************************************************************/
 
 static void spoolss_notify_job_status(int snum,
-                                     SPOOL_NOTIFY_INFO_DATA *data,
+                                     struct spoolss_Notify *data,
                                      print_queue_struct *queue,
                                      NT_PRINTER_INFO_LEVEL *printer,
                                      TALLOC_CTX *mem_ctx)
 {
-       data->notify_data.value[0]=nt_printj_status(queue->status);
-       data->notify_data.value[1] = 0;
+       SETUP_SPOOLSS_NOTIFY_DATA_INTEGER(data, nt_printj_status(queue->status));
 }
 
 /*******************************************************************
@@ -3317,25 +3265,12 @@ static void spoolss_notify_job_status(int snum,
  ********************************************************************/
 
 static void spoolss_notify_job_name(int snum,
-                                   SPOOL_NOTIFY_INFO_DATA *data,
+                                   struct spoolss_Notify *data,
                                    print_queue_struct *queue,
                                    NT_PRINTER_INFO_LEVEL *printer,
                                    TALLOC_CTX *mem_ctx)
 {
-       smb_ucs2_t *temp = NULL;
-       uint32 len;
-
-       len = rpcstr_push_talloc(mem_ctx, &temp, queue->fs_file);
-       if (len == (uint32)-1) {
-               len = 0;
-       }
-
-       data->notify_data.data.length = len;
-       if (len) {
-               data->notify_data.data.string = (uint16 *)temp;
-       } else {
-               data->notify_data.data.string = NULL;
-       }
+       SETUP_SPOOLSS_NOTIFY_DATA_STRING(data, queue->fs_file);
 }
 
 /*******************************************************************
@@ -3343,7 +3278,7 @@ static void spoolss_notify_job_name(int snum,
  ********************************************************************/
 
 static void spoolss_notify_job_status_string(int snum,
-                                            SPOOL_NOTIFY_INFO_DATA *data,
+                                            struct spoolss_Notify *data,
                                             print_queue_struct *queue,
                                             NT_PRINTER_INFO_LEVEL *printer,
                                             TALLOC_CTX *mem_ctx)
@@ -3353,8 +3288,6 @@ static void spoolss_notify_job_status_string(int snum,
         */
 
        const char *p = "";
-       smb_ucs2_t *temp = NULL;
-       uint32 len;
 
 #if 0 /* NO LONGER NEEDED - JRA. 02/22/2001 */
        p = "unknown";
@@ -3375,17 +3308,7 @@ static void spoolss_notify_job_status_string(int snum,
        }
 #endif /* NO LONGER NEEDED. */
 
-       len = rpcstr_push_talloc(mem_ctx, &temp, p);
-       if (len == (uint32)-1) {
-               len = 0;
-       }
-
-       data->notify_data.data.length = len;
-       if (len) {
-               data->notify_data.data.string = (uint16 *)temp;
-       } else {
-               data->notify_data.data.string = NULL;
-       }
+       SETUP_SPOOLSS_NOTIFY_DATA_STRING(data, p);
 }
 
 /*******************************************************************
@@ -3393,13 +3316,12 @@ static void spoolss_notify_job_status_string(int snum,
  ********************************************************************/
 
 static void spoolss_notify_job_time(int snum,
-                                   SPOOL_NOTIFY_INFO_DATA *data,
+                                   struct spoolss_Notify *data,
                                    print_queue_struct *queue,
                                    NT_PRINTER_INFO_LEVEL *printer,
                                    TALLOC_CTX *mem_ctx)
 {
-       data->notify_data.value[0]=0x0;
-       data->notify_data.value[1]=0;
+       SETUP_SPOOLSS_NOTIFY_DATA_INTEGER(data, 0);
 }
 
 /*******************************************************************
@@ -3407,39 +3329,37 @@ static void spoolss_notify_job_time(int snum,
  ********************************************************************/
 
 static void spoolss_notify_job_size(int snum,
-                                   SPOOL_NOTIFY_INFO_DATA *data,
+                                   struct spoolss_Notify *data,
                                    print_queue_struct *queue,
                                    NT_PRINTER_INFO_LEVEL *printer,
                                    TALLOC_CTX *mem_ctx)
 {
-       data->notify_data.value[0]=queue->size;
-       data->notify_data.value[1]=0;
+       SETUP_SPOOLSS_NOTIFY_DATA_INTEGER(data, queue->size);
 }
 
 /*******************************************************************
  * fill a notify_info_data with page info
  ********************************************************************/
 static void spoolss_notify_total_pages(int snum,
-                               SPOOL_NOTIFY_INFO_DATA *data,
+                               struct spoolss_Notify *data,
                                print_queue_struct *queue,
                                NT_PRINTER_INFO_LEVEL *printer,
                                TALLOC_CTX *mem_ctx)
 {
-       data->notify_data.value[0]=queue->page_count;
-       data->notify_data.value[1]=0;
+       SETUP_SPOOLSS_NOTIFY_DATA_INTEGER(data, queue->page_count);
 }
 
 /*******************************************************************
  * fill a notify_info_data with pages printed info.
  ********************************************************************/
 static void spoolss_notify_pages_printed(int snum,
-                               SPOOL_NOTIFY_INFO_DATA *data,
+                               struct spoolss_Notify *data,
                                print_queue_struct *queue,
                                NT_PRINTER_INFO_LEVEL *printer,
                                TALLOC_CTX *mem_ctx)
 {
-       data->notify_data.value[0]=0;  /* Add code when back-end tracks this */
-       data->notify_data.value[1]=0;
+       /* Add code when back-end tracks this */
+       SETUP_SPOOLSS_NOTIFY_DATA_INTEGER(data, 0);
 }
 
 /*******************************************************************
@@ -3447,13 +3367,12 @@ static void spoolss_notify_pages_printed(int snum,
  ********************************************************************/
 
 static void spoolss_notify_job_position(int snum,
-                                       SPOOL_NOTIFY_INFO_DATA *data,
+                                       struct spoolss_Notify *data,
                                        print_queue_struct *queue,
                                        NT_PRINTER_INFO_LEVEL *printer,
                                        TALLOC_CTX *mem_ctx)
 {
-       data->notify_data.value[0]=queue->job;
-       data->notify_data.value[1]=0;
+       SETUP_SPOOLSS_NOTIFY_DATA_INTEGER(data, queue->job);
 }
 
 /*******************************************************************
@@ -3461,53 +3380,27 @@ static void spoolss_notify_job_position(int snum,
  ********************************************************************/
 
 static void spoolss_notify_submitted_time(int snum,
-                                         SPOOL_NOTIFY_INFO_DATA *data,
+                                         struct spoolss_Notify *data,
                                          print_queue_struct *queue,
                                          NT_PRINTER_INFO_LEVEL *printer,
                                          TALLOC_CTX *mem_ctx)
 {
-       struct tm *t;
-       uint32 len;
-       SYSTEMTIME st;
-       char *p;
+       data->data.string.string = NULL;
+       data->data.string.size = 0;
 
-       t=gmtime(&queue->time);
+       init_systemtime_buffer(mem_ctx, gmtime(&queue->time),
+                              &data->data.string.string,
+                              &data->data.string.size);
 
-       len = sizeof(SYSTEMTIME);
-
-       data->notify_data.data.length = len;
-       data->notify_data.data.string = (uint16 *)TALLOC(mem_ctx, len);
-
-       if (!data->notify_data.data.string) {
-               data->notify_data.data.length = 0;
-               return;
-       }
-
-       make_systemtime(&st, t);
-
-       /*
-        * Systemtime must be linearized as a set of UINT16's.
-        * Fix from Benjamin (Bj) Kuit bj@it.uts.edu.au
-        */
-
-       p = (char *)data->notify_data.data.string;
-       SSVAL(p, 0, st.year);
-       SSVAL(p, 2, st.month);
-       SSVAL(p, 4, st.dayofweek);
-       SSVAL(p, 6, st.day);
-       SSVAL(p, 8, st.hour);
-        SSVAL(p, 10, st.minute);
-       SSVAL(p, 12, st.second);
-       SSVAL(p, 14, st.milliseconds);
 }
 
 struct s_notify_info_data_table
 {
-       uint16 type;
-       uint16 field;
+       enum spoolss_NotifyType type;
+       enum spoolss_Field field;
        const char *name;
-       uint32 size;
-       void (*fn) (int snum, SPOOL_NOTIFY_INFO_DATA *data,
+       enum spoolss_NotifyTable variable_type;
+       void (*fn) (int snum, struct spoolss_Notify *data,
                    print_queue_struct *queue,
                    NT_PRINTER_INFO_LEVEL *printer, TALLOC_CTX *mem_ctx);
 };
@@ -3518,86 +3411,70 @@ struct s_notify_info_data_table
 
 static const struct s_notify_info_data_table notify_info_data_table[] =
 {
-{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_SERVER_NAME,         "PRINTER_NOTIFY_SERVER_NAME",         NOTIFY_STRING,   spoolss_notify_server_name },
-{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_PRINTER_NAME,        "PRINTER_NOTIFY_PRINTER_NAME",        NOTIFY_STRING,   spoolss_notify_printer_name },
-{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_SHARE_NAME,          "PRINTER_NOTIFY_SHARE_NAME",          NOTIFY_STRING,   spoolss_notify_share_name },
-{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_PORT_NAME,           "PRINTER_NOTIFY_PORT_NAME",           NOTIFY_STRING,   spoolss_notify_port_name },
-{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_DRIVER_NAME,         "PRINTER_NOTIFY_DRIVER_NAME",         NOTIFY_STRING,   spoolss_notify_driver_name },
-{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_COMMENT,             "PRINTER_NOTIFY_COMMENT",             NOTIFY_STRING,   spoolss_notify_comment },
-{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_LOCATION,            "PRINTER_NOTIFY_LOCATION",            NOTIFY_STRING,   spoolss_notify_location },
-{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_DEVMODE,             "PRINTER_NOTIFY_DEVMODE",             NOTIFY_POINTER,   spoolss_notify_devmode },
-{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_SEPFILE,             "PRINTER_NOTIFY_SEPFILE",             NOTIFY_STRING,   spoolss_notify_sepfile },
-{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_PRINT_PROCESSOR,     "PRINTER_NOTIFY_PRINT_PROCESSOR",     NOTIFY_STRING,   spoolss_notify_print_processor },
-{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_PARAMETERS,          "PRINTER_NOTIFY_PARAMETERS",          NOTIFY_STRING,   spoolss_notify_parameters },
-{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_DATATYPE,            "PRINTER_NOTIFY_DATATYPE",            NOTIFY_STRING,   spoolss_notify_datatype },
-{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_SECURITY_DESCRIPTOR, "PRINTER_NOTIFY_SECURITY_DESCRIPTOR", NOTIFY_SECDESC,   spoolss_notify_security_desc },
-{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_ATTRIBUTES,          "PRINTER_NOTIFY_ATTRIBUTES",          NOTIFY_ONE_VALUE, spoolss_notify_attributes },
-{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_PRIORITY,            "PRINTER_NOTIFY_PRIORITY",            NOTIFY_ONE_VALUE, spoolss_notify_priority },
-{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_DEFAULT_PRIORITY,    "PRINTER_NOTIFY_DEFAULT_PRIORITY",    NOTIFY_ONE_VALUE, spoolss_notify_default_priority },
-{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_START_TIME,          "PRINTER_NOTIFY_START_TIME",          NOTIFY_ONE_VALUE, spoolss_notify_start_time },
-{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_UNTIL_TIME,          "PRINTER_NOTIFY_UNTIL_TIME",          NOTIFY_ONE_VALUE, spoolss_notify_until_time },
-{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_STATUS,              "PRINTER_NOTIFY_STATUS",              NOTIFY_ONE_VALUE, spoolss_notify_status },
-{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_STATUS_STRING,       "PRINTER_NOTIFY_STATUS_STRING",       NOTIFY_POINTER,   NULL },
-{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_CJOBS,               "PRINTER_NOTIFY_CJOBS",               NOTIFY_ONE_VALUE, spoolss_notify_cjobs },
-{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_AVERAGE_PPM,         "PRINTER_NOTIFY_AVERAGE_PPM",         NOTIFY_ONE_VALUE, spoolss_notify_average_ppm },
-{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_TOTAL_PAGES,         "PRINTER_NOTIFY_TOTAL_PAGES",         NOTIFY_POINTER,   NULL },
-{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_PAGES_PRINTED,       "PRINTER_NOTIFY_PAGES_PRINTED",       NOTIFY_POINTER,   NULL },
-{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_TOTAL_BYTES,         "PRINTER_NOTIFY_TOTAL_BYTES",         NOTIFY_POINTER,   NULL },
-{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_BYTES_PRINTED,       "PRINTER_NOTIFY_BYTES_PRINTED",       NOTIFY_POINTER,   NULL },
-{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_PRINTER_NAME,            "JOB_NOTIFY_PRINTER_NAME",            NOTIFY_STRING,   spoolss_notify_printer_name },
-{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_MACHINE_NAME,            "JOB_NOTIFY_MACHINE_NAME",            NOTIFY_STRING,   spoolss_notify_server_name },
-{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_PORT_NAME,               "JOB_NOTIFY_PORT_NAME",               NOTIFY_STRING,   spoolss_notify_port_name },
-{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_USER_NAME,               "JOB_NOTIFY_USER_NAME",               NOTIFY_STRING,   spoolss_notify_username },
-{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_NOTIFY_NAME,             "JOB_NOTIFY_NOTIFY_NAME",             NOTIFY_STRING,   spoolss_notify_username },
-{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_DATATYPE,                "JOB_NOTIFY_DATATYPE",                NOTIFY_STRING,   spoolss_notify_datatype },
-{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_PRINT_PROCESSOR,         "JOB_NOTIFY_PRINT_PROCESSOR",         NOTIFY_STRING,   spoolss_notify_print_processor },
-{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_PARAMETERS,              "JOB_NOTIFY_PARAMETERS",              NOTIFY_STRING,   spoolss_notify_parameters },
-{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_DRIVER_NAME,             "JOB_NOTIFY_DRIVER_NAME",             NOTIFY_STRING,   spoolss_notify_driver_name },
-{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_DEVMODE,                 "JOB_NOTIFY_DEVMODE",                 NOTIFY_POINTER,   spoolss_notify_devmode },
-{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_STATUS,                  "JOB_NOTIFY_STATUS",                  NOTIFY_ONE_VALUE, spoolss_notify_job_status },
-{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_STATUS_STRING,           "JOB_NOTIFY_STATUS_STRING",           NOTIFY_STRING,   spoolss_notify_job_status_string },
-{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_SECURITY_DESCRIPTOR,     "JOB_NOTIFY_SECURITY_DESCRIPTOR",     NOTIFY_POINTER,   NULL },
-{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_DOCUMENT,                "JOB_NOTIFY_DOCUMENT",                NOTIFY_STRING,   spoolss_notify_job_name },
-{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_PRIORITY,                "JOB_NOTIFY_PRIORITY",                NOTIFY_ONE_VALUE, spoolss_notify_priority },
-{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_POSITION,                "JOB_NOTIFY_POSITION",                NOTIFY_ONE_VALUE, spoolss_notify_job_position },
-{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_SUBMITTED,               "JOB_NOTIFY_SUBMITTED",               NOTIFY_POINTER,   spoolss_notify_submitted_time },
-{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_START_TIME,              "JOB_NOTIFY_START_TIME",              NOTIFY_ONE_VALUE, spoolss_notify_start_time },
-{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_UNTIL_TIME,              "JOB_NOTIFY_UNTIL_TIME",              NOTIFY_ONE_VALUE, spoolss_notify_until_time },
-{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_TIME,                    "JOB_NOTIFY_TIME",                    NOTIFY_ONE_VALUE, spoolss_notify_job_time },
-{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_TOTAL_PAGES,             "JOB_NOTIFY_TOTAL_PAGES",             NOTIFY_ONE_VALUE, spoolss_notify_total_pages },
-{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_PAGES_PRINTED,           "JOB_NOTIFY_PAGES_PRINTED",           NOTIFY_ONE_VALUE, spoolss_notify_pages_printed },
-{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_TOTAL_BYTES,             "JOB_NOTIFY_TOTAL_BYTES",             NOTIFY_ONE_VALUE, spoolss_notify_job_size },
-{ PRINT_TABLE_END, 0x0, NULL, 0x0, NULL },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_SERVER_NAME,         "PRINTER_NOTIFY_SERVER_NAME",         NOTIFY_TABLE_STRING,   spoolss_notify_server_name },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_PRINTER_NAME,        "PRINTER_NOTIFY_PRINTER_NAME",        NOTIFY_TABLE_STRING,   spoolss_notify_printer_name },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_SHARE_NAME,          "PRINTER_NOTIFY_SHARE_NAME",          NOTIFY_TABLE_STRING,   spoolss_notify_share_name },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_PORT_NAME,           "PRINTER_NOTIFY_PORT_NAME",           NOTIFY_TABLE_STRING,   spoolss_notify_port_name },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_DRIVER_NAME,         "PRINTER_NOTIFY_DRIVER_NAME",         NOTIFY_TABLE_STRING,   spoolss_notify_driver_name },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_COMMENT,             "PRINTER_NOTIFY_COMMENT",             NOTIFY_TABLE_STRING,   spoolss_notify_comment },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_LOCATION,            "PRINTER_NOTIFY_LOCATION",            NOTIFY_TABLE_STRING,   spoolss_notify_location },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_DEVMODE,             "PRINTER_NOTIFY_DEVMODE",             NOTIFY_TABLE_DEVMODE,  spoolss_notify_devmode },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_SEPFILE,             "PRINTER_NOTIFY_SEPFILE",             NOTIFY_TABLE_STRING,   spoolss_notify_sepfile },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_PRINT_PROCESSOR,     "PRINTER_NOTIFY_PRINT_PROCESSOR",     NOTIFY_TABLE_STRING,   spoolss_notify_print_processor },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_PARAMETERS,          "PRINTER_NOTIFY_PARAMETERS",          NOTIFY_TABLE_STRING,   spoolss_notify_parameters },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_DATATYPE,            "PRINTER_NOTIFY_DATATYPE",            NOTIFY_TABLE_STRING,   spoolss_notify_datatype },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_SECURITY_DESCRIPTOR, "PRINTER_NOTIFY_SECURITY_DESCRIPTOR", NOTIFY_TABLE_SECURITYDESCRIPTOR,   spoolss_notify_security_desc },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_ATTRIBUTES,          "PRINTER_NOTIFY_ATTRIBUTES",          NOTIFY_TABLE_DWORD,    spoolss_notify_attributes },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_PRIORITY,            "PRINTER_NOTIFY_PRIORITY",            NOTIFY_TABLE_DWORD,    spoolss_notify_priority },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_DEFAULT_PRIORITY,    "PRINTER_NOTIFY_DEFAULT_PRIORITY",    NOTIFY_TABLE_DWORD,    spoolss_notify_default_priority },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_START_TIME,          "PRINTER_NOTIFY_START_TIME",          NOTIFY_TABLE_DWORD,    spoolss_notify_start_time },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_UNTIL_TIME,          "PRINTER_NOTIFY_UNTIL_TIME",          NOTIFY_TABLE_DWORD,    spoolss_notify_until_time },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_STATUS,              "PRINTER_NOTIFY_STATUS",              NOTIFY_TABLE_DWORD,    spoolss_notify_status },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_STATUS_STRING,       "PRINTER_NOTIFY_STATUS_STRING",       NOTIFY_TABLE_STRING,   NULL },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_CJOBS,               "PRINTER_NOTIFY_CJOBS",               NOTIFY_TABLE_DWORD,    spoolss_notify_cjobs },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_AVERAGE_PPM,         "PRINTER_NOTIFY_AVERAGE_PPM",         NOTIFY_TABLE_DWORD,    spoolss_notify_average_ppm },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_TOTAL_PAGES,         "PRINTER_NOTIFY_TOTAL_PAGES",         NOTIFY_TABLE_DWORD,    NULL },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_PAGES_PRINTED,       "PRINTER_NOTIFY_PAGES_PRINTED",       NOTIFY_TABLE_DWORD,    NULL },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_TOTAL_BYTES,         "PRINTER_NOTIFY_TOTAL_BYTES",         NOTIFY_TABLE_DWORD,    NULL },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_BYTES_PRINTED,       "PRINTER_NOTIFY_BYTES_PRINTED",       NOTIFY_TABLE_DWORD,    NULL },
+{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_PRINTER_NAME,            "JOB_NOTIFY_PRINTER_NAME",            NOTIFY_TABLE_STRING,   spoolss_notify_printer_name },
+{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_MACHINE_NAME,            "JOB_NOTIFY_MACHINE_NAME",            NOTIFY_TABLE_STRING,   spoolss_notify_server_name },
+{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_PORT_NAME,               "JOB_NOTIFY_PORT_NAME",               NOTIFY_TABLE_STRING,   spoolss_notify_port_name },
+{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_USER_NAME,               "JOB_NOTIFY_USER_NAME",               NOTIFY_TABLE_STRING,   spoolss_notify_username },
+{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_NOTIFY_NAME,             "JOB_NOTIFY_NOTIFY_NAME",             NOTIFY_TABLE_STRING,   spoolss_notify_username },
+{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_DATATYPE,                "JOB_NOTIFY_DATATYPE",                NOTIFY_TABLE_STRING,   spoolss_notify_datatype },
+{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_PRINT_PROCESSOR,         "JOB_NOTIFY_PRINT_PROCESSOR",         NOTIFY_TABLE_STRING,   spoolss_notify_print_processor },
+{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_PARAMETERS,              "JOB_NOTIFY_PARAMETERS",              NOTIFY_TABLE_STRING,   spoolss_notify_parameters },
+{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_DRIVER_NAME,             "JOB_NOTIFY_DRIVER_NAME",             NOTIFY_TABLE_STRING,   spoolss_notify_driver_name },
+{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_DEVMODE,                 "JOB_NOTIFY_DEVMODE",                 NOTIFY_TABLE_DEVMODE,  spoolss_notify_devmode },
+{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_STATUS,                  "JOB_NOTIFY_STATUS",                  NOTIFY_TABLE_DWORD,    spoolss_notify_job_status },
+{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_STATUS_STRING,           "JOB_NOTIFY_STATUS_STRING",           NOTIFY_TABLE_STRING,   spoolss_notify_job_status_string },
+{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_SECURITY_DESCRIPTOR,     "JOB_NOTIFY_SECURITY_DESCRIPTOR",     NOTIFY_TABLE_SECURITYDESCRIPTOR,   NULL },
+{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_DOCUMENT,                "JOB_NOTIFY_DOCUMENT",                NOTIFY_TABLE_STRING,   spoolss_notify_job_name },
+{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_PRIORITY,                "JOB_NOTIFY_PRIORITY",                NOTIFY_TABLE_DWORD,    spoolss_notify_priority },
+{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_POSITION,                "JOB_NOTIFY_POSITION",                NOTIFY_TABLE_DWORD,    spoolss_notify_job_position },
+{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_SUBMITTED,               "JOB_NOTIFY_SUBMITTED",               NOTIFY_TABLE_TIME,     spoolss_notify_submitted_time },
+{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_START_TIME,              "JOB_NOTIFY_START_TIME",              NOTIFY_TABLE_DWORD,    spoolss_notify_start_time },
+{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_UNTIL_TIME,              "JOB_NOTIFY_UNTIL_TIME",              NOTIFY_TABLE_DWORD,    spoolss_notify_until_time },
+{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_TIME,                    "JOB_NOTIFY_TIME",                    NOTIFY_TABLE_DWORD,    spoolss_notify_job_time },
+{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_TOTAL_PAGES,             "JOB_NOTIFY_TOTAL_PAGES",             NOTIFY_TABLE_DWORD,    spoolss_notify_total_pages },
+{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_PAGES_PRINTED,           "JOB_NOTIFY_PAGES_PRINTED",           NOTIFY_TABLE_DWORD,    spoolss_notify_pages_printed },
+{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_TOTAL_BYTES,             "JOB_NOTIFY_TOTAL_BYTES",             NOTIFY_TABLE_DWORD,    spoolss_notify_job_size },
 };
 
 /*******************************************************************
- Return the size of info_data structure.
+ Return the variable_type of info_data structure.
 ********************************************************************/
 
-static uint32 size_of_notify_info_data(uint16 type, uint16 field)
+static uint32_t variable_type_of_notify_info_data(enum spoolss_NotifyType type,
+                                                 enum spoolss_Field field)
 {
        int i=0;
 
-       for (i = 0; i < (sizeof(notify_info_data_table)/sizeof(struct s_notify_info_data_table)); i++) {
-               if ( (notify_info_data_table[i].type == type)
-                       && (notify_info_data_table[i].field == field) ) {
-                       switch(notify_info_data_table[i].size) {
-                               case NOTIFY_ONE_VALUE:
-                               case NOTIFY_TWO_VALUE:
-                                       return 1;
-                               case NOTIFY_STRING:
-                                       return 2;
-
-                               /* The only pointer notify data I have seen on
-                                  the wire is the submitted time and this has
-                                  the notify size set to 4. -tpot */
-
-                               case NOTIFY_POINTER:
-                                       return 4;
-
-                               case NOTIFY_SECDESC:
-                                       return 5;
-                       }
+       for (i = 0; i < ARRAY_SIZE(notify_info_data_table); i++) {
+               if ( (notify_info_data_table[i].type == type) &&
+                    (notify_info_data_table[i].field == field) ) {
+                       return notify_info_data_table[i].variable_type;
                }
        }
 
@@ -3606,31 +3483,16 @@ static uint32 size_of_notify_info_data(uint16 type, uint16 field)
        return 0;
 }
 
-/*******************************************************************
- Return the type of notify_info_data.
-********************************************************************/
-
-static uint32 type_of_notify_info_data(uint16 type, uint16 field)
-{
-       uint32 i=0;
-
-       for (i = 0; i < (sizeof(notify_info_data_table)/sizeof(struct s_notify_info_data_table)); i++) {
-               if (notify_info_data_table[i].type == type &&
-                   notify_info_data_table[i].field == field)
-                       return notify_info_data_table[i].size;
-       }
-
-       return 0;
-}
-
 /****************************************************************************
 ****************************************************************************/
 
-static bool search_notify(uint16 type, uint16 field, int *value)
+static bool search_notify(enum spoolss_NotifyType type,
+                         enum spoolss_Field field,
+                         int *value)
 {
        int i;
 
-       for (i = 0; notify_info_data_table[i].type != PRINT_TABLE_END; i++) {
+       for (i = 0; i < ARRAY_SIZE(notify_info_data_table); i++) {
                if (notify_info_data_table[i].type == type &&
                    notify_info_data_table[i].field == field &&
                    notify_info_data_table[i].fn != NULL) {
@@ -3645,16 +3507,15 @@ static bool search_notify(uint16 type, uint16 field, int *value)
 /****************************************************************************
 ****************************************************************************/
 
-void construct_info_data(SPOOL_NOTIFY_INFO_DATA *info_data, uint16 type, uint16 field, int id)
+void construct_info_data(struct spoolss_Notify *info_data,
+                        enum spoolss_NotifyType type,
+                        enum spoolss_Field field,
+                        int id)
 {
-       info_data->type     = type;
-       info_data->field    = field;
-       info_data->reserved = 0;
-
-       info_data->size     = size_of_notify_info_data(type, field);
-       info_data->enc_type = type_of_notify_info_data(type, field);
-
-       info_data->id = id;
+       info_data->type                 = type;
+       info_data->field                = field;
+       info_data->variable_type        = variable_type_of_notify_info_data(type, field);
+       info_data->job_id               = id;
 }
 
 /*******************************************************************
@@ -3663,29 +3524,31 @@ void construct_info_data(SPOOL_NOTIFY_INFO_DATA *info_data, uint16 type, uint16
  *
  ********************************************************************/
 
-static bool construct_notify_printer_info(Printer_entry *print_hnd, SPOOL_NOTIFY_INFO *info, int
-                                         snum, SPOOL_NOTIFY_OPTION_TYPE
-                                         *option_type, uint32 id,
+static bool construct_notify_printer_info(Printer_entry *print_hnd,
+                                         struct spoolss_NotifyInfo *info,
+                                         int snum,
+                                         const struct spoolss_NotifyOptionType *option_type,
+                                         uint32_t id,
                                          TALLOC_CTX *mem_ctx)
 {
        int field_num,j;
-       uint16 type;
-       uint16 field;
+       enum spoolss_NotifyType type;
+       enum spoolss_Field field;
 
-       SPOOL_NOTIFY_INFO_DATA *current_data;
+       struct spoolss_Notify *current_data;
        NT_PRINTER_INFO_LEVEL *printer = NULL;
        print_queue_struct *queue=NULL;
 
-       type=option_type->type;
+       type = option_type->type;
 
        DEBUG(4,("construct_notify_printer_info: Notify type: [%s], number of notify info: [%d] on printer: [%s]\n",
-               (option_type->type==PRINTER_NOTIFY_TYPE?"PRINTER_NOTIFY_TYPE":"JOB_NOTIFY_TYPE"),
+               (type == PRINTER_NOTIFY_TYPE ? "PRINTER_NOTIFY_TYPE" : "JOB_NOTIFY_TYPE"),
                option_type->count, lp_servicename(snum)));
 
        if (!W_ERROR_IS_OK(get_a_printer(print_hnd, &printer, 2, lp_const_servicename(snum))))
                return False;
 
-       for(field_num=0; field_num<option_type->count; field_num++) {
+       for(field_num=0; field_num < option_type->count; field_num++) {
                field = option_type->fields[field_num];
 
                DEBUG(4,("construct_notify_printer_info: notify [%d]: type [%x], field [%x]\n", field_num, type, field));
@@ -3693,13 +3556,16 @@ static bool construct_notify_printer_info(Printer_entry *print_hnd, SPOOL_NOTIFY
                if (!search_notify(type, field, &j) )
                        continue;
 
-               if((info->data=SMB_REALLOC_ARRAY(info->data, SPOOL_NOTIFY_INFO_DATA, info->count+1)) == NULL) {
+               info->notifies = TALLOC_REALLOC_ARRAY(info, info->notifies,
+                                                     struct spoolss_Notify,
+                                                     info->count + 1);
+               if (info->notifies == NULL) {
                        DEBUG(2,("construct_notify_printer_info: failed to enlarge buffer info->data!\n"));
                        free_a_printer(&printer, 2);
                        return False;
                }
 
-               current_data = &info->data[info->count];
+               current_data = &info->notifies[info->count];
 
                construct_info_data(current_data, type, field, id);
 
@@ -3723,24 +3589,24 @@ static bool construct_notify_printer_info(Printer_entry *print_hnd, SPOOL_NOTIFY
  ********************************************************************/
 
 static bool construct_notify_jobs_info(print_queue_struct *queue,
-                                      SPOOL_NOTIFY_INFO *info,
+                                      struct spoolss_NotifyInfo *info,
                                       NT_PRINTER_INFO_LEVEL *printer,
-                                      int snum, SPOOL_NOTIFY_OPTION_TYPE
-                                      *option_type, uint32 id,
+                                      int snum,
+                                      const struct spoolss_NotifyOptionType *option_type,
+                                      uint32_t id,
                                       TALLOC_CTX *mem_ctx)
 {
        int field_num,j;
-       uint16 type;
-       uint16 field;
-
-       SPOOL_NOTIFY_INFO_DATA *current_data;
+       enum spoolss_NotifyType type;
+       enum spoolss_Field field;
+       struct spoolss_Notify *current_data;
 
        DEBUG(4,("construct_notify_jobs_info\n"));
 
        type = option_type->type;
 
        DEBUGADD(4,("Notify type: [%s], number of notify info: [%d]\n",
-               (option_type->type==PRINTER_NOTIFY_TYPE?"PRINTER_NOTIFY_TYPE":"JOB_NOTIFY_TYPE"),
+               (type == PRINTER_NOTIFY_TYPE ? "PRINTER_NOTIFY_TYPE" : "JOB_NOTIFY_TYPE"),
                option_type->count));
 
        for(field_num=0; field_num<option_type->count; field_num++) {
@@ -3749,12 +3615,15 @@ static bool construct_notify_jobs_info(print_queue_struct *queue,
                if (!search_notify(type, field, &j) )
                        continue;
 
-               if((info->data=SMB_REALLOC_ARRAY(info->data, SPOOL_NOTIFY_INFO_DATA, info->count+1)) == NULL) {
+               info->notifies = TALLOC_REALLOC_ARRAY(info, info->notifies,
+                                                     struct spoolss_Notify,
+                                                     info->count + 1);
+               if (info->notifies == NULL) {
                        DEBUG(2,("construct_notify_jobs_info: failed to enlarg buffer info->data!\n"));
                        return False;
                }
 
-               current_data=&(info->data[info->count]);
+               current_data=&(info->notifies[info->count]);
 
                construct_info_data(current_data, type, field, id);
                notify_info_data_table[j].fn(snum, current_data, queue,
@@ -3796,25 +3665,26 @@ static bool construct_notify_jobs_info(print_queue_struct *queue,
  ********************************************************************/
 
 static WERROR printserver_notify_info(pipes_struct *p, POLICY_HND *hnd,
-                                     SPOOL_NOTIFY_INFO *info,
+                                     struct spoolss_NotifyInfo *info,
                                      TALLOC_CTX *mem_ctx)
 {
        int snum;
        Printer_entry *Printer=find_printer_index_by_hnd(p, hnd);
        int n_services=lp_numservices();
        int i;
-       SPOOL_NOTIFY_OPTION *option;
-       SPOOL_NOTIFY_OPTION_TYPE *option_type;
+       struct spoolss_NotifyOption *option;
+       struct spoolss_NotifyOptionType option_type;
 
        DEBUG(4,("printserver_notify_info\n"));
 
        if (!Printer)
                return WERR_BADFID;
 
-       option=Printer->notify.option;
-       info->version=2;
-       info->data=NULL;
-       info->count=0;
+       option = Printer->notify.option;
+
+       info->version   = 2;
+       info->notifies  = NULL;
+       info->count     = 0;
 
        /* a bug in xp sp2 rc2 causes it to send a fnpcn request without
           sending a ffpcn() request first */
@@ -3823,15 +3693,15 @@ static WERROR printserver_notify_info(pipes_struct *p, POLICY_HND *hnd,
                return WERR_BADFID;
 
        for (i=0; i<option->count; i++) {
-               option_type=&(option->ctr.type[i]);
+               option_type = option->types[i];
 
-               if (option_type->type!=PRINTER_NOTIFY_TYPE)
+               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) )
-                               construct_notify_printer_info ( Printer, info, snum, option_type, snum, mem_ctx );
+                               construct_notify_printer_info ( Printer, info, snum, &option_type, snum, mem_ctx );
                }
        }
 
@@ -3860,15 +3730,15 @@ static WERROR printserver_notify_info(pipes_struct *p, POLICY_HND *hnd,
  *
  ********************************************************************/
 
-static WERROR printer_notify_info(pipes_struct *p, POLICY_HND *hnd, SPOOL_NOTIFY_INFO *info,
+static WERROR printer_notify_info(pipes_struct *p, POLICY_HND *hnd, struct spoolss_NotifyInfo *info,
                                  TALLOC_CTX *mem_ctx)
 {
        int snum;
        Printer_entry *Printer=find_printer_index_by_hnd(p, hnd);
        int i;
        uint32 id;
-       SPOOL_NOTIFY_OPTION *option;
-       SPOOL_NOTIFY_OPTION_TYPE *option_type;
+       struct spoolss_NotifyOption *option;
+       struct spoolss_NotifyOptionType option_type;
        int count,j;
        print_queue_struct *queue=NULL;
        print_status_struct status;
@@ -3878,11 +3748,12 @@ static WERROR printer_notify_info(pipes_struct *p, POLICY_HND *hnd, SPOOL_NOTIFY
        if (!Printer)
                return WERR_BADFID;
 
-       option=Printer->notify.option;
+       option = Printer->notify.option;
        id = 0x0;
-       info->version=2;
-       info->data=NULL;
-       info->count=0;
+
+       info->version   = 2;
+       info->notifies  = NULL;
+       info->count     = 0;
 
        /* a bug in xp sp2 rc2 causes it to send a fnpcn request without
           sending a ffpcn() request first */
@@ -3893,12 +3764,12 @@ static WERROR printer_notify_info(pipes_struct *p, POLICY_HND *hnd, SPOOL_NOTIFY
        get_printer_snum(p, hnd, &snum, NULL);
 
        for (i=0; i<option->count; i++) {
-               option_type=&option->ctr.type[i];
+               option_type = option->types[i];
 
-               switch ( option_type->type ) {
+               switch (option_type.type) {
                case PRINTER_NOTIFY_TYPE:
                        if(construct_notify_printer_info(Printer, info, snum,
-                                                        option_type, id,
+                                                        &option_type, id,
                                                         mem_ctx))
                                id--;
                        break;
@@ -3914,7 +3785,7 @@ static WERROR printer_notify_info(pipes_struct *p, POLICY_HND *hnd, SPOOL_NOTIFY
                        for (j=0; j<count; j++) {
                                construct_notify_jobs_info(&queue[j], info,
                                                           printer, snum,
-                                                          option_type,
+                                                          &option_type,
                                                           queue[j].job,
                                                           mem_ctx);
                        }
@@ -3945,24 +3816,31 @@ static WERROR printer_notify_info(pipes_struct *p, POLICY_HND *hnd, SPOOL_NOTIFY
        return WERR_OK;
 }
 
-/********************************************************************
- * spoolss_rfnpcnex
- ********************************************************************/
+/****************************************************************
+ _spoolss_RouterRefreshPrinterChangeNotify
+****************************************************************/
 
-WERROR _spoolss_rfnpcnex( pipes_struct *p, SPOOL_Q_RFNPCNEX *q_u, SPOOL_R_RFNPCNEX *r_u)
+WERROR _spoolss_RouterRefreshPrinterChangeNotify(pipes_struct *p,
+                                                struct spoolss_RouterRefreshPrinterChangeNotify *r)
 {
-       POLICY_HND *handle = &q_u->handle;
-       SPOOL_NOTIFY_INFO *info = &r_u->info;
+       POLICY_HND *handle = r->in.handle;
+       struct spoolss_NotifyInfo *info;
 
        Printer_entry *Printer=find_printer_index_by_hnd(p, handle);
        WERROR result = WERR_BADFID;
 
-       /* we always have a NOTIFY_INFO struct */
-       r_u->info_ptr=0x1;
+       /* we always have a spoolss_NotifyInfo struct */
+       info = talloc_zero(p->mem_ctx, struct spoolss_NotifyInfo);
+       if (!info) {
+               result = WERR_NOMEM;
+               goto done;
+       }
+
+       *r->out.info = info;
 
        if (!Printer) {
-               DEBUG(2,("_spoolss_rfnpcnex: Invalid handle (%s:%u:%u).\n",
-                        OUR_HANDLE(handle)));
+               DEBUG(2,("_spoolss_RouterRefreshPrinterChangeNotify: "
+                       "Invalid handle (%s:%u:%u).\n", OUR_HANDLE(handle)));
                goto done;
        }
 
@@ -3981,11 +3859,13 @@ WERROR _spoolss_rfnpcnex( pipes_struct *p, SPOOL_Q_RFNPCNEX *q_u, SPOOL_R_RFNPCN
        Printer->notify.fnpcn = True;
 
        if (Printer->notify.client_connected) {
-               DEBUG(10,("_spoolss_rfnpcnex: Saving change value in request [%x]\n", q_u->change));
-               Printer->notify.change = q_u->change;
+               DEBUG(10,("_spoolss_RouterRefreshPrinterChangeNotify: "
+                       "Saving change value in request [%x]\n",
+                       r->in.change_low));
+               Printer->notify.change = r->in.change_low;
        }
 
-       /* just ignore the SPOOL_NOTIFY_OPTION */
+       /* just ignore the spoolss_NotifyOption */
 
        switch (Printer->printer_type) {
                case SPLHND_SERVER:
@@ -4008,162 +3888,161 @@ done:
  * fill a printer_info_0 struct
  ********************************************************************/
 
-static bool construct_printer_info_0(Printer_entry *print_hnd, PRINTER_INFO_0 *printer, int snum)
+static WERROR construct_printer_info0(TALLOC_CTX *mem_ctx,
+                                     const NT_PRINTER_INFO_LEVEL *ntprinter,
+                                     struct spoolss_PrinterInfo0 *r,
+                                     int snum)
 {
-       char *chaine = NULL;
        int count;
-       NT_PRINTER_INFO_LEVEL *ntprinter = NULL;
        counter_printer_0 *session_counter;
-       uint32 global_counter;
-       struct tm *t;
        time_t setuptime;
        print_status_struct status;
-       TALLOC_CTX *ctx = talloc_tos();
-
-       if (!W_ERROR_IS_OK(get_a_printer(print_hnd, &ntprinter, 2, lp_const_servicename(snum))))
-               return False;
 
-       init_unistr(&printer->printername, ntprinter->info_2->printername);
+       r->printername          = talloc_strdup(mem_ctx, ntprinter->info_2->printername);
+       W_ERROR_HAVE_NO_MEMORY(r->printername);
 
-       chaine = talloc_asprintf(ctx, "\\\\%s", get_server_name(print_hnd));
-       if (!chaine) {
-               free_a_printer(&ntprinter,2);
-               return false;
-       }
+       r->servername           = talloc_strdup(mem_ctx, ntprinter->info_2->servername);
+       W_ERROR_HAVE_NO_MEMORY(r->servername);
 
        count = print_queue_length(snum, &status);
 
        /* check if we already have a counter for this printer */
-       for(session_counter = counter_list; session_counter; session_counter = session_counter->next) {
+       for (session_counter = counter_list; session_counter; session_counter = session_counter->next) {
                if (session_counter->snum == snum)
                        break;
        }
 
-       init_unistr(&printer->servername, chaine);
-
        /* it's the first time, add it to the list */
-       if (session_counter==NULL) {
-               if((session_counter=SMB_MALLOC_P(counter_printer_0)) == NULL) {
-                       free_a_printer(&ntprinter, 2);
-                       return False;
-               }
+       if (session_counter == NULL) {
+               session_counter = SMB_MALLOC_P(counter_printer_0);
+               W_ERROR_HAVE_NO_MEMORY(session_counter);
                ZERO_STRUCTP(session_counter);
-               session_counter->snum=snum;
-               session_counter->counter=0;
+               session_counter->snum           = snum;
+               session_counter->counter        = 0;
                DLIST_ADD(counter_list, session_counter);
        }
 
        /* increment it */
        session_counter->counter++;
 
+       r->cjobs                        = count;
+       r->total_jobs                   = 0;
+       r->total_bytes                  = 0;
+
+       setuptime = (time_t)ntprinter->info_2->setuptime;
+
+       init_systemtime(&r->time, gmtime(&setuptime));
+
        /* 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;
-       printer->cjobs = count;
-       printer->total_jobs = 0;
-       printer->total_bytes = 0;
+       r->global_counter               = session_counter->counter;
+       r->total_pages                  = 0;
+       /* in 2.2 we reported ourselves as 0x0004 and 0x0565 */
+       r->version                      = 0x0005;       /* NT 5 */
+       r->free_build                   = 0x0893;       /* build 2195 */
+       r->spooling                     = 0;
+       r->max_spooling                 = 0;
+       r->session_counter              = session_counter->counter;
+       r->num_error_out_of_paper       = 0x0;
+       r->num_error_not_ready          = 0x0;          /* number of print failure */
+       r->job_error                    = 0x0;
+       r->number_of_processors         = 0x1;
+       r->processor_type               = PROCESSOR_INTEL_PENTIUM; /* 586 Pentium ? */
+       r->high_part_total_bytes        = 0x0;
+       r->change_id                    = ntprinter->info_2->changeid; /* ChangeID in milliseconds*/
+       r->last_error                   = WERR_OK;
+       r->status                       = nt_printq_status(status.status);
+       r->enumerate_network_printers   = 0x0;
+       r->c_setprinter                 = get_c_setprinter(); /* monotonically increasing sum of delta printer counts */
+       r->processor_architecture       = 0x0;
+       r->processor_level              = 0x6;          /* 6  ???*/
+       r->ref_ic                       = 0;
+       r->reserved2                    = 0;
+       r->reserved3                    = 0;
 
-       setuptime = (time_t)ntprinter->info_2->setuptime;
-       t=gmtime(&setuptime);
+       return WERR_OK;
+}
 
-       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;
+/****************************************************************************
+ Free a DEVMODE struct.
+****************************************************************************/
 
-       printer->global_counter = global_counter;
-       printer->total_pages = 0;
+static void free_dev_mode(DEVICEMODE *dev)
+{
+       if (dev == NULL)
+               return;
 
-       /* in 2.2 we reported ourselves as 0x0004 and 0x0565 */
-       printer->major_version = 0x0005;        /* NT 5 */
-       printer->build_version = 0x0893;        /* build 2195 */
-
-       printer->unknown7 = 0x1;
-       printer->unknown8 = 0x0;
-       printer->unknown9 = 0x0;
-       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 = nt_printq_status(status.status);
-       printer->unknown20 =  0x0;
-       printer->c_setprinter = get_c_setprinter(); /* monotonically increasing sum of delta printer counts */
-       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;
-
-       free_a_printer(&ntprinter,2);
-       return (True);
-}
-
-/********************************************************************
- * construct_printer_info_1
- * fill a printer_info_1 struct
- ********************************************************************/
-static bool construct_printer_info_1(Printer_entry *print_hnd, uint32 flags, PRINTER_INFO_1 *printer, int snum)
-{
-       char *chaine = NULL;
-       NT_PRINTER_INFO_LEVEL *ntprinter = NULL;
-       TALLOC_CTX *ctx = talloc_tos();
-
-       if (!W_ERROR_IS_OK(get_a_printer(print_hnd, &ntprinter, 2, lp_const_servicename(snum))))
-               return false;
-
-       printer->flags=flags;
-
-       if (*ntprinter->info_2->comment == '\0') {
-               init_unistr(&printer->comment, lp_comment(snum));
-               chaine = talloc_asprintf(ctx,
-                               "%s,%s,%s", ntprinter->info_2->printername,
-                               ntprinter->info_2->drivername, lp_comment(snum));
-       }
-       else {
-               init_unistr(&printer->comment, ntprinter->info_2->comment); /* saved comment. */
-               chaine = talloc_asprintf(ctx,
-                               "%s,%s,%s", ntprinter->info_2->printername,
-                               ntprinter->info_2->drivername, ntprinter->info_2->comment);
-       }
-
-       if (!chaine) {
-               free_a_printer(&ntprinter,2);
-               return false;
-       }
-
-       init_unistr(&printer->description, chaine);
-       init_unistr(&printer->name, ntprinter->info_2->printername);
-
-       free_a_printer(&ntprinter,2);
-
-       return True;
+       SAFE_FREE(dev->dev_private);
+       SAFE_FREE(dev);
 }
 
 /****************************************************************************
- Free a DEVMODE struct.
+ Convert an NT_DEVICEMODE to a spoolss_DeviceMode structure.  Both pointers
+ should be valid upon entry
 ****************************************************************************/
 
-static void free_dev_mode(DEVICEMODE *dev)
+static WERROR convert_nt_devicemode_new(TALLOC_CTX *mem_ctx,
+                                       struct spoolss_DeviceMode *r,
+                                       const NT_DEVICEMODE *ntdevmode)
 {
-       if (dev == NULL)
-               return;
+       if (!r || !ntdevmode) {
+               return WERR_INVALID_PARAM;
+       }
 
-       SAFE_FREE(dev->dev_private);
-       SAFE_FREE(dev);
+       r->devicename           = talloc_strdup(mem_ctx, ntdevmode->devicename);
+       W_ERROR_HAVE_NO_MEMORY(r->devicename);
+
+       r->specversion          = ntdevmode->specversion;
+       r->driverversion        = ntdevmode->driverversion;
+       r->size                 = ntdevmode->size;
+       r->__driverextra_length = ntdevmode->driverextra;
+       r->fields               = ntdevmode->fields;
+
+       r->orientation          = ntdevmode->orientation;
+       r->papersize            = ntdevmode->papersize;
+       r->paperlength          = ntdevmode->paperlength;
+       r->paperwidth           = ntdevmode->paperwidth;
+       r->scale                = ntdevmode->scale;
+       r->copies               = ntdevmode->copies;
+       r->defaultsource        = ntdevmode->defaultsource;
+       r->printquality         = ntdevmode->printquality;
+       r->color                = ntdevmode->color;
+       r->duplex               = ntdevmode->duplex;
+       r->yresolution          = ntdevmode->yresolution;
+       r->ttoption             = ntdevmode->ttoption;
+       r->collate              = ntdevmode->collate;
+
+       r->formname             = talloc_strdup(mem_ctx, ntdevmode->formname);
+       W_ERROR_HAVE_NO_MEMORY(r->formname);
+
+       /* all 0 below are values that have not been set in the old parsing/copy
+        * function, maybe they should... - gd */
+
+       r->logpixels            = 0;
+       r->bitsperpel           = 0;
+       r->pelswidth            = 0;
+       r->pelsheight           = 0;
+       r->displayflags         = 0;
+       r->displayfrequency     = 0;
+       r->icmmethod            = ntdevmode->icmmethod;
+       r->icmintent            = ntdevmode->icmintent;
+       r->mediatype            = ntdevmode->mediatype;
+       r->dithertype           = ntdevmode->dithertype;
+       r->reserved1            = 0;
+       r->reserved2            = 0;
+       r->panningwidth         = 0;
+       r->panningheight        = 0;
+
+       if (ntdevmode->nt_dev_private != NULL) {
+               r->driverextra_data = data_blob_talloc(mem_ctx,
+                       ntdevmode->nt_dev_private,
+                       ntdevmode->driverextra);
+               W_ERROR_HAVE_NO_MEMORY(r->driverextra_data.data);
+       }
+
+       return WERR_OK;
 }
 
 
@@ -4213,6 +4092,48 @@ static bool convert_nt_devicemode( DEVICEMODE *devmode, NT_DEVICEMODE *ntdevmode
        return True;
 }
 
+/****************************************************************************
+ Create a spoolss_DeviceMode struct. Returns talloced memory.
+****************************************************************************/
+
+struct spoolss_DeviceMode *construct_dev_mode_new(TALLOC_CTX *mem_ctx,
+                                                 const char *servicename)
+{
+       WERROR result;
+       NT_PRINTER_INFO_LEVEL   *printer = NULL;
+       struct spoolss_DeviceMode *devmode = NULL;
+
+       DEBUG(7,("construct_dev_mode_new\n"));
+
+       DEBUGADD(8,("getting printer characteristics\n"));
+
+       if (!W_ERROR_IS_OK(get_a_printer(NULL, &printer, 2, servicename)))
+               return NULL;
+
+       if (!printer->info_2->devmode) {
+               DEBUG(5, ("BONG! There was no device mode!\n"));
+               goto done;
+       }
+
+       devmode = TALLOC_ZERO_P(mem_ctx, struct spoolss_DeviceMode);
+       if (!devmode) {
+               DEBUG(2,("construct_dev_mode_new: talloc fail.\n"));
+               goto done;
+       }
+
+       DEBUGADD(8,("loading DEVICEMODE\n"));
+
+       result = convert_nt_devicemode_new(mem_ctx, devmode, printer->info_2->devmode);
+       if (!W_ERROR_IS_OK(result)) {
+               TALLOC_FREE(devmode);
+       }
+
+done:
+       free_a_printer(&printer,2);
+
+       return devmode;
+}
+
 /****************************************************************************
  Create a DEVMODE struct. Returns malloced memory.
 ****************************************************************************/
@@ -4255,298 +4176,336 @@ done:
 }
 
 /********************************************************************
- * construct_printer_info_2
- * fill a printer_info_2 struct
+ * construct_printer_info3
+ * fill a spoolss_PrinterInfo3 struct
  ********************************************************************/
 
-static bool construct_printer_info_2(Printer_entry *print_hnd, PRINTER_INFO_2 *printer, int snum)
+static WERROR construct_printer_info3(TALLOC_CTX *mem_ctx,
+                                     const NT_PRINTER_INFO_LEVEL *ntprinter,
+                                     struct spoolss_PrinterInfo3 *r,
+                                     int snum)
 {
-       int count;
-       NT_PRINTER_INFO_LEVEL *ntprinter = NULL;
-
-       print_status_struct status;
-
-       if (!W_ERROR_IS_OK(get_a_printer(print_hnd, &ntprinter, 2, lp_const_servicename(snum))))
-               return False;
-
-       count = print_queue_length(snum, &status);
-
-       init_unistr(&printer->servername, ntprinter->info_2->servername); /* servername*/
-       init_unistr(&printer->printername, ntprinter->info_2->printername);                             /* printername*/
-       init_unistr(&printer->sharename, lp_servicename(snum));                 /* sharename */
-       init_unistr(&printer->portname, ntprinter->info_2->portname);                   /* port */
-       init_unistr(&printer->drivername, ntprinter->info_2->drivername);       /* drivername */
-
-       if (*ntprinter->info_2->comment == '\0')
-               init_unistr(&printer->comment, lp_comment(snum));                       /* comment */
-       else
-               init_unistr(&printer->comment, ntprinter->info_2->comment); /* saved 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 = ntprinter->info_2->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 = nt_printq_status(status.status);                      /* status */
-       printer->cjobs = count;                                                 /* jobs */
-       printer->averageppm = ntprinter->info_2->averageppm;                    /* average pages per minute */
-
-       if ( !(printer->devmode = construct_dev_mode(
-                      lp_const_servicename(snum))) )
-               DEBUG(8, ("Returning NULL Devicemode!\n"));
-
-       printer->secdesc = NULL;
+       /* These are the components of the SD we are returning. */
 
-       if ( ntprinter->info_2->secdesc_buf
-               && ntprinter->info_2->secdesc_buf->sd_size != 0 )
-       {
+       if (ntprinter->info_2->secdesc_buf && ntprinter->info_2->secdesc_buf->sd_size != 0) {
                /* don't use talloc_steal() here unless you do a deep steal of all
                   the SEC_DESC members */
 
-               printer->secdesc = dup_sec_desc( talloc_tos(),
-                       ntprinter->info_2->secdesc_buf->sd );
+               r->secdesc = dup_sec_desc(mem_ctx,
+                                         ntprinter->info_2->secdesc_buf->sd);
+               W_ERROR_HAVE_NO_MEMORY(r->secdesc);
        }
 
-       free_a_printer(&ntprinter, 2);
-
-       return True;
+       return WERR_OK;
 }
 
 /********************************************************************
- * construct_printer_info_3
- * fill a printer_info_3 struct
+ * construct_printer_info4
+ * fill a spoolss_PrinterInfo4 struct
  ********************************************************************/
 
-static bool construct_printer_info_3(Printer_entry *print_hnd, PRINTER_INFO_3 **pp_printer, int snum)
+static WERROR construct_printer_info4(TALLOC_CTX *mem_ctx,
+                                     const NT_PRINTER_INFO_LEVEL *ntprinter,
+                                     struct spoolss_PrinterInfo4 *r,
+                                     int snum)
 {
-       NT_PRINTER_INFO_LEVEL *ntprinter = NULL;
-       PRINTER_INFO_3 *printer = NULL;
+       r->printername  = talloc_strdup(mem_ctx, ntprinter->info_2->printername);
+       W_ERROR_HAVE_NO_MEMORY(r->printername);
+       r->servername   = talloc_strdup(mem_ctx, ntprinter->info_2->servername);
+       W_ERROR_HAVE_NO_MEMORY(r->servername);
 
-       if (!W_ERROR_IS_OK(get_a_printer(print_hnd, &ntprinter, 2, lp_const_servicename(snum))))
-               return False;
+       r->attributes   = ntprinter->info_2->attributes;
 
-       *pp_printer = NULL;
-       if ((printer = SMB_MALLOC_P(PRINTER_INFO_3)) == NULL) {
-               DEBUG(2,("construct_printer_info_3: malloc fail.\n"));
-               free_a_printer(&ntprinter, 2);
-               return False;
-       }
+       return WERR_OK;
+}
 
-       ZERO_STRUCTP(printer);
+/********************************************************************
+ * construct_printer_info5
+ * fill a spoolss_PrinterInfo5 struct
+ ********************************************************************/
 
-       /* These are the components of the SD we are returning. */
+static WERROR construct_printer_info5(TALLOC_CTX *mem_ctx,
+                                     const NT_PRINTER_INFO_LEVEL *ntprinter,
+                                     struct spoolss_PrinterInfo5 *r,
+                                     int snum)
+{
+       r->printername  = talloc_strdup(mem_ctx, ntprinter->info_2->printername);
+       W_ERROR_HAVE_NO_MEMORY(r->printername);
+       r->portname     = talloc_strdup(mem_ctx, ntprinter->info_2->portname);
+       W_ERROR_HAVE_NO_MEMORY(r->portname);
 
-       if (ntprinter->info_2->secdesc_buf && ntprinter->info_2->secdesc_buf->sd_size != 0) {
-               /* don't use talloc_steal() here unless you do a deep steal of all
-                  the SEC_DESC members */
+       r->attributes   = ntprinter->info_2->attributes;
 
-               printer->secdesc = dup_sec_desc( talloc_tos(),
-                       ntprinter->info_2->secdesc_buf->sd );
-       }
+       /* these two are not used by NT+ according to MSDN */
 
-       free_a_printer(&ntprinter, 2);
+       r->device_not_selected_timeout          = 0x0;  /* have seen 0x3a98 */
+       r->transmission_retry_timeout           = 0x0;  /* have seen 0xafc8 */
 
-       *pp_printer = printer;
-       return True;
+       return WERR_OK;
 }
 
 /********************************************************************
- * construct_printer_info_4
- * fill a printer_info_4 struct
+ * construct_printer_info_6
+ * fill a spoolss_PrinterInfo6 struct
  ********************************************************************/
 
-static bool construct_printer_info_4(Printer_entry *print_hnd, PRINTER_INFO_4 *printer, int snum)
+static WERROR construct_printer_info6(TALLOC_CTX *mem_ctx,
+                                     const NT_PRINTER_INFO_LEVEL *ntprinter,
+                                     struct spoolss_PrinterInfo6 *r,
+                                     int snum)
 {
-       NT_PRINTER_INFO_LEVEL *ntprinter = NULL;
+       int count;
+       print_status_struct status;
 
-       if (!W_ERROR_IS_OK(get_a_printer(print_hnd, &ntprinter, 2, lp_const_servicename(snum))))
-               return False;
+       count = print_queue_length(snum, &status);
 
-       init_unistr(&printer->printername, ntprinter->info_2->printername);                             /* printername*/
-       init_unistr(&printer->servername, ntprinter->info_2->servername); /* servername*/
-       printer->attributes = ntprinter->info_2->attributes;
+       r->status = nt_printq_status(status.status);
 
-       free_a_printer(&ntprinter, 2);
-       return True;
+       return WERR_OK;
 }
 
 /********************************************************************
- * construct_printer_info_5
- * fill a printer_info_5 struct
+ * construct_printer_info7
+ * fill a spoolss_PrinterInfo7 struct
  ********************************************************************/
 
-static bool construct_printer_info_5(Printer_entry *print_hnd, PRINTER_INFO_5 *printer, int snum)
+static WERROR construct_printer_info7(TALLOC_CTX *mem_ctx,
+                                     Printer_entry *print_hnd,
+                                     struct spoolss_PrinterInfo7 *r,
+                                     int snum)
 {
-       NT_PRINTER_INFO_LEVEL *ntprinter = NULL;
+       struct GUID guid;
 
-       if (!W_ERROR_IS_OK(get_a_printer(print_hnd, &ntprinter, 2, lp_const_servicename(snum))))
-               return False;
+       if (is_printer_published(print_hnd, snum, &guid)) {
+               r->guid = talloc_strdup_upper(mem_ctx, GUID_string2(mem_ctx, &guid));
+               r->action = DSPRINT_PUBLISH;
+       } else {
+               r->guid = talloc_strdup(mem_ctx, "");
+               r->action = DSPRINT_UNPUBLISH;
+       }
+       W_ERROR_HAVE_NO_MEMORY(r->guid);
 
-       init_unistr(&printer->printername, ntprinter->info_2->printername);
-       init_unistr(&printer->portname, ntprinter->info_2->portname);
-       printer->attributes = ntprinter->info_2->attributes;
+       return WERR_OK;
+}
 
-       /* these two are not used by NT+ according to MSDN */
+/********************************************************************
+ * construct_printer_info1
+ * fill a spoolss_PrinterInfo1 struct
+********************************************************************/
 
-       printer->device_not_selected_timeout = 0x0;  /* have seen 0x3a98 */
-       printer->transmission_retry_timeout  = 0x0;  /* have seen 0xafc8 */
+static WERROR construct_printer_info1(TALLOC_CTX *mem_ctx,
+                                     const NT_PRINTER_INFO_LEVEL *ntprinter,
+                                     uint32_t flags,
+                                     struct spoolss_PrinterInfo1 *r,
+                                     int snum)
+{
+       char *chaine = NULL;
+       r->flags                = flags;
 
-       free_a_printer(&ntprinter, 2);
+       if (*ntprinter->info_2->comment == '\0') {
+               r->comment      = talloc_strdup(mem_ctx, lp_comment(snum));
+               chaine = talloc_asprintf(mem_ctx,
+                               "%s,%s,%s", ntprinter->info_2->printername,
+                               ntprinter->info_2->drivername, lp_comment(snum));
+       } else {
+               r->comment      = talloc_strdup(mem_ctx, ntprinter->info_2->comment); /* saved comment */
+               chaine = talloc_asprintf(mem_ctx,
+                               "%s,%s,%s", ntprinter->info_2->printername,
+                               ntprinter->info_2->drivername, ntprinter->info_2->comment);
+       }
+       W_ERROR_HAVE_NO_MEMORY(chaine);
+       W_ERROR_HAVE_NO_MEMORY(r->comment);
 
-       return True;
+       r->description          = talloc_strdup(mem_ctx, chaine);
+       W_ERROR_HAVE_NO_MEMORY(r->description);
+       r->name                 = talloc_strdup(mem_ctx, ntprinter->info_2->printername);
+       W_ERROR_HAVE_NO_MEMORY(r->name);
+
+       return WERR_OK;
 }
 
 /********************************************************************
- * construct_printer_info_6
- * fill a printer_info_6 struct
- ********************************************************************/
+ * construct_printer_info2
+ * fill a spoolss_PrinterInfo2 struct
+********************************************************************/
 
-static bool construct_printer_info_6(Printer_entry *print_hnd,
-                                    PRINTER_INFO_6 *printer,
-                                    int snum)
+static WERROR construct_printer_info2(TALLOC_CTX *mem_ctx,
+                                     const NT_PRINTER_INFO_LEVEL *ntprinter,
+                                     struct spoolss_PrinterInfo2 *r,
+                                     int snum)
 {
-       NT_PRINTER_INFO_LEVEL *ntprinter = NULL;
        int count;
-       print_status_struct status;
 
-       if (!W_ERROR_IS_OK(get_a_printer(print_hnd, &ntprinter, 2,
-                                        lp_const_servicename(snum))))
-               return False;
+       print_status_struct status;
 
        count = print_queue_length(snum, &status);
 
-       printer->status = nt_printq_status(status.status);
+       r->servername           = talloc_strdup(mem_ctx, ntprinter->info_2->servername);
+       W_ERROR_HAVE_NO_MEMORY(r->servername);
+       r->printername          = talloc_strdup(mem_ctx, ntprinter->info_2->printername);
+       W_ERROR_HAVE_NO_MEMORY(r->printername);
+       r->sharename            = talloc_strdup(mem_ctx, lp_servicename(snum));
+       W_ERROR_HAVE_NO_MEMORY(r->sharename);
+       r->portname             = talloc_strdup(mem_ctx, ntprinter->info_2->portname);
+       W_ERROR_HAVE_NO_MEMORY(r->portname);
+       r->drivername           = talloc_strdup(mem_ctx, ntprinter->info_2->drivername);
+       W_ERROR_HAVE_NO_MEMORY(r->drivername);
 
-       free_a_printer(&ntprinter, 2);
+       if (*ntprinter->info_2->comment == '\0') {
+               r->comment      = talloc_strdup(mem_ctx, lp_comment(snum));
+       } else {
+               r->comment      = talloc_strdup(mem_ctx, ntprinter->info_2->comment);
+       }
+       W_ERROR_HAVE_NO_MEMORY(r->comment);
 
-       return True;
-}
+       r->location             = talloc_strdup(mem_ctx, ntprinter->info_2->location);
+       W_ERROR_HAVE_NO_MEMORY(r->location);
+       r->sepfile              = talloc_strdup(mem_ctx, ntprinter->info_2->sepfile);
+       W_ERROR_HAVE_NO_MEMORY(r->sepfile);
+       r->printprocessor       = talloc_strdup(mem_ctx, ntprinter->info_2->printprocessor);
+       W_ERROR_HAVE_NO_MEMORY(r->printprocessor);
+       r->datatype             = talloc_strdup(mem_ctx, ntprinter->info_2->datatype);
+       W_ERROR_HAVE_NO_MEMORY(r->datatype);
+       r->parameters           = talloc_strdup(mem_ctx, ntprinter->info_2->parameters);
+       W_ERROR_HAVE_NO_MEMORY(r->parameters);
 
-/********************************************************************
- * construct_printer_info_7
- * fill a printer_info_7 struct
- ********************************************************************/
+       r->attributes           = ntprinter->info_2->attributes;
 
-static bool construct_printer_info_7(Printer_entry *print_hnd, PRINTER_INFO_7 *printer, int snum)
-{
-       char *guid_str = NULL;
-       struct GUID guid;
+       r->priority             = ntprinter->info_2->priority;
+       r->defaultpriority      = ntprinter->info_2->default_priority;
+       r->starttime            = ntprinter->info_2->starttime;
+       r->untiltime            = ntprinter->info_2->untiltime;
+       r->status               = nt_printq_status(status.status);
+       r->cjobs                = count;
+       r->averageppm           = ntprinter->info_2->averageppm;
 
-       if (is_printer_published(print_hnd, snum, &guid)) {
-               if (asprintf(&guid_str, "{%s}",
-                            GUID_string(talloc_tos(), &guid)) == -1) {
-                       return false;
-               }
-               strupper_m(guid_str);
-               init_unistr(&printer->guid, guid_str);
-               SAFE_FREE(guid_str);
-               printer->action = SPOOL_DS_PUBLISH;
-       } else {
-               init_unistr(&printer->guid, "");
-               printer->action = SPOOL_DS_UNPUBLISH;
+       r->devmode = construct_dev_mode_new(mem_ctx, lp_const_servicename(snum));
+       if (!r->devmode) {
+               DEBUG(8,("Returning NULL Devicemode!\n"));
        }
 
-       return True;
+       r->secdesc              = NULL;
+
+       if (ntprinter->info_2->secdesc_buf && ntprinter->info_2->secdesc_buf->sd_size != 0) {
+               /* don't use talloc_steal() here unless you do a deep steal of all
+                  the SEC_DESC members */
+
+               r->secdesc      = dup_sec_desc(mem_ctx, ntprinter->info_2->secdesc_buf->sd);
+       }
+
+       return WERR_OK;
+}
+
+/********************************************************************
+********************************************************************/
+
+static bool snum_is_shared_printer(int snum)
+{
+       return (lp_browseable(snum) && lp_snum_ok(snum) && lp_print_ok(snum));
 }
 
 /********************************************************************
  Spoolss_enumprinters.
 ********************************************************************/
 
-static WERROR enum_all_printers_info_1(uint32 flags, RPC_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+static WERROR enum_all_printers_info_1(TALLOC_CTX *mem_ctx,
+                                      uint32_t flags,
+                                      union spoolss_PrinterInfo **info_p,
+                                      uint32_t *count)
 {
        int snum;
-       int i;
-       int n_services=lp_numservices();
-       PRINTER_INFO_1 *printers=NULL;
-       PRINTER_INFO_1 current_prt;
+       int n_services = lp_numservices();
+       union spoolss_PrinterInfo *info = NULL;
        WERROR result = WERR_OK;
 
        DEBUG(4,("enum_all_printers_info_1\n"));
 
+       *count = 0;
+
        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(NULL, flags, &current_prt, snum)) {
-                               if((printers=SMB_REALLOC_ARRAY(printers, PRINTER_INFO_1, *returned +1)) == NULL) {
-                                       DEBUG(2,("enum_all_printers_info_1: failed to enlarge printers buffer!\n"));
-                                       *returned=0;
-                                       return WERR_NOMEM;
-                               }
-                               DEBUG(4,("ReAlloced memory for [%d] PRINTER_INFO_1\n", *returned));
 
-                               memcpy(&printers[*returned], &current_prt, sizeof(PRINTER_INFO_1));
-                               (*returned)++;
-                       }
+               NT_PRINTER_INFO_LEVEL *ntprinter = NULL;
+               struct spoolss_PrinterInfo1 info1;
+
+               if (!snum_is_shared_printer(snum)) {
+                       continue;
                }
-       }
 
-       /* check the required size. */
-       for (i=0; i<*returned; i++)
-               (*needed) += spoolss_size_printer_info_1(&printers[i]);
+               DEBUG(4,("Found a printer in smb.conf: %s[%x]\n", lp_servicename(snum), snum));
 
-       if (*needed > offered) {
-               result = WERR_INSUFFICIENT_BUFFER;
-               goto out;
-       }
+               result = get_a_printer(NULL, &ntprinter, 2, lp_const_servicename(snum));
+               if (!W_ERROR_IS_OK(result)) {
+                       continue;
+               }
 
-       if (!rpcbuf_alloc_size(buffer, *needed)) {
-               result = WERR_NOMEM;
-               goto out;
-       }
+               result = construct_printer_info1(info, ntprinter, flags, &info1, snum);
+               free_a_printer(&ntprinter,2);
+               if (!W_ERROR_IS_OK(result)) {
+                       continue;
+               }
 
-       /* fill the buffer with the structures */
-       for (i=0; i<*returned; i++)
-               smb_io_printer_info_1("", buffer, &printers[i], 0);
+               info = TALLOC_REALLOC_ARRAY(mem_ctx, info,
+                                           union spoolss_PrinterInfo,
+                                           *count + 1);
+               if (!info) {
+                       DEBUG(2,("enum_all_printers_info_1: failed to enlarge printers buffer!\n"));
+                       result = WERR_NOMEM;
+                       goto out;
+               }
 
-out:
-       /* clear memory */
+               DEBUG(4,("ReAlloced memory for [%d] PRINTER_INFO_1\n", *count));
 
-       SAFE_FREE(printers);
+               info[*count].info1 = info1;
+               (*count)++;
+       }
 
-       if ( !W_ERROR_IS_OK(result) )
-               *returned = 0;
+ out:
+       if (!W_ERROR_IS_OK(result)) {
+               TALLOC_FREE(info);
+               *count = 0;
+               return result;
+       }
 
-       return result;
+       *info_p = info;
+
+       return WERR_OK;
 }
 
 /********************************************************************
  enum_all_printers_info_1_local.
 *********************************************************************/
 
-static WERROR enum_all_printers_info_1_local(RPC_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+static WERROR enum_all_printers_info_1_local(TALLOC_CTX *mem_ctx,
+                                            union spoolss_PrinterInfo **info,
+                                            uint32_t *count)
 {
        DEBUG(4,("enum_all_printers_info_1_local\n"));
 
-       return enum_all_printers_info_1(PRINTER_ENUM_ICON8, buffer, offered, needed, returned);
+       return enum_all_printers_info_1(mem_ctx, PRINTER_ENUM_ICON8, info, count);
 }
 
 /********************************************************************
  enum_all_printers_info_1_name.
 *********************************************************************/
 
-static WERROR enum_all_printers_info_1_name(fstring name, RPC_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+static WERROR enum_all_printers_info_1_name(TALLOC_CTX *mem_ctx,
+                                           const char *name,
+                                           union spoolss_PrinterInfo **info,
+                                           uint32_t *count)
 {
-       char *s = name;
+       const char *s = name;
 
        DEBUG(4,("enum_all_printers_info_1_name\n"));
 
-       if ((name[0] == '\\') && (name[1] == '\\'))
+       if ((name[0] == '\\') && (name[1] == '\\')) {
                s = name + 2;
-
-       if (is_myname_or_ipaddr(s)) {
-               return enum_all_printers_info_1(PRINTER_ENUM_ICON8, buffer, offered, needed, returned);
        }
-       else
+
+       if (!is_myname_or_ipaddr(s)) {
                return WERR_INVALID_NAME;
+       }
+
+       return enum_all_printers_info_1(mem_ctx, PRINTER_ENUM_ICON8, info, count);
 }
 
 #if 0  /* JERRY -- disabled for now.  Don't think this is used, tested, or correct */
@@ -4617,9 +4576,12 @@ out:
  enum_all_printers_info_1_network.
 *********************************************************************/
 
-static WERROR enum_all_printers_info_1_network(fstring name, RPC_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+static WERROR enum_all_printers_info_1_network(TALLOC_CTX *mem_ctx,
+                                              const char *name,
+                                              union spoolss_PrinterInfo **info,
+                                              uint32_t *count)
 {
-       char *s = name;
+       const char *s = name;
 
        DEBUG(4,("enum_all_printers_info_1_network\n"));
 
@@ -4631,13 +4593,15 @@ static WERROR enum_all_printers_info_1_network(fstring name, RPC_BUFFER *buffer,
           listed. Windows responds to this call with a
           WERR_CAN_NOT_COMPLETE so we should do the same. */
 
-       if (name[0] == '\\' && name[1] == '\\')
+       if (name[0] == '\\' && name[1] == '\\') {
                 s = name + 2;
+       }
 
-       if (is_myname_or_ipaddr(s))
+       if (is_myname_or_ipaddr(s)) {
                 return WERR_CAN_NOT_COMPLETE;
+       }
 
-       return enum_all_printers_info_1(PRINTER_ENUM_NAME, buffer, offered, needed, returned);
+       return enum_all_printers_info_1(mem_ctx, PRINTER_ENUM_NAME, info, count);
 }
 
 /********************************************************************
@@ -4646,92 +4610,96 @@ static WERROR enum_all_printers_info_1_network(fstring name, RPC_BUFFER *buffer,
  * called from api_spoolss_enumprinters (see this to understand)
  ********************************************************************/
 
-static WERROR enum_all_printers_info_2(RPC_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+static WERROR enum_all_printers_info_2(TALLOC_CTX *mem_ctx,
+                                      union spoolss_PrinterInfo **info_p,
+                                      uint32_t *count)
 {
        int snum;
-       int i;
-       int n_services=lp_numservices();
-       PRINTER_INFO_2 *printers=NULL;
-       PRINTER_INFO_2 current_prt;
+       int n_services = lp_numservices();
+       union spoolss_PrinterInfo *info = NULL;
        WERROR result = WERR_OK;
 
-       *returned = 0;
+       *count = 0;
 
        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(NULL, &current_prt, snum)) {
-                               if ( !(printers=SMB_REALLOC_ARRAY(printers, PRINTER_INFO_2, *returned +1)) ) {
-                                       DEBUG(2,("enum_all_printers_info_2: failed to enlarge printers buffer!\n"));
-                                       *returned = 0;
-                                       return WERR_NOMEM;
-                               }
 
-                               DEBUG(4,("ReAlloced memory for [%d] PRINTER_INFO_2\n", *returned + 1));
+               struct spoolss_PrinterInfo2 info2;
+               NT_PRINTER_INFO_LEVEL *ntprinter = NULL;
 
-                               memcpy(&printers[*returned], &current_prt, sizeof(PRINTER_INFO_2));
+               if (!snum_is_shared_printer(snum)) {
+                       continue;
+               }
 
-                               (*returned)++;
-                       }
+               DEBUG(4,("Found a printer in smb.conf: %s[%x]\n", lp_servicename(snum), snum));
+
+               result = get_a_printer(NULL, &ntprinter, 2, lp_const_servicename(snum));
+               if (!W_ERROR_IS_OK(result)) {
+                       continue;
                }
-       }
 
-       /* check the required size. */
-       for (i=0; i<*returned; i++)
-               (*needed) += spoolss_size_printer_info_2(&printers[i]);
+               result = construct_printer_info2(info, ntprinter, &info2, snum);
+               free_a_printer(&ntprinter, 2);
+               if (!W_ERROR_IS_OK(result)) {
+                       continue;
+               }
 
-       if (*needed > offered) {
-               result = WERR_INSUFFICIENT_BUFFER;
-               goto out;
-       }
+               info = TALLOC_REALLOC_ARRAY(mem_ctx, info,
+                                           union spoolss_PrinterInfo,
+                                           *count + 1);
+               if (!info) {
+                       DEBUG(2,("enum_all_printers_info_2: failed to enlarge printers buffer!\n"));
+                       result = WERR_NOMEM;
+                       goto out;
+               }
 
-       if (!rpcbuf_alloc_size(buffer, *needed)) {
-               result = WERR_NOMEM;
-               goto out;
-       }
+               DEBUG(4,("ReAlloced memory for [%d] PRINTER_INFO_2\n", *count + 1));
 
-       /* fill the buffer with the structures */
-       for (i=0; i<*returned; i++)
-               smb_io_printer_info_2("", buffer, &(printers[i]), 0);
-
-out:
-       /* clear memory */
+               info[*count].info2 = info2;
 
-       for (i=0; i<*returned; i++)
-               free_devmode(printers[i].devmode);
+               (*count)++;
+       }
 
-       SAFE_FREE(printers);
+ out:
+       if (!W_ERROR_IS_OK(result)) {
+               TALLOC_FREE(info);
+               *count = 0;
+               return result;
+       }
 
-       if ( !W_ERROR_IS_OK(result) )
-               *returned = 0;
+       *info_p = info;
 
-       return result;
+       return WERR_OK;
 }
 
 /********************************************************************
  * handle enumeration of printers at level 1
  ********************************************************************/
 
-static WERROR enumprinters_level1( uint32 flags, fstring name,
-                                RPC_BUFFER *buffer, uint32 offered,
-                                uint32 *needed, uint32 *returned)
+static WERROR enumprinters_level1(TALLOC_CTX *mem_ctx,
+                                 uint32_t flags,
+                                 const char *name,
+                                 union spoolss_PrinterInfo **info,
+                                 uint32_t *count)
 {
        /* Not all the flags are equals */
 
-       if (flags & PRINTER_ENUM_LOCAL)
-               return enum_all_printers_info_1_local(buffer, offered, needed, returned);
+       if (flags & PRINTER_ENUM_LOCAL) {
+               return enum_all_printers_info_1_local(mem_ctx, info, count);
+       }
 
-       if (flags & PRINTER_ENUM_NAME)
-               return enum_all_printers_info_1_name(name, buffer, offered, needed, returned);
+       if (flags & PRINTER_ENUM_NAME) {
+               return enum_all_printers_info_1_name(mem_ctx, name, info, count);
+       }
 
 #if 0  /* JERRY - disabled for now */
-       if (flags & PRINTER_ENUM_REMOTE)
-               return enum_all_printers_info_1_remote(name, buffer, offered, needed, returned);
+       if (flags & PRINTER_ENUM_REMOTE) {
+               return enum_all_printers_info_1_remote(mem_ctx, name, info, count);
+       }
 #endif
 
-       if (flags & PRINTER_ENUM_NETWORK)
-               return enum_all_printers_info_1_network(name, buffer, offered, needed, returned);
+       if (flags & PRINTER_ENUM_NETWORK) {
+               return enum_all_printers_info_1_network(mem_ctx, name, info, count);
+       }
 
        return WERR_OK; /* NT4sp5 does that */
 }
@@ -4740,23 +4708,27 @@ static WERROR enumprinters_level1( uint32 flags, fstring name,
  * handle enumeration of printers at level 2
  ********************************************************************/
 
-static WERROR enumprinters_level2( uint32 flags, const char *servername,
-                                RPC_BUFFER *buffer, uint32 offered,
-                                uint32 *needed, uint32 *returned)
+static WERROR enumprinters_level2(TALLOC_CTX *mem_ctx,
+                                 uint32_t flags,
+                                 const char *servername,
+                                 union spoolss_PrinterInfo **info,
+                                 uint32_t *count)
 {
        if (flags & PRINTER_ENUM_LOCAL) {
-                       return enum_all_printers_info_2(buffer, offered, needed, returned);
+               return enum_all_printers_info_2(mem_ctx, info, count);
        }
 
        if (flags & PRINTER_ENUM_NAME) {
-               if (is_myname_or_ipaddr(canon_servername(servername)))
-                       return enum_all_printers_info_2(buffer, offered, needed, returned);
-               else
+               if (!is_myname_or_ipaddr(canon_servername(servername))) {
                        return WERR_INVALID_NAME;
+               }
+
+               return enum_all_printers_info_2(mem_ctx, info, count);
        }
 
-       if (flags & PRINTER_ENUM_REMOTE)
+       if (flags & PRINTER_ENUM_REMOTE) {
                return WERR_UNKNOWN_LEVEL;
+       }
 
        return WERR_OK;
 }
@@ -4765,45 +4737,37 @@ static WERROR enumprinters_level2( uint32 flags, const char *servername,
  * handle enumeration of printers at level 5
  ********************************************************************/
 
-static WERROR enumprinters_level5( uint32 flags, const char *servername,
-                                RPC_BUFFER *buffer, uint32 offered,
-                                uint32 *needed, uint32 *returned)
+static WERROR enumprinters_level5(TALLOC_CTX *mem_ctx,
+                                 uint32_t flags,
+                                 const char *servername,
+                                 union spoolss_PrinterInfo **info,
+                                 uint32_t *count)
 {
-/*     return enum_all_printers_info_5(buffer, offered, needed, returned);*/
+/*     return enum_all_printers_info_5(mem_ctx, info, offered, needed, count);*/
        return WERR_OK;
 }
 
-/********************************************************************
- * api_spoolss_enumprinters
- *
- * called from api_spoolss_enumprinters (see this to understand)
- ********************************************************************/
+/****************************************************************
+ _spoolss_EnumPrinters
+****************************************************************/
 
-WERROR _spoolss_enumprinters( pipes_struct *p, SPOOL_Q_ENUMPRINTERS *q_u, SPOOL_R_ENUMPRINTERS *r_u)
+WERROR _spoolss_EnumPrinters(pipes_struct *p,
+                            struct spoolss_EnumPrinters *r)
 {
-       uint32 flags = q_u->flags;
-       UNISTR2 *servername = &q_u->servername;
-       uint32 level = q_u->level;
-       RPC_BUFFER *buffer = NULL;
-       uint32 offered = q_u->offered;
-       uint32 *needed = &r_u->needed;
-       uint32 *returned = &r_u->returned;
-
-       fstring name;
+       const char *name;
+       WERROR result;
 
        /* that's an [in out] buffer */
 
-       if (!q_u->buffer && (offered!=0)) {
+       if (!r->in.buffer && (r->in.offered != 0)) {
                return WERR_INVALID_PARAM;
        }
 
-       rpcbuf_move(q_u->buffer, &r_u->buffer);
-       buffer = r_u->buffer;
+       DEBUG(4,("_spoolss_EnumPrinters\n"));
 
-       DEBUG(4,("_spoolss_enumprinters\n"));
-
-       *needed=0;
-       *returned=0;
+       *r->out.needed = 0;
+       *r->out.count = 0;
+       *r->out.info = NULL;
 
        /*
         * Level 1:
@@ -4818,388 +4782,376 @@ WERROR _spoolss_enumprinters( pipes_struct *p, SPOOL_Q_ENUMPRINTERS *q_u, SPOOL_
         * Level 5: same as Level 2
         */
 
-       unistr2_to_ascii(name, servername, sizeof(name));
-       strupper_m(name);
+       name = talloc_strdup_upper(p->mem_ctx, r->in.server);
+       W_ERROR_HAVE_NO_MEMORY(name);
 
-       switch (level) {
+       switch (r->in.level) {
        case 1:
-               return enumprinters_level1(flags, name, buffer, offered, needed, returned);
+               result = enumprinters_level1(p->mem_ctx, r->in.flags, name,
+                                            r->out.info, r->out.count);
+               break;
        case 2:
-               return enumprinters_level2(flags, name, buffer, offered, needed, returned);
+               result = enumprinters_level2(p->mem_ctx, r->in.flags, name,
+                                            r->out.info, r->out.count);
+               break;
        case 5:
-               return enumprinters_level5(flags, name, buffer, offered, needed, returned);
+               result = enumprinters_level5(p->mem_ctx, r->in.flags, name,
+                                            r->out.info, r->out.count);
+               break;
        case 3:
        case 4:
+               result = WERR_OK; /* ??? */
                break;
-       }
-       return WERR_UNKNOWN_LEVEL;
-}
-
-/****************************************************************************
-****************************************************************************/
-
-static WERROR getprinter_level_0(Printer_entry *print_hnd, int snum, RPC_BUFFER *buffer, uint32 offered, uint32 *needed)
-{
-       PRINTER_INFO_0 *printer=NULL;
-       WERROR result = WERR_OK;
-
-       if((printer=SMB_MALLOC_P(PRINTER_INFO_0)) == NULL)
-               return WERR_NOMEM;
-
-       construct_printer_info_0(print_hnd, printer, snum);
-
-       /* check the required size. */
-       *needed += spoolss_size_printer_info_0(printer);
-
-       if (*needed > offered) {
-               result = WERR_INSUFFICIENT_BUFFER;
-               goto out;
+       default:
+               return WERR_UNKNOWN_LEVEL;
        }
 
-       if (!rpcbuf_alloc_size(buffer, *needed)) {
-               result = WERR_NOMEM;
-               goto out;
+       if (!W_ERROR_IS_OK(result)) {
+               return result;
        }
 
-       /* fill the buffer with the structures */
-       smb_io_printer_info_0("", buffer, printer, 0);
-
-out:
-       /* clear memory */
-
-       SAFE_FREE(printer);
+       *r->out.needed  = SPOOLSS_BUFFER_UNION_ARRAY(p->mem_ctx,
+                                                    spoolss_EnumPrinters, NULL,
+                                                    *r->out.info, r->in.level,
+                                                    *r->out.count);
+       *r->out.info    = SPOOLSS_BUFFER_OK(*r->out.info, NULL);
+       *r->out.count   = SPOOLSS_BUFFER_OK(*r->out.count, 0);
 
-       return result;
+       return SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER);
 }
 
-/****************************************************************************
-****************************************************************************/
+/****************************************************************
+ _spoolss_GetPrinter
+****************************************************************/
 
-static WERROR getprinter_level_1(Printer_entry *print_hnd, int snum, RPC_BUFFER *buffer, uint32 offered, uint32 *needed)
+WERROR _spoolss_GetPrinter(pipes_struct *p,
+                          struct spoolss_GetPrinter *r)
 {
-       PRINTER_INFO_1 *printer=NULL;
+       Printer_entry *Printer = find_printer_index_by_hnd(p, r->in.handle);
+       NT_PRINTER_INFO_LEVEL *ntprinter = NULL;
        WERROR result = WERR_OK;
 
-       if((printer=SMB_MALLOC_P(PRINTER_INFO_1)) == NULL)
-               return WERR_NOMEM;
-
-       construct_printer_info_1(print_hnd, PRINTER_ENUM_ICON8, printer, snum);
-
-       /* check the required size. */
-       *needed += spoolss_size_printer_info_1(printer);
+       int snum;
 
-       if (*needed > offered) {
-               result = WERR_INSUFFICIENT_BUFFER;
-               goto out;
-       }
+       /* that's an [in out] buffer */
 
-       if (!rpcbuf_alloc_size(buffer, *needed)) {
-               result = WERR_NOMEM;
-               goto out;
+       if (!r->in.buffer && (r->in.offered != 0)) {
+               return WERR_INVALID_PARAM;
        }
 
-       /* fill the buffer with the structures */
-       smb_io_printer_info_1("", buffer, printer, 0);
-
-out:
-       /* clear memory */
-       SAFE_FREE(printer);
-
-       return result;
-}
-
-/****************************************************************************
-****************************************************************************/
+       *r->out.needed = 0;
 
-static WERROR getprinter_level_2(Printer_entry *print_hnd, int snum, RPC_BUFFER *buffer, uint32 offered, uint32 *needed)
-{
-       PRINTER_INFO_2 *printer=NULL;
-       WERROR result = WERR_OK;
-
-       if((printer=SMB_MALLOC_P(PRINTER_INFO_2))==NULL)
-               return WERR_NOMEM;
-
-       construct_printer_info_2(print_hnd, printer, snum);
-
-       /* check the required size. */
-       *needed += spoolss_size_printer_info_2(printer);
-
-       if (*needed > offered) {
-               result = WERR_INSUFFICIENT_BUFFER;
-               goto out;
+       if (!get_printer_snum(p, r->in.handle, &snum, NULL)) {
+               return WERR_BADFID;
        }
 
-       if (!rpcbuf_alloc_size(buffer, *needed)) {
-               result = WERR_NOMEM;
-               goto out;
+       result = get_a_printer(Printer, &ntprinter, 2,
+                              lp_const_servicename(snum));
+       if (!W_ERROR_IS_OK(result)) {
+               return result;
        }
 
-       /* fill the buffer with the structures */
-       if (!smb_io_printer_info_2("", buffer, printer, 0))
-               result = WERR_NOMEM;
-
-out:
-       /* clear memory */
-       free_printer_info_2(printer);
-
-       return result;
-}
-
-/****************************************************************************
-****************************************************************************/
-
-static WERROR getprinter_level_3(Printer_entry *print_hnd, int snum, RPC_BUFFER *buffer, uint32 offered, uint32 *needed)
-{
-       PRINTER_INFO_3 *printer=NULL;
-       WERROR result = WERR_OK;
-
-       if (!construct_printer_info_3(print_hnd, &printer, snum))
-               return WERR_NOMEM;
-
-       /* check the required size. */
-       *needed += spoolss_size_printer_info_3(printer);
-
-       if (*needed > offered) {
-               result = WERR_INSUFFICIENT_BUFFER;
-               goto out;
+       switch (r->in.level) {
+       case 0:
+               result = construct_printer_info0(p->mem_ctx, ntprinter,
+                                                &r->out.info->info0, snum);
+               break;
+       case 1:
+               result = construct_printer_info1(p->mem_ctx, ntprinter,
+                                                PRINTER_ENUM_ICON8,
+                                                &r->out.info->info1, snum);
+               break;
+       case 2:
+               result = construct_printer_info2(p->mem_ctx, ntprinter,
+                                                &r->out.info->info2, snum);
+               break;
+       case 3:
+               result = construct_printer_info3(p->mem_ctx, ntprinter,
+                                                &r->out.info->info3, snum);
+               break;
+       case 4:
+               result = construct_printer_info4(p->mem_ctx, ntprinter,
+                                                &r->out.info->info4, snum);
+               break;
+       case 5:
+               result = construct_printer_info5(p->mem_ctx, ntprinter,
+                                                &r->out.info->info5, snum);
+               break;
+       case 6:
+               result = construct_printer_info6(p->mem_ctx, ntprinter,
+                                                &r->out.info->info6, snum);
+               break;
+       case 7:
+               result = construct_printer_info7(p->mem_ctx, Printer,
+                                                &r->out.info->info7, snum);
+               break;
+       default:
+               result = WERR_UNKNOWN_LEVEL;
+               break;
        }
 
-       if (!rpcbuf_alloc_size(buffer, *needed)) {
-               result = WERR_NOMEM;
-               goto out;
-       }
+       free_a_printer(&ntprinter, 2);
 
-       /* fill the buffer with the structures */
-       smb_io_printer_info_3("", buffer, printer, 0);
+       if (!W_ERROR_IS_OK(result)) {
+               TALLOC_FREE(r->out.info);
+               return result;
+       }
 
-out:
-       /* clear memory */
-       free_printer_info_3(printer);
+       *r->out.needed  = SPOOLSS_BUFFER_UNION(spoolss_PrinterInfo, NULL,
+                                              r->out.info, r->in.level);
+       r->out.info     = SPOOLSS_BUFFER_OK(r->out.info, NULL);
 
-       return result;
+       return SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER);
 }
 
-/****************************************************************************
-****************************************************************************/
+/********************************************************************
+ ********************************************************************/
 
-static WERROR getprinter_level_4(Printer_entry *print_hnd, int snum, RPC_BUFFER *buffer, uint32 offered, uint32 *needed)
+static const char **string_array_from_driver_info(TALLOC_CTX *mem_ctx,
+                                                 fstring *fstring_array,
+                                                 const char *cservername)
 {
-       PRINTER_INFO_4 *printer=NULL;
-       WERROR result = WERR_OK;
+       int i, num_strings = 0;
+       const char **array = NULL;
 
-       if((printer=SMB_MALLOC_P(PRINTER_INFO_4))==NULL)
-               return WERR_NOMEM;
+       for (i=0; fstring_array && fstring_array[i][0] != '\0'; i++) {
 
-       if (!construct_printer_info_4(print_hnd, printer, snum)) {
-               SAFE_FREE(printer);
-               return WERR_NOMEM;
-       }
+               const char *str = talloc_asprintf(mem_ctx, "\\\\%s%s",
+                                                 cservername, fstring_array[i]);
+               if (!str) {
+                       TALLOC_FREE(array);
+                       return NULL;
+               }
 
-       /* check the required size. */
-       *needed += spoolss_size_printer_info_4(printer);
 
-       if (*needed > offered) {
-               result = WERR_INSUFFICIENT_BUFFER;
-               goto out;
+               if (!add_string_to_array(mem_ctx, str, &array, &num_strings)) {
+                       TALLOC_FREE(array);
+                       return NULL;
+               }
        }
 
-       if (!rpcbuf_alloc_size(buffer, *needed)) {
-               result = WERR_NOMEM;
-               goto out;
+       if (i > 0) {
+               ADD_TO_ARRAY(mem_ctx, const char *, NULL,
+                            &array, &num_strings);
        }
 
-       /* fill the buffer with the structures */
-       smb_io_printer_info_4("", buffer, printer, 0);
-
-out:
-       /* clear memory */
-       free_printer_info_4(printer);
-
-       return result;
+       return array;
 }
 
-/****************************************************************************
-****************************************************************************/
+/********************************************************************
+ * fill a spoolss_DriverInfo1 struct
+ ********************************************************************/
 
-static WERROR getprinter_level_5(Printer_entry *print_hnd, int snum, RPC_BUFFER *buffer, uint32 offered, uint32 *needed)
+static WERROR fill_printer_driver_info1(TALLOC_CTX *mem_ctx,
+                                       struct spoolss_DriverInfo1 *r,
+                                       const NT_PRINTER_DRIVER_INFO_LEVEL *driver,
+                                       const char *servername,
+                                       const char *architecture)
 {
-       PRINTER_INFO_5 *printer=NULL;
-       WERROR result = WERR_OK;
-
-       if((printer=SMB_MALLOC_P(PRINTER_INFO_5))==NULL)
-               return WERR_NOMEM;
-
-       if (!construct_printer_info_5(print_hnd, printer, snum)) {
-               free_printer_info_5(printer);
-               return WERR_NOMEM;
-       }
+       r->driver_name          = talloc_strdup(mem_ctx, driver->info_3->name);
+       W_ERROR_HAVE_NO_MEMORY(r->driver_name);
 
-       /* check the required size. */
-       *needed += spoolss_size_printer_info_5(printer);
-
-       if (*needed > offered) {
-               result = WERR_INSUFFICIENT_BUFFER;
-               goto out;
-       }
-
-       if (!rpcbuf_alloc_size(buffer, *needed)) {
-               result = WERR_NOMEM;
-               goto out;
-       }
-
-       /* fill the buffer with the structures */
-       smb_io_printer_info_5("", buffer, printer, 0);
+       return WERR_OK;
+}
 
-out:
-       /* clear memory */
-       free_printer_info_5(printer);
+/********************************************************************
+ * fill a spoolss_DriverInfo2 struct
+ ********************************************************************/
 
-       return result;
-}
+static WERROR fill_printer_driver_info2(TALLOC_CTX *mem_ctx,
+                                       struct spoolss_DriverInfo2 *r,
+                                       const NT_PRINTER_DRIVER_INFO_LEVEL *driver,
+                                       const char *servername)
 
-static WERROR getprinter_level_6(Printer_entry *print_hnd,
-                                int snum,
-                                RPC_BUFFER *buffer, uint32 offered,
-                                uint32 *needed)
 {
-       PRINTER_INFO_6 *printer;
-       WERROR result = WERR_OK;
-
-       if ((printer = SMB_MALLOC_P(PRINTER_INFO_6)) == NULL) {
-               return WERR_NOMEM;
-       }
+       const char *cservername = canon_servername(servername);
 
-       if (!construct_printer_info_6(print_hnd, printer, snum)) {
-               free_printer_info_6(printer);
-               return WERR_NOMEM;
-       }
+       r->version              = driver->info_3->cversion;
 
-       /* check the required size. */
-       *needed += spoolss_size_printer_info_6(printer);
+       r->driver_name          = talloc_strdup(mem_ctx, driver->info_3->name);
+       W_ERROR_HAVE_NO_MEMORY(r->driver_name);
+       r->architecture         = talloc_strdup(mem_ctx, driver->info_3->environment);
+       W_ERROR_HAVE_NO_MEMORY(r->architecture);
 
-       if (*needed > offered) {
-               result = WERR_INSUFFICIENT_BUFFER;
-               goto out;
+       if (strlen(driver->info_3->driverpath)) {
+               r->driver_path  = talloc_asprintf(mem_ctx, "\\\\%s%s",
+                               cservername, driver->info_3->driverpath);
+       } else {
+               r->driver_path  = talloc_strdup(mem_ctx, "");
        }
+       W_ERROR_HAVE_NO_MEMORY(r->driver_path);
 
-       if (!rpcbuf_alloc_size(buffer, *needed)) {
-               result = WERR_NOMEM;
-               goto out;
+       if (strlen(driver->info_3->datafile)) {
+               r->data_file    = talloc_asprintf(mem_ctx, "\\\\%s%s",
+                               cservername, driver->info_3->datafile);
+       } else {
+               r->data_file    = talloc_strdup(mem_ctx, "");
        }
+       W_ERROR_HAVE_NO_MEMORY(r->data_file);
 
-       /* fill the buffer with the structures */
-       smb_io_printer_info_6("", buffer, printer, 0);
-
-out:
-       /* clear memory */
-       free_printer_info_6(printer);
+       if (strlen(driver->info_3->configfile)) {
+               r->config_file  = talloc_asprintf(mem_ctx, "\\\\%s%s",
+                               cservername, driver->info_3->configfile);
+       } else {
+               r->config_file  = talloc_strdup(mem_ctx, "");
+       }
+       W_ERROR_HAVE_NO_MEMORY(r->config_file);
 
-       return result;
+       return WERR_OK;
 }
 
-static WERROR getprinter_level_7(Printer_entry *print_hnd, int snum, RPC_BUFFER *buffer, uint32 offered, uint32 *needed)
-{
-       PRINTER_INFO_7 *printer=NULL;
-       WERROR result = WERR_OK;
+/********************************************************************
+ * fill a spoolss_DriverInfo3 struct
+ ********************************************************************/
 
-       if((printer=SMB_MALLOC_P(PRINTER_INFO_7))==NULL)
-               return WERR_NOMEM;
+static WERROR fill_printer_driver_info3(TALLOC_CTX *mem_ctx,
+                                       struct spoolss_DriverInfo3 *r,
+                                       const NT_PRINTER_DRIVER_INFO_LEVEL *driver,
+                                       const char *servername)
+{
+       const char *cservername = canon_servername(servername);
 
-       if (!construct_printer_info_7(print_hnd, printer, snum)) {
-               result = WERR_NOMEM;
-               goto out;
-       }
+       r->version              = driver->info_3->cversion;
 
-       /* check the required size. */
-       *needed += spoolss_size_printer_info_7(printer);
+       r->driver_name          = talloc_strdup(mem_ctx, driver->info_3->name);
+       W_ERROR_HAVE_NO_MEMORY(r->driver_name);
+       r->architecture         = talloc_strdup(mem_ctx, driver->info_3->environment);
+       W_ERROR_HAVE_NO_MEMORY(r->architecture);
 
-       if (*needed > offered) {
-               result = WERR_INSUFFICIENT_BUFFER;
-               goto out;
+       if (strlen(driver->info_3->driverpath)) {
+               r->driver_path  = talloc_asprintf(mem_ctx, "\\\\%s%s",
+                               cservername, driver->info_3->driverpath);
+       } else {
+               r->driver_path  = talloc_strdup(mem_ctx, "");
        }
+       W_ERROR_HAVE_NO_MEMORY(r->driver_path);
 
-       if (!rpcbuf_alloc_size(buffer, *needed)) {
-               result = WERR_NOMEM;
-               goto out;
+       if (strlen(driver->info_3->datafile)) {
+               r->data_file    = talloc_asprintf(mem_ctx, "\\\\%s%s",
+                               cservername, driver->info_3->datafile);
+       } else {
+               r->data_file    = talloc_strdup(mem_ctx, "");
+       }
+       W_ERROR_HAVE_NO_MEMORY(r->data_file);
 
+       if (strlen(driver->info_3->configfile)) {
+               r->config_file  = talloc_asprintf(mem_ctx, "\\\\%s%s",
+                               cservername, driver->info_3->configfile);
+       } else {
+               r->config_file  = talloc_strdup(mem_ctx, "");
        }
+       W_ERROR_HAVE_NO_MEMORY(r->config_file);
 
-       /* fill the buffer with the structures */
-       smb_io_printer_info_7("", buffer, printer, 0);
+       if (strlen(driver->info_3->helpfile)) {
+               r->help_file    = talloc_asprintf(mem_ctx, "\\\\%s%s",
+                               cservername, driver->info_3->helpfile);
+       } else {
+               r->help_file    = talloc_strdup(mem_ctx, "");
+       }
+       W_ERROR_HAVE_NO_MEMORY(r->config_file);
 
-out:
-       /* clear memory */
-       free_printer_info_7(printer);
+       r->monitor_name         = talloc_strdup(mem_ctx, driver->info_3->monitorname);
+       W_ERROR_HAVE_NO_MEMORY(r->monitor_name);
+       r->default_datatype     = talloc_strdup(mem_ctx, driver->info_3->defaultdatatype);
+       W_ERROR_HAVE_NO_MEMORY(r->default_datatype);
 
-       return result;
+       r->dependent_files = string_array_from_driver_info(mem_ctx,
+                                                          driver->info_3->dependentfiles,
+                                                          cservername);
+       return WERR_OK;
 }
 
-/****************************************************************************
-****************************************************************************/
+/********************************************************************
+ * fill a spoolss_DriverInfo6 struct
+ ********************************************************************/
 
-WERROR _spoolss_getprinter(pipes_struct *p, SPOOL_Q_GETPRINTER *q_u, SPOOL_R_GETPRINTER *r_u)
+static WERROR fill_printer_driver_info6(TALLOC_CTX *mem_ctx,
+                                       struct spoolss_DriverInfo6 *r,
+                                       const NT_PRINTER_DRIVER_INFO_LEVEL *driver,
+                                       const char *servername)
 {
-       POLICY_HND *handle = &q_u->handle;
-       uint32 level = q_u->level;
-       RPC_BUFFER *buffer = NULL;
-       uint32 offered = q_u->offered;
-       uint32 *needed = &r_u->needed;
-       Printer_entry *Printer=find_printer_index_by_hnd(p, handle);
+       const char *cservername = canon_servername(servername);
 
-       int snum;
+       r->version              = driver->info_3->cversion;
 
-       /* that's an [in out] buffer */
+       r->driver_name          = talloc_strdup(mem_ctx, driver->info_3->name);
+       W_ERROR_HAVE_NO_MEMORY(r->driver_name);
+       r->architecture         = talloc_strdup(mem_ctx, driver->info_3->environment);
+       W_ERROR_HAVE_NO_MEMORY(r->architecture);
 
-       if (!q_u->buffer && (offered!=0)) {
-               return WERR_INVALID_PARAM;
+       if (strlen(driver->info_3->driverpath)) {
+               r->driver_path  = talloc_asprintf(mem_ctx, "\\\\%s%s",
+                               cservername, driver->info_3->driverpath);
+       } else {
+               r->driver_path  = talloc_strdup(mem_ctx, "");
        }
+       W_ERROR_HAVE_NO_MEMORY(r->driver_path);
 
-       rpcbuf_move(q_u->buffer, &r_u->buffer);
-       buffer = r_u->buffer;
-
-       *needed=0;
-
-       if (!get_printer_snum(p, handle, &snum, NULL))
-               return WERR_BADFID;
+       if (strlen(driver->info_3->datafile)) {
+               r->data_file    = talloc_asprintf(mem_ctx, "\\\\%s%s",
+                               cservername, driver->info_3->datafile);
+       } else {
+               r->data_file    = talloc_strdup(mem_ctx, "");
+       }
+       W_ERROR_HAVE_NO_MEMORY(r->data_file);
 
-       switch (level) {
-       case 0:
-               return getprinter_level_0(Printer, snum, buffer, offered, needed);
-       case 1:
-               return getprinter_level_1(Printer, snum, buffer, offered, needed);
-       case 2:
-               return getprinter_level_2(Printer, snum, buffer, offered, needed);
-       case 3:
-               return getprinter_level_3(Printer, snum, buffer, offered, needed);
-       case 4:
-               return getprinter_level_4(Printer, snum, buffer, offered, needed);
-       case 5:
-               return getprinter_level_5(Printer, snum, buffer, offered, needed);
-       case 6:
-               return getprinter_level_6(Printer, snum, buffer, offered, needed);
-       case 7:
-               return getprinter_level_7(Printer, snum, buffer, offered, needed);
+       if (strlen(driver->info_3->configfile)) {
+               r->config_file  = talloc_asprintf(mem_ctx, "\\\\%s%s",
+                               cservername, driver->info_3->configfile);
+       } else {
+               r->config_file  = talloc_strdup(mem_ctx, "");
        }
-       return WERR_UNKNOWN_LEVEL;
-}
+       W_ERROR_HAVE_NO_MEMORY(r->config_file);
 
-/********************************************************************
- * fill a DRIVER_INFO_1 struct
- ********************************************************************/
+       if (strlen(driver->info_3->helpfile)) {
+               r->help_file    = talloc_asprintf(mem_ctx, "\\\\%s%s",
+                               cservername, driver->info_3->helpfile);
+       } else {
+               r->help_file    = talloc_strdup(mem_ctx, "");
+       }
+       W_ERROR_HAVE_NO_MEMORY(r->config_file);
+
+       r->monitor_name         = talloc_strdup(mem_ctx, driver->info_3->monitorname);
+       W_ERROR_HAVE_NO_MEMORY(r->monitor_name);
+       r->default_datatype     = talloc_strdup(mem_ctx, driver->info_3->defaultdatatype);
+       W_ERROR_HAVE_NO_MEMORY(r->default_datatype);
+
+       r->dependent_files = string_array_from_driver_info(mem_ctx,
+                                                          driver->info_3->dependentfiles,
+                                                          cservername);
+       r->previous_names = string_array_from_driver_info(mem_ctx,
+                                                         NULL,
+                                                         cservername);
+
+       r->driver_date          = 0;
+       r->driver_version       = 0;
+
+       r->manufacturer_name    = talloc_strdup(mem_ctx, "");
+       W_ERROR_HAVE_NO_MEMORY(r->manufacturer_name);
+       r->manufacturer_url     = talloc_strdup(mem_ctx, "");
+       W_ERROR_HAVE_NO_MEMORY(r->manufacturer_url);
+       r->hardware_id          = talloc_strdup(mem_ctx, "");
+       W_ERROR_HAVE_NO_MEMORY(r->hardware_id);
+       r->provider             = talloc_strdup(mem_ctx, "");
+       W_ERROR_HAVE_NO_MEMORY(r->provider);
 
-static void fill_printer_driver_info_1(DRIVER_INFO_1 *info, NT_PRINTER_DRIVER_INFO_LEVEL driver, const char *servername, fstring architecture)
-{
-       init_unistr( &info->name, driver.info_3->name);
+       return WERR_OK;
 }
 
 /********************************************************************
  * construct_printer_driver_info_1
  ********************************************************************/
 
-static WERROR construct_printer_driver_info_1(DRIVER_INFO_1 *info, int snum, const char *servername, fstring architecture, uint32 version)
+static WERROR construct_printer_driver_info_1(TALLOC_CTX *mem_ctx,
+                                             struct spoolss_DriverInfo1 *r,
+                                             int snum,
+                                             const char *servername,
+                                             const char *architecture,
+                                             uint32_t version)
 {
        NT_PRINTER_INFO_LEVEL *printer = NULL;
        NT_PRINTER_DRIVER_INFO_LEVEL driver;
+       WERROR result;
 
        ZERO_STRUCT(driver);
 
@@ -5211,58 +5163,11 @@ static WERROR construct_printer_driver_info_1(DRIVER_INFO_1 *info, int snum, con
                return WERR_UNKNOWN_PRINTER_DRIVER;
        }
 
-       fill_printer_driver_info_1(info, driver, servername, architecture);
+       result = fill_printer_driver_info1(mem_ctx, r, &driver, servername, architecture);
 
        free_a_printer(&printer,2);
 
-       return WERR_OK;
-}
-
-/********************************************************************
- * 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, const char *servername)
-{
-       TALLOC_CTX *ctx = talloc_tos();
-       char *temp = NULL;
-       const char *cservername = canon_servername(servername);
-
-       info->version=driver.info_3->cversion;
-
-       init_unistr( &info->name, driver.info_3->name );
-       init_unistr( &info->architecture, driver.info_3->environment );
-
-       if (strlen(driver.info_3->driverpath)) {
-               temp = talloc_asprintf(ctx,
-                               "\\\\%s%s",
-                               cservername,
-                               driver.info_3->driverpath);
-               init_unistr( &info->driverpath, temp );
-       } else {
-               init_unistr( &info->driverpath, "" );
-       }
-
-       TALLOC_FREE(temp);
-       if (strlen(driver.info_3->datafile)) {
-               temp = talloc_asprintf(ctx,
-                               "\\\\%s%s",
-                               cservername,
-                               driver.info_3->datafile);
-               init_unistr( &info->datafile, temp );
-       } else
-               init_unistr( &info->datafile, "" );
-
-       TALLOC_FREE(temp);
-       if (strlen(driver.info_3->configfile)) {
-               temp = talloc_asprintf(ctx,
-                               "\\\\%s%s",
-                               cservername,
-                               driver.info_3->configfile);
-               init_unistr( &info->configfile, temp );
-       } else
-               init_unistr( &info->configfile, "" );
+       return result;
 }
 
 /********************************************************************
@@ -5270,10 +5175,16 @@ static void fill_printer_driver_info_2(DRIVER_INFO_2 *info, NT_PRINTER_DRIVER_IN
  * fill a printer_info_2 struct
  ********************************************************************/
 
-static WERROR construct_printer_driver_info_2(DRIVER_INFO_2 *info, int snum, const char *servername, fstring architecture, uint32 version)
+static WERROR construct_printer_driver_info_2(TALLOC_CTX *mem_ctx,
+                                             struct spoolss_DriverInfo2 *r,
+                                             int snum,
+                                             const char *servername,
+                                             const char *architecture,
+                                             uint32_t version)
 {
        NT_PRINTER_INFO_LEVEL *printer = NULL;
        NT_PRINTER_DRIVER_INFO_LEVEL driver;
+       WERROR result;
 
        ZERO_STRUCT(printer);
        ZERO_STRUCT(driver);
@@ -5286,11 +5197,11 @@ static WERROR construct_printer_driver_info_2(DRIVER_INFO_2 *info, int snum, con
                return WERR_UNKNOWN_PRINTER_DRIVER;
        }
 
-       fill_printer_driver_info_2(info, driver, servername);
+       result = fill_printer_driver_info2(mem_ctx, r, &driver, servername);
 
        free_a_printer(&printer,2);
 
-       return WERR_OK;
+       return result;
 }
 
 /********************************************************************
@@ -5371,72 +5282,12 @@ static uint32 init_unistr_array(uint16 **uni_array, fstring *char_array, const c
  * fill a printer_info_3 struct
  ********************************************************************/
 
-static void fill_printer_driver_info_3(DRIVER_INFO_3 *info, NT_PRINTER_DRIVER_INFO_LEVEL driver, const char *servername)
-{
-       char *temp = NULL;
-       TALLOC_CTX *ctx = talloc_tos();
-       const char *cservername = canon_servername(servername);
-
-       ZERO_STRUCTP(info);
-
-       info->version=driver.info_3->cversion;
-
-       init_unistr( &info->name, driver.info_3->name );
-       init_unistr( &info->architecture, driver.info_3->environment );
-
-       if (strlen(driver.info_3->driverpath)) {
-               temp = talloc_asprintf(ctx,
-                               "\\\\%s%s",
-                               cservername,
-                               driver.info_3->driverpath);
-               init_unistr( &info->driverpath, temp );
-       } else
-               init_unistr( &info->driverpath, "" );
-
-       TALLOC_FREE(temp);
-       if (strlen(driver.info_3->datafile)) {
-               temp = talloc_asprintf(ctx,
-                               "\\\\%s%s",
-                               cservername,
-                               driver.info_3->datafile);
-               init_unistr( &info->datafile, temp );
-       } else
-               init_unistr( &info->datafile, "" );
-
-       TALLOC_FREE(temp);
-       if (strlen(driver.info_3->configfile)) {
-               temp = talloc_asprintf(ctx,
-                               "\\\\%s%s",
-                               cservername,
-                               driver.info_3->configfile);
-               init_unistr( &info->configfile, temp );
-       } else
-               init_unistr( &info->configfile, "" );
-
-       TALLOC_FREE(temp);
-       if (strlen(driver.info_3->helpfile)) {
-               temp = talloc_asprintf(ctx,
-                               "\\\\%s%s",
-                               cservername,
-                               driver.info_3->helpfile);
-               init_unistr( &info->helpfile, temp );
-       } else
-               init_unistr( &info->helpfile, "" );
-
-       TALLOC_FREE(temp);
-       init_unistr( &info->monitorname, driver.info_3->monitorname );
-       init_unistr( &info->defaultdatatype, driver.info_3->defaultdatatype );
-
-       info->dependentfiles=NULL;
-       init_unistr_array(&info->dependentfiles, driver.info_3->dependentfiles, cservername);
-}
-
-/********************************************************************
- * construct_printer_info_3
- * fill a printer_info_3 struct
- ********************************************************************/
-
-static WERROR construct_printer_driver_info_3(DRIVER_INFO_3 *info, int snum, const char *servername, fstring architecture, uint32 version)
+static WERROR construct_printer_driver_info_3(TALLOC_CTX *mem_ctx,
+                                             struct spoolss_DriverInfo3 *r,
+                                             int snum,
+                                             const char *servername,
+                                             const char *architecture,
+                                             uint32_t version)
 {
        NT_PRINTER_INFO_LEVEL *printer = NULL;
        NT_PRINTER_DRIVER_INFO_LEVEL driver;
@@ -5483,92 +5334,11 @@ static WERROR construct_printer_driver_info_3(DRIVER_INFO_3 *info, int snum, con
 #endif
 
 
-       fill_printer_driver_info_3(info, driver, servername);
+       status = fill_printer_driver_info3(mem_ctx, r, &driver, servername);
 
        free_a_printer(&printer,2);
 
-       return WERR_OK;
-}
-
-/********************************************************************
- * construct_printer_info_6
- * fill a printer_info_6 struct - we know that driver is really level 3. This sucks. JRA.
- ********************************************************************/
-
-static void fill_printer_driver_info_6(DRIVER_INFO_6 *info, NT_PRINTER_DRIVER_INFO_LEVEL driver, const char *servername)
-{
-       char *temp = NULL;
-       fstring nullstr;
-       TALLOC_CTX *ctx = talloc_tos();
-       const char *cservername = canon_servername(servername);
-
-       ZERO_STRUCTP(info);
-       memset(&nullstr, '\0', sizeof(fstring));
-
-       info->version=driver.info_3->cversion;
-
-       init_unistr( &info->name, driver.info_3->name );
-       init_unistr( &info->architecture, driver.info_3->environment );
-
-       if (strlen(driver.info_3->driverpath)) {
-               temp = talloc_asprintf(ctx,
-                               "\\\\%s%s",
-                               cservername,
-                               driver.info_3->driverpath);
-               init_unistr( &info->driverpath, temp );
-       } else
-               init_unistr( &info->driverpath, "" );
-
-       TALLOC_FREE(temp);
-       if (strlen(driver.info_3->datafile)) {
-               temp = talloc_asprintf(ctx,
-                               "\\\\%s%s",
-                               cservername,
-                               driver.info_3->datafile);
-               init_unistr( &info->datafile, temp );
-       } else
-               init_unistr( &info->datafile, "" );
-
-       TALLOC_FREE(temp);
-       if (strlen(driver.info_3->configfile)) {
-               temp = talloc_asprintf(ctx,
-                               "\\\\%s%s",
-                               cservername,
-                               driver.info_3->configfile);
-               init_unistr( &info->configfile, temp );
-       } else
-               init_unistr( &info->configfile, "" );
-
-       TALLOC_FREE(temp);
-       if (strlen(driver.info_3->helpfile)) {
-               temp = talloc_asprintf(ctx,
-                               "\\\\%s%s",
-                               cservername,
-                               driver.info_3->helpfile);
-               init_unistr( &info->helpfile, temp );
-       } else
-               init_unistr( &info->helpfile, "" );
-
-       TALLOC_FREE(temp);
-       init_unistr( &info->monitorname, driver.info_3->monitorname );
-       init_unistr( &info->defaultdatatype, driver.info_3->defaultdatatype );
-
-       info->dependentfiles = NULL;
-       init_unistr_array( &info->dependentfiles, driver.info_3->dependentfiles, servername );
-
-       info->previousdrivernames=NULL;
-       init_unistr_array(&info->previousdrivernames, &nullstr, servername);
-
-       info->driver_date=0;
-
-       info->padding=0;
-       info->driver_version_low=0;
-       info->driver_version_high=0;
-
-       init_unistr( &info->mfgname, "");
-       init_unistr( &info->oem_url, "");
-       init_unistr( &info->hardware_id, "");
-       init_unistr( &info->provider, "");
+       return status;
 }
 
 /********************************************************************
@@ -5576,283 +5346,149 @@ static void fill_printer_driver_info_6(DRIVER_INFO_6 *info, NT_PRINTER_DRIVER_IN
  * fill a printer_info_6 struct
  ********************************************************************/
 
-static WERROR construct_printer_driver_info_6(DRIVER_INFO_6 *info, int snum,
-              const char *servername, fstring architecture, uint32 version)
-{
-       NT_PRINTER_INFO_LEVEL           *printer = NULL;
-       NT_PRINTER_DRIVER_INFO_LEVEL    driver;
-       WERROR                          status;
-
-       ZERO_STRUCT(driver);
-
-       status=get_a_printer(NULL, &printer, 2, lp_const_servicename(snum) );
-
-       DEBUG(8,("construct_printer_driver_info_6: status: %s\n", win_errstr(status)));
-
-       if (!W_ERROR_IS_OK(status))
-               return WERR_INVALID_PRINTER_NAME;
-
-       status = get_a_printer_driver(&driver, 3, printer->info_2->drivername, architecture, version);
-
-       DEBUG(8,("construct_printer_driver_info_6: status: %s\n", win_errstr(status)));
-
-       if (!W_ERROR_IS_OK(status))
-       {
-               /*
-                * Is this a W2k client ?
-                */
-
-               if (version < 3) {
-                       free_a_printer(&printer,2);
-                       return WERR_UNKNOWN_PRINTER_DRIVER;
-               }
-
-               /* Yes - try again with a WinNT driver. */
-               version = 2;
-               status=get_a_printer_driver(&driver, 3, printer->info_2->drivername, architecture, version);
-               DEBUG(8,("construct_printer_driver_info_6: status: %s\n", win_errstr(status)));
-               if (!W_ERROR_IS_OK(status)) {
-                       free_a_printer(&printer,2);
-                       return WERR_UNKNOWN_PRINTER_DRIVER;
-               }
-       }
-
-       fill_printer_driver_info_6(info, driver, servername);
-
-       free_a_printer(&printer,2);
-       free_a_printer_driver(driver, 3);
-
-       return WERR_OK;
-}
-
-/****************************************************************************
-****************************************************************************/
-
-static void free_printer_driver_info_3(DRIVER_INFO_3 *info)
-{
-       SAFE_FREE(info->dependentfiles);
-}
-
-/****************************************************************************
-****************************************************************************/
-
-static void free_printer_driver_info_6(DRIVER_INFO_6 *info)
-{
-       SAFE_FREE(info->dependentfiles);
-}
-
-/****************************************************************************
-****************************************************************************/
-
-static WERROR getprinterdriver2_level1(const char *servername, fstring architecture, uint32 version, int snum, RPC_BUFFER *buffer, uint32 offered, uint32 *needed)
-{
-       DRIVER_INFO_1 *info=NULL;
-       WERROR result;
-
-       if((info=SMB_MALLOC_P(DRIVER_INFO_1)) == NULL)
-               return WERR_NOMEM;
-
-       result = construct_printer_driver_info_1(info, snum, servername, architecture, version);
-       if (!W_ERROR_IS_OK(result))
-               goto out;
-
-       /* check the required size. */
-       *needed += spoolss_size_printer_driver_info_1(info);
-
-       if (*needed > offered) {
-               result = WERR_INSUFFICIENT_BUFFER;
-               goto out;
-       }
-
-       if (!rpcbuf_alloc_size(buffer, *needed)) {
-               result = WERR_NOMEM;
-               goto out;
-       }
-
-       /* fill the buffer with the structures */
-       smb_io_printer_driver_info_1("", buffer, info, 0);
-
-out:
-       /* clear memory */
-       SAFE_FREE(info);
-
-       return result;
-}
-
-/****************************************************************************
-****************************************************************************/
-
-static WERROR getprinterdriver2_level2(const char *servername, fstring architecture, uint32 version, int snum, RPC_BUFFER *buffer, uint32 offered, uint32 *needed)
-{
-       DRIVER_INFO_2 *info=NULL;
-       WERROR result;
-
-       if((info=SMB_MALLOC_P(DRIVER_INFO_2)) == NULL)
-               return WERR_NOMEM;
-
-       result = construct_printer_driver_info_2(info, snum, servername, architecture, version);
-       if (!W_ERROR_IS_OK(result))
-               goto out;
-
-       /* check the required size. */
-       *needed += spoolss_size_printer_driver_info_2(info);
-
-       if (*needed > offered) {
-               result = WERR_INSUFFICIENT_BUFFER;
-               goto out;
-       }
-
-       if (!rpcbuf_alloc_size(buffer, *needed)) {
-               result = WERR_NOMEM;
-               goto out;
-       }
-
-       /* fill the buffer with the structures */
-       smb_io_printer_driver_info_2("", buffer, info, 0);
-
-out:
-       /* clear memory */
-       SAFE_FREE(info);
-
-       return result;
-}
-
-/****************************************************************************
-****************************************************************************/
-
-static WERROR getprinterdriver2_level3(const char *servername, fstring architecture, uint32 version, int snum, RPC_BUFFER *buffer, uint32 offered, uint32 *needed)
-{
-       DRIVER_INFO_3 info;
-       WERROR result;
-
-       ZERO_STRUCT(info);
-
-       result = construct_printer_driver_info_3(&info, snum, servername, architecture, version);
-       if (!W_ERROR_IS_OK(result))
-               goto out;
-
-       /* check the required size. */
-       *needed += spoolss_size_printer_driver_info_3(&info);
-
-       if (*needed > offered) {
-               result = WERR_INSUFFICIENT_BUFFER;
-               goto out;
-       }
-
-       if (!rpcbuf_alloc_size(buffer, *needed)) {
-               result = WERR_NOMEM;
-               goto out;
-       }
-
-       /* fill the buffer with the structures */
-       smb_io_printer_driver_info_3("", buffer, &info, 0);
+static WERROR construct_printer_driver_info_6(TALLOC_CTX *mem_ctx,
+                                             struct spoolss_DriverInfo6 *r,
+                                             int snum,
+                                             const char *servername,
+                                             const char *architecture,
+                                             uint32_t version)
+{
+       NT_PRINTER_INFO_LEVEL           *printer = NULL;
+       NT_PRINTER_DRIVER_INFO_LEVEL    driver;
+       WERROR                          status;
 
-out:
-       free_printer_driver_info_3(&info);
+       ZERO_STRUCT(driver);
 
-       return result;
-}
+       status=get_a_printer(NULL, &printer, 2, lp_const_servicename(snum) );
 
-/****************************************************************************
-****************************************************************************/
+       DEBUG(8,("construct_printer_driver_info_6: status: %s\n", win_errstr(status)));
 
-static WERROR getprinterdriver2_level6(const char *servername, fstring architecture, uint32 version, int snum, RPC_BUFFER *buffer, uint32 offered, uint32 *needed)
-{
-       DRIVER_INFO_6 info;
-       WERROR result;
+       if (!W_ERROR_IS_OK(status))
+               return WERR_INVALID_PRINTER_NAME;
 
-       ZERO_STRUCT(info);
+       status = get_a_printer_driver(&driver, 3, printer->info_2->drivername, architecture, version);
 
-       result = construct_printer_driver_info_6(&info, snum, servername, architecture, version);
-       if (!W_ERROR_IS_OK(result))
-               goto out;
+       DEBUG(8,("construct_printer_driver_info_6: status: %s\n", win_errstr(status)));
 
-       /* check the required size. */
-       *needed += spoolss_size_printer_driver_info_6(&info);
+       if (!W_ERROR_IS_OK(status))
+       {
+               /*
+                * Is this a W2k client ?
+                */
 
-       if (*needed > offered) {
-               result = WERR_INSUFFICIENT_BUFFER;
-               goto out;
-       }
+               if (version < 3) {
+                       free_a_printer(&printer,2);
+                       return WERR_UNKNOWN_PRINTER_DRIVER;
+               }
 
-       if (!rpcbuf_alloc_size(buffer, *needed)) {
-               result = WERR_NOMEM;
-               goto out;
+               /* Yes - try again with a WinNT driver. */
+               version = 2;
+               status=get_a_printer_driver(&driver, 3, printer->info_2->drivername, architecture, version);
+               DEBUG(8,("construct_printer_driver_info_6: status: %s\n", win_errstr(status)));
+               if (!W_ERROR_IS_OK(status)) {
+                       free_a_printer(&printer,2);
+                       return WERR_UNKNOWN_PRINTER_DRIVER;
+               }
        }
 
-       /* fill the buffer with the structures */
-       smb_io_printer_driver_info_6("", buffer, &info, 0);
+       status = fill_printer_driver_info6(mem_ctx, r, &driver, servername);
 
-out:
-       free_printer_driver_info_6(&info);
+       free_a_printer(&printer,2);
+       free_a_printer_driver(driver, 3);
 
-       return result;
+       return status;
 }
 
-/****************************************************************************
-****************************************************************************/
+/****************************************************************
+ _spoolss_GetPrinterDriver2
+****************************************************************/
 
-WERROR _spoolss_getprinterdriver2(pipes_struct *p, SPOOL_Q_GETPRINTERDRIVER2 *q_u, SPOOL_R_GETPRINTERDRIVER2 *r_u)
-{
-       POLICY_HND *handle = &q_u->handle;
-       UNISTR2 *uni_arch = &q_u->architecture;
-       uint32 level = q_u->level;
-       uint32 clientmajorversion = q_u->clientmajorversion;
-       RPC_BUFFER *buffer = NULL;
-       uint32 offered = q_u->offered;
-       uint32 *needed = &r_u->needed;
-       uint32 *servermajorversion = &r_u->servermajorversion;
-       uint32 *serverminorversion = &r_u->serverminorversion;
+WERROR _spoolss_GetPrinterDriver2(pipes_struct *p,
+                                 struct spoolss_GetPrinterDriver2 *r)
+{
        Printer_entry *printer;
+       WERROR result;
 
-       fstring servername;
-       fstring architecture;
+       const char *servername;
        int snum;
 
        /* that's an [in out] buffer */
 
-       if (!q_u->buffer && (offered!=0)) {
+       if (!r->in.buffer && (r->in.offered != 0)) {
                return WERR_INVALID_PARAM;
        }
 
-       rpcbuf_move(q_u->buffer, &r_u->buffer);
-       buffer = r_u->buffer;
+       DEBUG(4,("_spoolss_GetPrinterDriver2\n"));
 
-       DEBUG(4,("_spoolss_getprinterdriver2\n"));
-
-       if ( !(printer = find_printer_index_by_hnd( p, handle )) ) {
-               DEBUG(0,("_spoolss_getprinterdriver2: invalid printer handle!\n"));
+       if (!(printer = find_printer_index_by_hnd( p, r->in.handle))) {
+               DEBUG(0,("_spoolss_GetPrinterDriver2: invalid printer handle!\n"));
                return WERR_INVALID_PRINTER_NAME;
        }
 
-       *needed = 0;
-       *servermajorversion = 0;
-       *serverminorversion = 0;
+       *r->out.needed = 0;
+       *r->out.server_major_version = 0;
+       *r->out.server_minor_version = 0;
 
-       fstrcpy(servername, get_server_name( printer ));
-       unistr2_to_ascii(architecture, uni_arch, sizeof(architecture));
+       servername = get_server_name(printer);
 
-       if (!get_printer_snum(p, handle, &snum, NULL))
+       if (!get_printer_snum(p, r->in.handle, &snum, NULL)) {
                return WERR_BADFID;
+       }
 
-       switch (level) {
+       switch (r->in.level) {
        case 1:
-               return getprinterdriver2_level1(servername, architecture, clientmajorversion, snum, buffer, offered, needed);
+               result = construct_printer_driver_info_1(p->mem_ctx,
+                                                        &r->out.info->info1,
+                                                        snum,
+                                                        servername,
+                                                        r->in.architecture,
+                                                        r->in.client_major_version);
+               break;
        case 2:
-               return getprinterdriver2_level2(servername, architecture, clientmajorversion, snum, buffer, offered, needed);
+               result = construct_printer_driver_info_2(p->mem_ctx,
+                                                        &r->out.info->info2,
+                                                        snum,
+                                                        servername,
+                                                        r->in.architecture,
+                                                        r->in.client_major_version);
+               break;
        case 3:
-               return getprinterdriver2_level3(servername, architecture, clientmajorversion, snum, buffer, offered, needed);
+               result = construct_printer_driver_info_3(p->mem_ctx,
+                                                        &r->out.info->info3,
+                                                        snum,
+                                                        servername,
+                                                        r->in.architecture,
+                                                        r->in.client_major_version);
+               break;
        case 6:
-               return getprinterdriver2_level6(servername, architecture, clientmajorversion, snum, buffer, offered, needed);
+               result = construct_printer_driver_info_6(p->mem_ctx,
+                                                        &r->out.info->info6,
+                                                        snum,
+                                                        servername,
+                                                        r->in.architecture,
+                                                        r->in.client_major_version);
+               break;
+       default:
 #if 0  /* JERRY */
        case 101:
                /* apparently this call is the equivalent of
                   EnumPrinterDataEx() for the DsDriver key */
                break;
 #endif
+               result = WERR_UNKNOWN_LEVEL;
+               break;
        }
 
-       return WERR_UNKNOWN_LEVEL;
+       if (!W_ERROR_IS_OK(result)) {
+               TALLOC_FREE(r->out.info);
+               return result;
+       }
+
+       *r->out.needed  = SPOOLSS_BUFFER_UNION(spoolss_DriverInfo, NULL,
+                                              r->out.info, r->in.level);
+       r->out.info     = SPOOLSS_BUFFER_OK(r->out.info, NULL);
+
+       return SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER);
 }
 
 
@@ -5950,7 +5586,7 @@ WERROR _spoolss_StartDocPrinter(pipes_struct *p,
        }
 
        Printer->jobid = print_job_start(p->server_info, snum,
-                                        CONST_DISCARD(char *,info_1->document_name),
+                                        info_1->document_name,
                                         Printer->nt_devmode);
 
        /* An error occured in print_job_start() so return an appropriate
@@ -6039,18 +5675,18 @@ static WERROR control_printer(POLICY_HND *handle, uint32 command,
                return WERR_BADFID;
 
        switch (command) {
-       case PRINTER_CONTROL_PAUSE:
+       case SPOOLSS_PRINTER_CONTROL_PAUSE:
                if (print_queue_pause(p->server_info, snum, &errcode)) {
                        errcode = WERR_OK;
                }
                break;
-       case PRINTER_CONTROL_RESUME:
-       case PRINTER_CONTROL_UNPAUSE:
+       case SPOOLSS_PRINTER_CONTROL_RESUME:
+       case SPOOLSS_PRINTER_CONTROL_UNPAUSE:
                if (print_queue_resume(p->server_info, snum, &errcode)) {
                        errcode = WERR_OK;
                }
                break;
-       case PRINTER_CONTROL_PURGE:
+       case SPOOLSS_PRINTER_CONTROL_PURGE:
                if (print_queue_purge(p->server_info, snum, &errcode)) {
                        errcode = WERR_OK;
                }
@@ -6096,8 +5732,7 @@ WERROR _spoolss_AbortPrinter(pipes_struct *p,
  * when updating a printer description
  ********************************************************************/
 
-static WERROR update_printer_sec(POLICY_HND *handle, uint32 level,
-                                const SPOOL_PRINTER_INFO_LEVEL *info,
+static WERROR update_printer_sec(POLICY_HND *handle,
                                 pipes_struct *p, SEC_DESC_BUF *secdesc_ctr)
 {
        SEC_DESC_BUF *new_secdesc_ctr = NULL, *old_secdesc_ctr = NULL;
@@ -6383,9 +6018,9 @@ bool add_printer_hook(TALLOC_CTX *ctx, NT_USER_TOKEN *token, NT_PRINTER_INFO_LEV
  * when updating a printer description.
  ********************************************************************/
 
-static WERROR update_printer(pipes_struct *p, POLICY_HND *handle, uint32 level,
-                           const SPOOL_PRINTER_INFO_LEVEL *info,
-                           DEVICEMODE *devmode)
+static WERROR update_printer(pipes_struct *p, POLICY_HND *handle,
+                            struct spoolss_SetPrinterInfoCtr *info_ctr,
+                            struct spoolss_DeviceMode *devmode)
 {
        int snum;
        NT_PRINTER_INFO_LEVEL *printer = NULL, *old_printer = NULL;
@@ -6422,7 +6057,7 @@ static WERROR update_printer(pipes_struct *p, POLICY_HND *handle, uint32 level,
         * just read from the tdb in the pointer 'printer'.
         */
 
-       if (!convert_printer_info(info, printer, level)) {
+       if (!convert_printer_info_new(info_ctr, printer)) {
                result =  WERR_NOMEM;
                goto done;
        }
@@ -6432,8 +6067,9 @@ static WERROR update_printer(pipes_struct *p, POLICY_HND *handle, uint32 level,
                   convert it and link it*/
 
                DEBUGADD(8,("update_printer: Converting the devicemode struct\n"));
-               if (!convert_devicemode(printer->info_2->printername, devmode,
-                               &printer->info_2->devmode)) {
+               if (!convert_devicemode_new(printer->info_2->printername,
+                                           devmode,
+                                           &printer->info_2->devmode)) {
                        result =  WERR_NOMEM;
                        goto done;
                }
@@ -6577,10 +6213,9 @@ done:
 /****************************************************************************
 ****************************************************************************/
 static WERROR publish_or_unpublish_printer(pipes_struct *p, POLICY_HND *handle,
-                                  const SPOOL_PRINTER_INFO_LEVEL *info)
+                                          struct spoolss_SetPrinterInfo7 *info7)
 {
 #ifdef HAVE_ADS
-       SPOOL_PRINTER_INFO_LEVEL_7 *info7 = info->info_7;
        int snum;
        Printer_entry *Printer;
 
@@ -6605,42 +6240,45 @@ static WERROR publish_or_unpublish_printer(pipes_struct *p, POLICY_HND *handle,
        return WERR_UNKNOWN_LEVEL;
 #endif
 }
-/****************************************************************************
-****************************************************************************/
 
-WERROR _spoolss_setprinter(pipes_struct *p, SPOOL_Q_SETPRINTER *q_u, SPOOL_R_SETPRINTER *r_u)
+/****************************************************************
+ _spoolss_SetPrinter
+****************************************************************/
+
+WERROR _spoolss_SetPrinter(pipes_struct *p,
+                          struct spoolss_SetPrinter *r)
 {
-       POLICY_HND *handle = &q_u->handle;
-       uint32 level = q_u->level;
-       SPOOL_PRINTER_INFO_LEVEL *info = &q_u->info;
-       DEVMODE_CTR devmode_ctr = q_u->devmode_ctr;
-       SEC_DESC_BUF *secdesc_ctr = q_u->secdesc_ctr;
-       uint32 command = q_u->command;
+       POLICY_HND *handle = r->in.handle;
        WERROR result;
 
        Printer_entry *Printer = find_printer_index_by_hnd(p, handle);
 
        if (!Printer) {
-               DEBUG(2,("_spoolss_setprinter: Invalid handle (%s:%u:%u)\n", OUR_HANDLE(handle)));
+               DEBUG(2,("_spoolss_SetPrinter: Invalid handle (%s:%u:%u)\n",
+                       OUR_HANDLE(handle)));
                return WERR_BADFID;
        }
 
        /* check the level */
-       switch (level) {
+       switch (r->in.info_ctr->level) {
                case 0:
-                       return control_printer(handle, command, p);
+                       return control_printer(handle, r->in.command, p);
                case 2:
-                       result = update_printer(p, handle, level, info, devmode_ctr.devmode);
+                       result = update_printer(p, handle,
+                                               r->in.info_ctr,
+                                               r->in.devmode_ctr->devmode);
                        if (!W_ERROR_IS_OK(result))
                                return result;
-                       if (secdesc_ctr)
-                               result = update_printer_sec(handle, level, info, p, secdesc_ctr);
+                       if (r->in.secdesc_ctr->sd)
+                               result = update_printer_sec(handle, p,
+                                                           r->in.secdesc_ctr);
                        return result;
                case 3:
-                       return update_printer_sec(handle, level, info, p,
-                                                 secdesc_ctr);
+                       return update_printer_sec(handle, p,
+                                                 r->in.secdesc_ctr);
                case 7:
-                       return publish_or_unpublish_printer(p, handle, info);
+                       return publish_or_unpublish_printer(p, handle,
+                                                           r->in.info_ctr->info.info7);
                default:
                        return WERR_UNKNOWN_LEVEL;
        }
@@ -6678,8 +6316,7 @@ WERROR _spoolss_FindClosePrinterNotify(pipes_struct *p,
        Printer->notify.options=0;
        Printer->notify.localmachine[0]='\0';
        Printer->notify.printerlocal=0;
-       if (Printer->notify.option)
-               free_spool_notify_option(&Printer->notify.option);
+       TALLOC_FREE(Printer->notify.option);
        Printer->notify.client_connected=False;
 
        return WERR_OK;
@@ -6699,251 +6336,284 @@ WERROR _spoolss_AddJob(pipes_struct *p,
        /* this is what a NT server returns for AddJob. AddJob must fail on
         * non-local printers */
 
+       if (r->in.level != 1) {
+               return WERR_UNKNOWN_LEVEL;
+       }
+
        return WERR_INVALID_PARAM;
 }
 
 /****************************************************************************
+fill_job_info1
 ****************************************************************************/
 
-static void fill_job_info_1(JOB_INFO_1 *job_info, const print_queue_struct *queue,
-                            int position, int snum,
-                            const NT_PRINTER_INFO_LEVEL *ntprinter)
+static WERROR fill_job_info1(TALLOC_CTX *mem_ctx,
+                            struct spoolss_JobInfo1 *r,
+                            const print_queue_struct *queue,
+                            int position, int snum,
+                            const NT_PRINTER_INFO_LEVEL *ntprinter)
 {
        struct tm *t;
 
-       t=gmtime(&queue->time);
+       t = gmtime(&queue->time);
 
-       job_info->jobid=queue->job;
-       init_unistr(&job_info->printername, lp_servicename(snum));
-       init_unistr(&job_info->machinename, ntprinter->info_2->servername);
-       init_unistr(&job_info->username, queue->fs_user);
-       init_unistr(&job_info->document, queue->fs_file);
-       init_unistr(&job_info->datatype, "RAW");
-       init_unistr(&job_info->text_status, "");
-       job_info->status=nt_printj_status(queue->status);
-       job_info->priority=queue->priority;
-       job_info->position=position;
-       job_info->totalpages=queue->page_count;
-       job_info->pagesprinted=0;
+       r->job_id               = queue->job;
 
-       make_systemtime(&job_info->submitted, t);
+       r->printer_name         = talloc_strdup(mem_ctx, lp_servicename(snum));
+       W_ERROR_HAVE_NO_MEMORY(r->printer_name);
+       r->server_name          = talloc_strdup(mem_ctx, ntprinter->info_2->servername);
+       W_ERROR_HAVE_NO_MEMORY(r->server_name);
+       r->user_name            = talloc_strdup(mem_ctx, queue->fs_user);
+       W_ERROR_HAVE_NO_MEMORY(r->user_name);
+       r->document_name        = talloc_strdup(mem_ctx, queue->fs_file);
+       W_ERROR_HAVE_NO_MEMORY(r->document_name);
+       r->data_type            = talloc_strdup(mem_ctx, "RAW");
+       W_ERROR_HAVE_NO_MEMORY(r->data_type);
+       r->text_status          = talloc_strdup(mem_ctx, "");
+       W_ERROR_HAVE_NO_MEMORY(r->text_status);
+
+       r->status               = nt_printj_status(queue->status);
+       r->priority             = queue->priority;
+       r->position             = position;
+       r->total_pages          = queue->page_count;
+       r->pages_printed        = 0; /* ??? */
+
+       init_systemtime(&r->submitted, t);
+
+       return WERR_OK;
 }
 
 /****************************************************************************
+fill_job_info2
 ****************************************************************************/
 
-static bool fill_job_info_2(JOB_INFO_2 *job_info, const print_queue_struct *queue,
-                            int position, int snum,
-                           const NT_PRINTER_INFO_LEVEL *ntprinter,
-                           DEVICEMODE *devmode)
+static WERROR fill_job_info2(TALLOC_CTX *mem_ctx,
+                            struct spoolss_JobInfo2 *r,
+                            const print_queue_struct *queue,
+                            int position, int snum,
+                            const NT_PRINTER_INFO_LEVEL *ntprinter,
+                            struct spoolss_DeviceMode *devmode)
 {
        struct tm *t;
 
-       t=gmtime(&queue->time);
-
-       job_info->jobid=queue->job;
-
-       init_unistr(&job_info->printername, ntprinter->info_2->printername);
-
-       init_unistr(&job_info->machinename, ntprinter->info_2->servername);
-       init_unistr(&job_info->username, queue->fs_user);
-       init_unistr(&job_info->document, queue->fs_file);
-       init_unistr(&job_info->notifyname, queue->fs_user);
-       init_unistr(&job_info->datatype, "RAW");
-       init_unistr(&job_info->printprocessor, "winprint");
-       init_unistr(&job_info->parameters, "");
-       init_unistr(&job_info->drivername, ntprinter->info_2->drivername);
-       init_unistr(&job_info->text_status, "");
-
-/* and here the security descriptor */
+       t = gmtime(&queue->time);
+
+       r->job_id               = queue->job;
+
+       r->printer_name         = talloc_strdup(mem_ctx, lp_servicename(snum));
+       W_ERROR_HAVE_NO_MEMORY(r->printer_name);
+       r->server_name          = talloc_strdup(mem_ctx, ntprinter->info_2->servername);
+       W_ERROR_HAVE_NO_MEMORY(r->server_name);
+       r->user_name            = talloc_strdup(mem_ctx, queue->fs_user);
+       W_ERROR_HAVE_NO_MEMORY(r->user_name);
+       r->document_name        = talloc_strdup(mem_ctx, queue->fs_file);
+       W_ERROR_HAVE_NO_MEMORY(r->document_name);
+       r->notify_name          = talloc_strdup(mem_ctx, queue->fs_user);
+       W_ERROR_HAVE_NO_MEMORY(r->notify_name);
+       r->data_type            = talloc_strdup(mem_ctx, "RAW");
+       W_ERROR_HAVE_NO_MEMORY(r->data_type);
+       r->print_processor      = talloc_strdup(mem_ctx, "winprint");
+       W_ERROR_HAVE_NO_MEMORY(r->print_processor);
+       r->parameters           = talloc_strdup(mem_ctx, "");
+       W_ERROR_HAVE_NO_MEMORY(r->parameters);
+       r->driver_name          = talloc_strdup(mem_ctx, ntprinter->info_2->drivername);
+       W_ERROR_HAVE_NO_MEMORY(r->driver_name);
+
+       r->devmode              = devmode;
+
+       r->text_status          = talloc_strdup(mem_ctx, "");
+       W_ERROR_HAVE_NO_MEMORY(r->text_status);
+
+       r->secdesc              = NULL;
+
+       r->status               = nt_printj_status(queue->status);
+       r->priority             = queue->priority;
+       r->position             = position;
+       r->start_time           = 0;
+       r->until_time           = 0;
+       r->total_pages          = queue->page_count;
+       r->size                 = queue->size;
+       init_systemtime(&r->submitted, t);
+       r->time                 = 0;
+       r->pages_printed        = 0; /* ??? */
 
-       job_info->status=nt_printj_status(queue->status);
-       job_info->priority=queue->priority;
-       job_info->position=position;
-       job_info->starttime=0;
-       job_info->untiltime=0;
-       job_info->totalpages=queue->page_count;
-       job_info->size=queue->size;
-       make_systemtime(&(job_info->submitted), t);
-       job_info->timeelapsed=0;
-       job_info->pagesprinted=0;
-
-       job_info->devmode = devmode;
-
-       return (True);
+       return WERR_OK;
 }
 
 /****************************************************************************
  Enumjobs at level 1.
 ****************************************************************************/
 
-static WERROR enumjobs_level1(const print_queue_struct *queue, int snum,
+static WERROR enumjobs_level1(TALLOC_CTX *mem_ctx,
+                             const print_queue_struct *queue,
+                             uint32_t num_queues, int snum,
                               const NT_PRINTER_INFO_LEVEL *ntprinter,
-                             RPC_BUFFER *buffer, uint32 offered,
-                             uint32 *needed, uint32 *returned)
+                             union spoolss_JobInfo **info_p,
+                             uint32_t *count)
 {
-       JOB_INFO_1 *info;
+       union spoolss_JobInfo *info;
        int i;
        WERROR result = WERR_OK;
 
-       info=SMB_MALLOC_ARRAY(JOB_INFO_1,*returned);
-       if (info==NULL) {
-               *returned=0;
-               return WERR_NOMEM;
-       }
-
-       for (i=0; i<*returned; i++)
-               fill_job_info_1( &info[i], &queue[i], i, snum, ntprinter );
+       info = TALLOC_ARRAY(mem_ctx, union spoolss_JobInfo, num_queues);
+       W_ERROR_HAVE_NO_MEMORY(info);
 
-       /* check the required size. */
-       for (i=0; i<*returned; i++)
-               (*needed) += spoolss_size_job_info_1(&info[i]);
+       *count = num_queues;
 
-       if (*needed > offered) {
-               result = WERR_INSUFFICIENT_BUFFER;
-               goto out;
+       for (i=0; i<*count; i++) {
+               result = fill_job_info1(info,
+                                       &info[i].info1,
+                                       &queue[i],
+                                       i,
+                                       snum,
+                                       ntprinter);
+               if (!W_ERROR_IS_OK(result)) {
+                       goto out;
+               }
        }
 
-       if (!rpcbuf_alloc_size(buffer, *needed)) {
-               result = WERR_NOMEM;
-               goto out;
+ out:
+       if (!W_ERROR_IS_OK(result)) {
+               TALLOC_FREE(info);
+               *count = 0;
+               return result;
        }
 
-       /* fill the buffer with the structures */
-       for (i=0; i<*returned; i++)
-               smb_io_job_info_1("", buffer, &info[i], 0);
-
-out:
-       /* clear memory */
-       SAFE_FREE(info);
+       *info_p = info;
 
-       if ( !W_ERROR_IS_OK(result) )
-               *returned = 0;
-
-       return result;
+       return WERR_OK;
 }
 
 /****************************************************************************
  Enumjobs at level 2.
 ****************************************************************************/
 
-static WERROR enumjobs_level2(const print_queue_struct *queue, int snum,
+static WERROR enumjobs_level2(TALLOC_CTX *mem_ctx,
+                             const print_queue_struct *queue,
+                             uint32_t num_queues, int snum,
                               const NT_PRINTER_INFO_LEVEL *ntprinter,
-                             RPC_BUFFER *buffer, uint32 offered,
-                             uint32 *needed, uint32 *returned)
+                             union spoolss_JobInfo **info_p,
+                             uint32_t *count)
 {
-       JOB_INFO_2 *info = NULL;
+       union spoolss_JobInfo *info;
        int i;
        WERROR result = WERR_OK;
-       DEVICEMODE *devmode = NULL;
 
-       if ( !(info = SMB_MALLOC_ARRAY(JOB_INFO_2,*returned)) ) {
-               *returned=0;
-               return WERR_NOMEM;
-       }
+       info = TALLOC_ARRAY(mem_ctx, union spoolss_JobInfo, num_queues);
+       W_ERROR_HAVE_NO_MEMORY(info);
 
-       /* this should not be a failure condition if the devmode is NULL */
+       *count = num_queues;
 
-       devmode = construct_dev_mode(lp_const_servicename(snum));
+       for (i=0; i<*count; i++) {
 
-       for (i=0; i<*returned; i++)
-               fill_job_info_2(&(info[i]), &queue[i], i, snum, ntprinter, devmode);
+               struct spoolss_DeviceMode *devmode;
 
-       /* check the required size. */
-       for (i=0; i<*returned; i++)
-               (*needed) += spoolss_size_job_info_2(&info[i]);
+               devmode = construct_dev_mode_new(info, lp_const_servicename(snum));
+               if (!devmode) {
+                       result = WERR_NOMEM;
+                       goto out;
+               }
 
-       if (*needed > offered) {
-               result = WERR_INSUFFICIENT_BUFFER;
-               goto out;
+               result = fill_job_info2(info,
+                                       &info[i].info2,
+                                       &queue[i],
+                                       i,
+                                       snum,
+                                       ntprinter,
+                                       devmode);
+               if (!W_ERROR_IS_OK(result)) {
+                       goto out;
+               }
        }
 
-       if (!rpcbuf_alloc_size(buffer, *needed)) {
-               result = WERR_NOMEM;
-               goto out;
+ out:
+       if (!W_ERROR_IS_OK(result)) {
+               TALLOC_FREE(info);
+               *count = 0;
+               return result;
        }
 
-       /* fill the buffer with the structures */
-       for (i=0; i<*returned; i++)
-               smb_io_job_info_2("", buffer, &info[i], 0);
-
-out:
-       free_devmode(devmode);
-       SAFE_FREE(info);
-
-       if ( !W_ERROR_IS_OK(result) )
-               *returned = 0;
-
-       return result;
+       *info_p = info;
 
+       return WERR_OK;
 }
 
-/****************************************************************************
- Enumjobs.
-****************************************************************************/
+/****************************************************************
+ _spoolss_EnumJobs
+****************************************************************/
 
-WERROR _spoolss_enumjobs( pipes_struct *p, SPOOL_Q_ENUMJOBS *q_u, SPOOL_R_ENUMJOBS *r_u)
+WERROR _spoolss_EnumJobs(pipes_struct *p,
+                        struct spoolss_EnumJobs *r)
 {
-       POLICY_HND *handle = &q_u->handle;
-       uint32 level = q_u->level;
-       RPC_BUFFER *buffer = NULL;
-       uint32 offered = q_u->offered;
-       uint32 *needed = &r_u->needed;
-       uint32 *returned = &r_u->returned;
-       WERROR wret;
+       WERROR result;
        NT_PRINTER_INFO_LEVEL *ntprinter = NULL;
        int snum;
        print_status_struct prt_status;
-       print_queue_struct *queue=NULL;
+       print_queue_struct *queue = NULL;
+       uint32_t count;
 
        /* that's an [in out] buffer */
 
-       if (!q_u->buffer && (offered!=0)) {
+       if (!r->in.buffer && (r->in.offered != 0)) {
                return WERR_INVALID_PARAM;
        }
 
-       rpcbuf_move(q_u->buffer, &r_u->buffer);
-       buffer = r_u->buffer;
+       DEBUG(4,("_spoolss_EnumJobs\n"));
 
-       DEBUG(4,("_spoolss_enumjobs\n"));
-
-       *needed=0;
-       *returned=0;
+       *r->out.needed = 0;
+       *r->out.count = 0;
+       *r->out.info = NULL;
 
        /* lookup the printer snum and tdb entry */
 
-       if (!get_printer_snum(p, handle, &snum, NULL))
+       if (!get_printer_snum(p, r->in.handle, &snum, NULL)) {
                return WERR_BADFID;
+       }
 
-       wret = get_a_printer(NULL, &ntprinter, 2, lp_servicename(snum));
-       if ( !W_ERROR_IS_OK(wret) )
-               return wret;
+       result = get_a_printer(NULL, &ntprinter, 2, lp_servicename(snum));
+       if (!W_ERROR_IS_OK(result)) {
+               return result;
+       }
 
-       *returned = print_queue_status(snum, &queue, &prt_status);
-       DEBUGADD(4,("count:[%d], status:[%d], [%s]\n", *returned, prt_status.status, prt_status.message));
+       count = print_queue_status(snum, &queue, &prt_status);
+       DEBUGADD(4,("count:[%d], status:[%d], [%s]\n",
+               count, prt_status.status, prt_status.message));
 
-       if (*returned == 0) {
+       if (count == 0) {
                SAFE_FREE(queue);
                free_a_printer(&ntprinter, 2);
                return WERR_OK;
        }
 
-       switch (level) {
+       switch (r->in.level) {
        case 1:
-               wret = enumjobs_level1(queue, snum, ntprinter, buffer, offered, needed, returned);
+               result = enumjobs_level1(p->mem_ctx, queue, count, snum,
+                                        ntprinter, r->out.info, r->out.count);
                break;
        case 2:
-               wret = enumjobs_level2(queue, snum, ntprinter, buffer, offered, needed, returned);
+               result = enumjobs_level2(p->mem_ctx, queue, count, snum,
+                                        ntprinter, r->out.info, r->out.count);
                break;
        default:
-               *returned=0;
-               wret = WERR_UNKNOWN_LEVEL;
+               result = WERR_UNKNOWN_LEVEL;
                break;
        }
 
        SAFE_FREE(queue);
-       free_a_printer( &ntprinter, 2 );
-       return wret;
+       free_a_printer(&ntprinter, 2);
+
+       if (!W_ERROR_IS_OK(result)) {
+               return result;
+       }
+
+       *r->out.needed  = SPOOLSS_BUFFER_UNION_ARRAY(p->mem_ctx,
+                                                    spoolss_EnumJobs, NULL,
+                                                    *r->out.info, r->in.level,
+                                                    *r->out.count);
+       *r->out.info    = SPOOLSS_BUFFER_OK(*r->out.info, NULL);
+       *r->out.count   = SPOOLSS_BUFFER_OK(*r->out.count, 0);
+
+       return SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER);
 }
 
 /****************************************************************
@@ -7007,455 +6677,479 @@ WERROR _spoolss_SetJob(pipes_struct *p,
  Enumerates all printer drivers at level 1.
 ****************************************************************************/
 
-static WERROR enumprinterdrivers_level1(const char *servername, fstring architecture, RPC_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+static WERROR enumprinterdrivers_level1(TALLOC_CTX *mem_ctx,
+                                       const char *servername,
+                                       const char *architecture,
+                                       union spoolss_DriverInfo **info_p,
+                                       uint32_t *count)
 {
        int i;
        int ndrivers;
-       uint32 version;
+       uint32_t version;
        fstring *list = NULL;
        NT_PRINTER_DRIVER_INFO_LEVEL driver;
-       DRIVER_INFO_1 *driver_info_1=NULL;
+       union spoolss_DriverInfo *info = NULL;
        WERROR result = WERR_OK;
 
-       *returned=0;
+       *count = 0;
 
        for (version=0; version<DRIVER_MAX_VERSION; version++) {
-               list=NULL;
-               ndrivers=get_ntdrivers(&list, architecture, version);
-               DEBUGADD(4,("we have:[%d] drivers in environment [%s] and version [%d]\n", ndrivers, architecture, version));
+               list = NULL;
+               ndrivers = get_ntdrivers(&list, architecture, version);
+               DEBUGADD(4,("we have:[%d] drivers in environment [%s] and version [%d]\n",
+                       ndrivers, architecture, version));
 
-               if(ndrivers == -1) {
-                       SAFE_FREE(driver_info_1);
-                       return WERR_NOMEM;
+               if (ndrivers == -1) {
+                       result = WERR_NOMEM;
+                       goto out;
                }
 
-               if(ndrivers != 0) {
-                       if((driver_info_1=SMB_REALLOC_ARRAY(driver_info_1, DRIVER_INFO_1, *returned+ndrivers )) == NULL) {
-                               DEBUG(0,("enumprinterdrivers_level1: failed to enlarge driver info buffer!\n"));
-                               SAFE_FREE(list);
-                               return WERR_NOMEM;
+               if (ndrivers != 0) {
+                       info = TALLOC_REALLOC_ARRAY(mem_ctx, info,
+                                                   union spoolss_DriverInfo,
+                                                   *count + ndrivers);
+                       if (!info) {
+                               DEBUG(0,("enumprinterdrivers_level1: "
+                                       "failed to enlarge driver info buffer!\n"));
+                               result = WERR_NOMEM;
+                               goto out;
                        }
                }
 
                for (i=0; i<ndrivers; i++) {
-                       WERROR status;
                        DEBUGADD(5,("\tdriver: [%s]\n", list[i]));
                        ZERO_STRUCT(driver);
-                       status = get_a_printer_driver(&driver, 3, list[i],
+                       result = get_a_printer_driver(&driver, 3, list[i],
                                                      architecture, version);
-                       if (!W_ERROR_IS_OK(status)) {
-                               SAFE_FREE(list);
-                               SAFE_FREE(driver_info_1);
-                               return status;
+                       if (!W_ERROR_IS_OK(result)) {
+                               goto out;
+                       }
+                       result = fill_printer_driver_info1(info, &info[*count+i].info1,
+                                                          &driver, servername,
+                                                          architecture);
+                       if (!W_ERROR_IS_OK(result)) {
+                               free_a_printer_driver(driver, 3);
+                               goto out;
                        }
-                       fill_printer_driver_info_1(&driver_info_1[*returned+i], driver, servername, architecture );
                        free_a_printer_driver(driver, 3);
                }
 
-               *returned+=ndrivers;
+               *count += ndrivers;
                SAFE_FREE(list);
        }
 
-       /* 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]);
-       }
-
-       if (*needed > offered) {
-               result = WERR_INSUFFICIENT_BUFFER;
-               goto out;
-       }
-
-       if (!rpcbuf_alloc_size(buffer, *needed)) {
-               result = WERR_NOMEM;
-               goto out;
-       }
+ out:
+       SAFE_FREE(list);
 
-       /* fill the buffer with the driver structures */
-       for (i=0; i<*returned; i++) {
-               DEBUGADD(6,("adding driver [%d] to buffer\n",i));
-               smb_io_printer_driver_info_1("", buffer, &driver_info_1[i], 0);
+       if (!W_ERROR_IS_OK(result)) {
+               TALLOC_FREE(info);
+               *count = 0;
+               return result;
        }
 
-out:
-       SAFE_FREE(driver_info_1);
-
-       if ( !W_ERROR_IS_OK(result) )
-               *returned = 0;
+       *info_p = info;
 
-       return result;
+       return WERR_OK;
 }
 
 /****************************************************************************
  Enumerates all printer drivers at level 2.
 ****************************************************************************/
 
-static WERROR enumprinterdrivers_level2(const char *servername, fstring architecture, RPC_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+static WERROR enumprinterdrivers_level2(TALLOC_CTX *mem_ctx,
+                                       const char *servername,
+                                       const char *architecture,
+                                       union spoolss_DriverInfo **info_p,
+                                       uint32_t *count)
 {
        int i;
        int ndrivers;
-       uint32 version;
+       uint32_t version;
        fstring *list = NULL;
        NT_PRINTER_DRIVER_INFO_LEVEL driver;
-       DRIVER_INFO_2 *driver_info_2=NULL;
+       union spoolss_DriverInfo *info = NULL;
        WERROR result = WERR_OK;
 
-       *returned=0;
+       *count = 0;
 
        for (version=0; version<DRIVER_MAX_VERSION; version++) {
-               list=NULL;
-               ndrivers=get_ntdrivers(&list, architecture, version);
-               DEBUGADD(4,("we have:[%d] drivers in environment [%s] and version [%d]\n", ndrivers, architecture, version));
+               list = NULL;
+               ndrivers = get_ntdrivers(&list, architecture, version);
+               DEBUGADD(4,("we have:[%d] drivers in environment [%s] and version [%d]\n",
+                       ndrivers, architecture, version));
 
-               if(ndrivers == -1) {
-                       SAFE_FREE(driver_info_2);
-                       return WERR_NOMEM;
+               if (ndrivers == -1) {
+                       result = WERR_NOMEM;
+                       goto out;
                }
 
-               if(ndrivers != 0) {
-                       if((driver_info_2=SMB_REALLOC_ARRAY(driver_info_2, DRIVER_INFO_2, *returned+ndrivers )) == NULL) {
-                               DEBUG(0,("enumprinterdrivers_level2: failed to enlarge driver info buffer!\n"));
-                               SAFE_FREE(list);
-                               return WERR_NOMEM;
+               if (ndrivers != 0) {
+                       info = TALLOC_REALLOC_ARRAY(mem_ctx, info,
+                                                   union spoolss_DriverInfo,
+                                                   *count + ndrivers);
+                       if (!info) {
+                               DEBUG(0,("enumprinterdrivers_level2: "
+                                       "failed to enlarge driver info buffer!\n"));
+                               result = WERR_NOMEM;
+                               goto out;
                        }
                }
 
                for (i=0; i<ndrivers; i++) {
-                       WERROR status;
-
                        DEBUGADD(5,("\tdriver: [%s]\n", list[i]));
                        ZERO_STRUCT(driver);
-                       status = get_a_printer_driver(&driver, 3, list[i],
+                       result = get_a_printer_driver(&driver, 3, list[i],
                                                      architecture, version);
-                       if (!W_ERROR_IS_OK(status)) {
-                               SAFE_FREE(list);
-                               SAFE_FREE(driver_info_2);
-                               return status;
+                       if (!W_ERROR_IS_OK(result)) {
+                               goto out;
+                       }
+                       result = fill_printer_driver_info2(info, &info[*count+i].info2,
+                                                          &driver, servername);
+                       if (!W_ERROR_IS_OK(result)) {
+                               free_a_printer_driver(driver, 3);
+                               goto out;
                        }
-                       fill_printer_driver_info_2(&driver_info_2[*returned+i], driver, servername);
                        free_a_printer_driver(driver, 3);
                }
 
-               *returned+=ndrivers;
+               *count += ndrivers;
                SAFE_FREE(list);
        }
 
-       /* 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 (*needed > offered) {
-               result = WERR_INSUFFICIENT_BUFFER;
-               goto out;
-       }
-
-       if (!rpcbuf_alloc_size(buffer, *needed)) {
-               result = WERR_NOMEM;
-               goto out;
-       }
+ out:
+       SAFE_FREE(list);
 
-       /* fill the buffer with the form structures */
-       for (i=0; i<*returned; i++) {
-               DEBUGADD(6,("adding driver [%d] to buffer\n",i));
-               smb_io_printer_driver_info_2("", buffer, &(driver_info_2[i]), 0);
+       if (!W_ERROR_IS_OK(result)) {
+               TALLOC_FREE(info);
+               *count = 0;
+               return result;
        }
 
-out:
-       SAFE_FREE(driver_info_2);
-
-       if ( !W_ERROR_IS_OK(result) )
-               *returned = 0;
+       *info_p = info;
 
-       return result;
+       return WERR_OK;
 }
 
 /****************************************************************************
  Enumerates all printer drivers at level 3.
 ****************************************************************************/
 
-static WERROR enumprinterdrivers_level3(const char *servername, fstring architecture, RPC_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+static WERROR enumprinterdrivers_level3(TALLOC_CTX *mem_ctx,
+                                       const char *servername,
+                                       const char *architecture,
+                                       union spoolss_DriverInfo **info_p,
+                                       uint32_t *count)
 {
        int i;
        int ndrivers;
-       uint32 version;
+       uint32_t version;
        fstring *list = NULL;
-       DRIVER_INFO_3 *driver_info_3=NULL;
+       union spoolss_DriverInfo *info = NULL;
        NT_PRINTER_DRIVER_INFO_LEVEL driver;
        WERROR result = WERR_OK;
 
-       *returned=0;
+       *count = 0;
 
        for (version=0; version<DRIVER_MAX_VERSION; version++) {
-               list=NULL;
-               ndrivers=get_ntdrivers(&list, architecture, version);
-               DEBUGADD(4,("we have:[%d] drivers in environment [%s] and version [%d]\n", ndrivers, architecture, version));
+               list = NULL;
+               ndrivers = get_ntdrivers(&list, architecture, version);
+               DEBUGADD(4,("we have:[%d] drivers in environment [%s] and version [%d]\n",
+                       ndrivers, architecture, version));
 
-               if(ndrivers == -1) {
-                       SAFE_FREE(driver_info_3);
-                       return WERR_NOMEM;
+               if (ndrivers == -1) {
+                       result = WERR_NOMEM;
+                       goto out;
                }
 
-               if(ndrivers != 0) {
-                       if((driver_info_3=SMB_REALLOC_ARRAY(driver_info_3, DRIVER_INFO_3, *returned+ndrivers )) == NULL) {
-                               DEBUG(0,("enumprinterdrivers_level3: failed to enlarge driver info buffer!\n"));
-                               SAFE_FREE(list);
-                               return WERR_NOMEM;
+               if (ndrivers != 0) {
+                       info = TALLOC_REALLOC_ARRAY(mem_ctx, info,
+                                                   union spoolss_DriverInfo,
+                                                   *count + ndrivers);
+                       if (!info) {
+                               DEBUG(0,("enumprinterdrivers_level3: "
+                                       "failed to enlarge driver info buffer!\n"));
+                               result = WERR_NOMEM;
+                               goto out;
                        }
                }
 
                for (i=0; i<ndrivers; i++) {
-                       WERROR status;
-
                        DEBUGADD(5,("\tdriver: [%s]\n", list[i]));
                        ZERO_STRUCT(driver);
-                       status = get_a_printer_driver(&driver, 3, list[i],
+                       result = get_a_printer_driver(&driver, 3, list[i],
                                                      architecture, version);
-                       if (!W_ERROR_IS_OK(status)) {
-                               SAFE_FREE(list);
-                               SAFE_FREE(driver_info_3);
-                               return status;
+                       if (!W_ERROR_IS_OK(result)) {
+                               goto out;
+                       }
+                       result = fill_printer_driver_info3(info, &info[*count+i].info3,
+                                                          &driver, servername);
+                       if (!W_ERROR_IS_OK(result)) {
+                               free_a_printer_driver(driver, 3);
+                               goto out;
                        }
-                       fill_printer_driver_info_3(&driver_info_3[*returned+i], driver, servername);
-                       free_a_printer_driver(driver, 3);
-               }
-
-               *returned+=ndrivers;
-               SAFE_FREE(list);
-       }
-
-       /* 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_3(&driver_info_3[i]);
-       }
 
-       if (*needed > offered) {
-               result = WERR_INSUFFICIENT_BUFFER;
-               goto out;
-       }
+                       free_a_printer_driver(driver, 3);
+               }
 
-       if (!rpcbuf_alloc_size(buffer, *needed)) {
-               result = WERR_NOMEM;
-               goto out;
+               *count += ndrivers;
+               SAFE_FREE(list);
        }
 
-       /* fill the buffer with the driver structures */
-       for (i=0; i<*returned; i++) {
-               DEBUGADD(6,("adding driver [%d] to buffer\n",i));
-               smb_io_printer_driver_info_3("", buffer, &driver_info_3[i], 0);
-       }
+ out:
+       SAFE_FREE(list);
 
-out:
-       for (i=0; i<*returned; i++) {
-               SAFE_FREE(driver_info_3[i].dependentfiles);
+       if (!W_ERROR_IS_OK(result)) {
+               TALLOC_FREE(info);
+               *count = 0;
+               return result;
        }
 
-       SAFE_FREE(driver_info_3);
-
-       if ( !W_ERROR_IS_OK(result) )
-               *returned = 0;
+       *info_p = info;
 
-       return result;
+       return WERR_OK;
 }
 
-/****************************************************************************
- Enumerates all printer drivers.
-****************************************************************************/
+/****************************************************************
+ _spoolss_EnumPrinterDrivers
+****************************************************************/
 
-WERROR _spoolss_enumprinterdrivers( pipes_struct *p, SPOOL_Q_ENUMPRINTERDRIVERS *q_u, SPOOL_R_ENUMPRINTERDRIVERS *r_u)
+WERROR _spoolss_EnumPrinterDrivers(pipes_struct *p,
+                                  struct spoolss_EnumPrinterDrivers *r)
 {
-       uint32 level = q_u->level;
-       RPC_BUFFER *buffer = NULL;
-       uint32 offered = q_u->offered;
-       uint32 *needed = &r_u->needed;
-       uint32 *returned = &r_u->returned;
        const char *cservername;
-       fstring servername;
-       fstring architecture;
+       WERROR result;
 
        /* that's an [in out] buffer */
 
-       if (!q_u->buffer && (offered!=0)) {
+       if (!r->in.buffer && (r->in.offered != 0)) {
                return WERR_INVALID_PARAM;
        }
 
-       rpcbuf_move(q_u->buffer, &r_u->buffer);
-       buffer = r_u->buffer;
+       DEBUG(4,("_spoolss_EnumPrinterDrivers\n"));
 
-       DEBUG(4,("_spoolss_enumprinterdrivers\n"));
+       *r->out.needed = 0;
+       *r->out.count = 0;
+       *r->out.info = NULL;
 
-       *needed   = 0;
-       *returned = 0;
+       cservername = canon_servername(r->in.server);
 
-       unistr2_to_ascii(architecture, &q_u->environment, sizeof(architecture));
-       unistr2_to_ascii(servername, &q_u->name, sizeof(servername));
-
-       cservername = canon_servername(servername);
-
-       if (!is_myname_or_ipaddr(cservername))
+       if (!is_myname_or_ipaddr(cservername)) {
                return WERR_UNKNOWN_PRINTER_DRIVER;
+       }
 
-       switch (level) {
+       switch (r->in.level) {
        case 1:
-               return enumprinterdrivers_level1(cservername, architecture, buffer, offered, needed, returned);
+               result = enumprinterdrivers_level1(p->mem_ctx, cservername,
+                                                  r->in.environment,
+                                                  r->out.info, r->out.count);
+               break;
        case 2:
-               return enumprinterdrivers_level2(cservername, architecture, buffer, offered, needed, returned);
+               result = enumprinterdrivers_level2(p->mem_ctx, cservername,
+                                                  r->in.environment,
+                                                  r->out.info, r->out.count);
+               break;
        case 3:
-               return enumprinterdrivers_level3(cservername, architecture, buffer, offered, needed, returned);
+               result = enumprinterdrivers_level3(p->mem_ctx, cservername,
+                                                  r->in.environment,
+                                                  r->out.info, r->out.count);
+               break;
        default:
                return WERR_UNKNOWN_LEVEL;
        }
+
+       if (!W_ERROR_IS_OK(result)) {
+               return result;
+       }
+
+       *r->out.needed  = SPOOLSS_BUFFER_UNION_ARRAY(p->mem_ctx,
+                                                    spoolss_EnumPrinterDrivers, NULL,
+                                                    *r->out.info, r->in.level,
+                                                    *r->out.count);
+       *r->out.info    = SPOOLSS_BUFFER_OK(*r->out.info, NULL);
+       *r->out.count   = SPOOLSS_BUFFER_OK(*r->out.count, 0);
+
+       return SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER);
 }
 
 /****************************************************************************
 ****************************************************************************/
 
-static void fill_form_1(FORM_1 *form, nt_forms_struct *list)
+static WERROR fill_form_info_1(TALLOC_CTX *mem_ctx,
+                              struct spoolss_FormInfo1 *r,
+                              const nt_forms_struct *form)
 {
-       form->flag=list->flag;
-       init_unistr(&form->name, list->name);
-       form->width=list->width;
-       form->length=list->length;
-       form->left=list->left;
-       form->top=list->top;
-       form->right=list->right;
-       form->bottom=list->bottom;
+       r->form_name    = talloc_strdup(mem_ctx, form->name);
+       W_ERROR_HAVE_NO_MEMORY(r->form_name);
+
+       r->flags        = form->flag;
+       r->size.width   = form->width;
+       r->size.height  = form->length;
+       r->area.left    = form->left;
+       r->area.top     = form->top;
+       r->area.right   = form->right;
+       r->area.bottom  = form->bottom;
+
+       return WERR_OK;
 }
 
-/****************************************************************************
-****************************************************************************/
+/****************************************************************
+ spoolss_enumforms_level1
+****************************************************************/
 
-static WERROR fill_form_info_1(TALLOC_CTX *mem_ctx,
-                              struct spoolss_FormInfo1 *form,
-                              nt_forms_struct *list)
+static WERROR spoolss_enumforms_level1(TALLOC_CTX *mem_ctx,
+                                      const nt_forms_struct *builtin_forms,
+                                      uint32_t num_builtin_forms,
+                                      const nt_forms_struct *user_forms,
+                                      uint32_t num_user_forms,
+                                      union spoolss_FormInfo **info_p,
+                                      uint32_t *count)
 {
-       form->form_name         = talloc_strdup(mem_ctx, list->name);
-       W_ERROR_HAVE_NO_MEMORY(form->form_name);
+       union spoolss_FormInfo *info;
+       WERROR result = WERR_OK;
+       int i;
 
-       form->flags             = list->flag;
-       form->size.width        = list->width;
-       form->size.height       = list->length;
-       form->area.left         = list->left;
-       form->area.top          = list->top;
-       form->area.right        = list->right;
-       form->area.bottom       = list->bottom;
+       *count = num_builtin_forms + num_user_forms;
+
+       info = TALLOC_ARRAY(mem_ctx, union spoolss_FormInfo, *count);
+       W_ERROR_HAVE_NO_MEMORY(info);
+
+       /* construct the list of form structures */
+       for (i=0; i<num_builtin_forms; i++) {
+               DEBUGADD(6,("Filling form number [%d]\n",i));
+               result = fill_form_info_1(info, &info[i].info1,
+                                         &builtin_forms[i]);
+               if (!W_ERROR_IS_OK(result)) {
+                       goto out;
+               }
+       }
+
+       for (; i<num_user_forms; i++) {
+               DEBUGADD(6,("Filling form number [%d]\n",i));
+               result = fill_form_info_1(info, &info[i].info1,
+                                         &user_forms[i-num_builtin_forms]);
+               if (!W_ERROR_IS_OK(result)) {
+                       goto out;
+               }
+       }
+
+ out:
+       if (!W_ERROR_IS_OK(result)) {
+               TALLOC_FREE(info);
+               *count = 0;
+               return result;
+       }
+
+       *info_p = info;
 
        return WERR_OK;
 }
 
-/****************************************************************************
-****************************************************************************/
+/****************************************************************
+ _spoolss_EnumForms
+****************************************************************/
 
-WERROR _spoolss_enumforms(pipes_struct *p, SPOOL_Q_ENUMFORMS *q_u, SPOOL_R_ENUMFORMS *r_u)
+WERROR _spoolss_EnumForms(pipes_struct *p,
+                         struct spoolss_EnumForms *r)
 {
-       uint32 level = q_u->level;
-       RPC_BUFFER *buffer = NULL;
-       uint32 offered = q_u->offered;
-       uint32 *needed = &r_u->needed;
-       uint32 *numofforms = &r_u->numofforms;
-       uint32 numbuiltinforms;
+       WERROR result;
+       nt_forms_struct *user_forms = NULL;
+       nt_forms_struct *builtin_forms = NULL;
+       uint32_t num_user_forms;
+       uint32_t num_builtin_forms;
 
-       nt_forms_struct *list=NULL;
-       nt_forms_struct *builtinlist=NULL;
-       FORM_1 *forms_1;
-       int buffer_size=0;
-       int i;
+       *r->out.count = 0;
+       *r->out.needed = 0;
+       *r->out.info = NULL;
 
        /* that's an [in out] buffer */
 
-       if (!q_u->buffer && (offered!=0) ) {
+       if (!r->in.buffer && (r->in.offered != 0) ) {
                return WERR_INVALID_PARAM;
        }
 
-       rpcbuf_move(q_u->buffer, &r_u->buffer);
-       buffer = r_u->buffer;
+       DEBUG(4,("_spoolss_EnumForms\n"));
+       DEBUGADD(5,("Offered buffer size [%d]\n", r->in.offered));
+       DEBUGADD(5,("Info level [%d]\n",          r->in.level));
 
-       DEBUG(4,("_spoolss_enumforms\n"));
-       DEBUGADD(5,("Offered buffer size [%d]\n", offered));
-       DEBUGADD(5,("Info level [%d]\n",          level));
+       num_builtin_forms = get_builtin_ntforms(&builtin_forms);
+       DEBUGADD(5,("Number of builtin forms [%d]\n", num_builtin_forms));
+       num_user_forms = get_ntforms(&user_forms);
+       DEBUGADD(5,("Number of user forms [%d]\n", num_user_forms));
 
-       numbuiltinforms = get_builtin_ntforms(&builtinlist);
-       DEBUGADD(5,("Number of builtin forms [%d]\n",     numbuiltinforms));
-       *numofforms = get_ntforms(&list);
-       DEBUGADD(5,("Number of user forms [%d]\n",     *numofforms));
-       *numofforms += numbuiltinforms;
-
-       if (*numofforms == 0) {
-               SAFE_FREE(builtinlist);
-               SAFE_FREE(list);
+       if (num_user_forms + num_builtin_forms == 0) {
+               SAFE_FREE(builtin_forms);
+               SAFE_FREE(user_forms);
                return WERR_NO_MORE_ITEMS;
        }
 
-       switch (level) {
+       switch (r->in.level) {
        case 1:
-               if ((forms_1=SMB_MALLOC_ARRAY(FORM_1, *numofforms)) == NULL) {
-                       SAFE_FREE(builtinlist);
-                       SAFE_FREE(list);
-                       *numofforms=0;
-                       return WERR_NOMEM;
-               }
+               result = spoolss_enumforms_level1(p->mem_ctx,
+                                                 builtin_forms,
+                                                 num_builtin_forms,
+                                                 user_forms,
+                                                 num_user_forms,
+                                                 r->out.info,
+                                                 r->out.count);
+               break;
+       default:
+               result = WERR_UNKNOWN_LEVEL;
+               break;
+       }
 
-               /* construct the list of form structures */
-               for (i=0; i<numbuiltinforms; i++) {
-                       DEBUGADD(6,("Filling form number [%d]\n",i));
-                       fill_form_1(&forms_1[i], &builtinlist[i]);
-               }
+       SAFE_FREE(user_forms);
+       SAFE_FREE(builtin_forms);
 
-               SAFE_FREE(builtinlist);
+       if (!W_ERROR_IS_OK(result)) {
+               return result;
+       }
 
-               for (; i<*numofforms; i++) {
-                       DEBUGADD(6,("Filling form number [%d]\n",i));
-                       fill_form_1(&forms_1[i], &list[i-numbuiltinforms]);
-               }
+       *r->out.needed  = SPOOLSS_BUFFER_UNION_ARRAY(p->mem_ctx,
+                                                    spoolss_EnumForms, NULL,
+                                                    *r->out.info, r->in.level,
+                                                    *r->out.count);
+       *r->out.info    = SPOOLSS_BUFFER_OK(*r->out.info, NULL);
+       *r->out.count   = SPOOLSS_BUFFER_OK(*r->out.count, 0);
 
-               SAFE_FREE(list);
+       return SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER);
+}
 
-               /* check the required size. */
-               for (i=0; i<numbuiltinforms; i++) {
-                       DEBUGADD(6,("adding form [%d]'s size\n",i));
-                       buffer_size += spoolss_size_form_1(&forms_1[i]);
-               }
-               for (; i<*numofforms; i++) {
-                       DEBUGADD(6,("adding form [%d]'s size\n",i));
-                       buffer_size += spoolss_size_form_1(&forms_1[i]);
-               }
+/****************************************************************
+****************************************************************/
 
-               *needed=buffer_size;
+static WERROR find_form_byname(const char *name,
+                              nt_forms_struct *form)
+{
+       nt_forms_struct *list = NULL;
+       int num_forms = 0, i = 0;
 
-               if (*needed > offered) {
-                       SAFE_FREE(forms_1);
-                       *numofforms=0;
-                       return WERR_INSUFFICIENT_BUFFER;
-               }
+       if (get_a_builtin_ntform_by_string(name, form)) {
+               return WERR_OK;
+       }
 
-               if (!rpcbuf_alloc_size(buffer, buffer_size)){
-                       SAFE_FREE(forms_1);
-                       *numofforms=0;
-                       return WERR_NOMEM;
-               }
+       num_forms = get_ntforms(&list);
+       DEBUGADD(5,("Number of forms [%d]\n", num_forms));
 
-               /* fill the buffer with the form structures */
-               for (i=0; i<numbuiltinforms; i++) {
-                       DEBUGADD(6,("adding form [%d] to buffer\n",i));
-                       smb_io_form_1("", buffer, &forms_1[i], 0);
-               }
-               for (; i<*numofforms; i++) {
-                       DEBUGADD(6,("adding form [%d] to buffer\n",i));
-                       smb_io_form_1("", buffer, &forms_1[i], 0);
-               }
+       if (num_forms == 0) {
+               return WERR_BADFID;
+       }
 
-               SAFE_FREE(forms_1);
+       /* Check if the requested name is in the list of form structures */
+       for (i = 0; i < num_forms; i++) {
 
-               return WERR_OK;
+               DEBUG(4,("checking form %s (want %s)\n", list[i].name, name));
 
-       default:
-               SAFE_FREE(list);
-               SAFE_FREE(builtinlist);
-               return WERR_UNKNOWN_LEVEL;
+               if (strequal(name, list[i].name)) {
+                       DEBUGADD(6,("Found form %s number [%d]\n", name, i));
+                       *form = list[i];
+                       SAFE_FREE(list);
+                       return WERR_OK;
+               }
        }
+
+       SAFE_FREE(list);
+
+       return WERR_BADFID;
 }
 
 /****************************************************************
@@ -7465,92 +7159,60 @@ WERROR _spoolss_enumforms(pipes_struct *p, SPOOL_Q_ENUMFORMS *q_u, SPOOL_R_ENUMF
 WERROR _spoolss_GetForm(pipes_struct *p,
                        struct spoolss_GetForm *r)
 {
-       uint32 level = r->in.level;
-       uint32 offered = r->in.offered;
-       uint32 *needed = r->out.needed;
-
-       nt_forms_struct *list=NULL;
-       nt_forms_struct builtin_form;
-       bool foundBuiltin;
-       union spoolss_FormInfo info;
-       struct spoolss_FormInfo1 form_1;
-       int numofforms=0, i=0;
+       WERROR result;
+       nt_forms_struct form;
 
        /* that's an [in out] buffer */
 
-       if (!r->in.buffer && (offered!=0)) {
+       if (!r->in.buffer && (r->in.offered != 0)) {
                return WERR_INVALID_PARAM;
        }
 
        DEBUG(4,("_spoolss_GetForm\n"));
-       DEBUGADD(5,("Offered buffer size [%d]\n", offered));
-       DEBUGADD(5,("Info level [%d]\n",          level));
-
-       foundBuiltin = get_a_builtin_ntform_by_string(r->in.form_name, &builtin_form);
-       if (!foundBuiltin) {
-               numofforms = get_ntforms(&list);
-               DEBUGADD(5,("Number of forms [%d]\n",     numofforms));
+       DEBUGADD(5,("Offered buffer size [%d]\n", r->in.offered));
+       DEBUGADD(5,("Info level [%d]\n",          r->in.level));
 
-               if (numofforms == 0)
-                       return WERR_BADFID;
+       result = find_form_byname(r->in.form_name, &form);
+       if (!W_ERROR_IS_OK(result)) {
+               TALLOC_FREE(r->out.info);
+               return result;
        }
 
-       switch (level) {
+       switch (r->in.level) {
        case 1:
-               if (foundBuiltin) {
-                       fill_form_info_1(p->mem_ctx, &form_1, &builtin_form);
-               } else {
-
-                       /* Check if the requested name is in the list of form structures */
-                       for (i=0; i<numofforms; i++) {
-
-                               DEBUG(4,("_spoolss_GetForm: checking form %s (want %s)\n",
-                                       list[i].name, r->in.form_name));
-
-                               if (strequal(r->in.form_name, list[i].name)) {
-                                       DEBUGADD(6,("Found form %s number [%d]\n",
-                                               r->in.form_name, i));
-                                       fill_form_info_1(p->mem_ctx, &form_1, &list[i]);
-                                       break;
-                               }
-                       }
-
-                       SAFE_FREE(list);
-                       if (i == numofforms) {
-                               return WERR_BADFID;
-                       }
-               }
-               /* check the required size. */
-
-               info.info1 = form_1;
-
-               *needed = ndr_size_spoolss_FormInfo(&info, 1, NULL, 0);
-
-               if (*needed > offered) {
-                       r->out.info = NULL;
-                       return WERR_INSUFFICIENT_BUFFER;
-               }
+               result = fill_form_info_1(p->mem_ctx,
+                                         &r->out.info->info1,
+                                         &form);
+               break;
 
-               r->out.info->info1 = form_1;
+       default:
+               result = WERR_UNKNOWN_LEVEL;
+               break;
+       }
 
-               /* fill the buffer with the form structures */
-               DEBUGADD(6,("adding form %s [%d] to buffer\n",
-                       r->in.form_name, i));
+       if (!W_ERROR_IS_OK(result)) {
+               TALLOC_FREE(r->out.info);
+               return result;
+       }
 
-               return WERR_OK;
+       *r->out.needed  = SPOOLSS_BUFFER_UNION(spoolss_FormInfo, NULL,
+                                              r->out.info, r->in.level);
+       r->out.info     = SPOOLSS_BUFFER_OK(r->out.info, NULL);
 
-       default:
-               SAFE_FREE(list);
-               return WERR_UNKNOWN_LEVEL;
-       }
+       return SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER);
 }
 
 /****************************************************************************
 ****************************************************************************/
 
-static void fill_port_1(PORT_INFO_1 *port, const char *name)
+static WERROR fill_port_1(TALLOC_CTX *mem_ctx,
+                         struct spoolss_PortInfo1 *r,
+                         const char *name)
 {
-       init_unistr(&port->port_name, name);
+       r->port_name = talloc_strdup(mem_ctx, name);
+       W_ERROR_HAVE_NO_MEMORY(r->port_name);
+
+       return WERR_OK;
 }
 
 /****************************************************************************
@@ -7558,13 +7220,23 @@ static void fill_port_1(PORT_INFO_1 *port, const char *name)
  somehow.
 ****************************************************************************/
 
-static void fill_port_2(PORT_INFO_2 *port, const char *name)
+static WERROR fill_port_2(TALLOC_CTX *mem_ctx,
+                         struct spoolss_PortInfo2 *r,
+                         const char *name)
 {
-       init_unistr(&port->port_name, name);
-       init_unistr(&port->monitor_name, "Local Monitor");
-       init_unistr(&port->description, SPL_LOCAL_PORT );
-       port->port_type=PORT_TYPE_WRITE;
-       port->reserved=0x0;
+       r->port_name = talloc_strdup(mem_ctx, name);
+       W_ERROR_HAVE_NO_MEMORY(r->port_name);
+
+       r->monitor_name = talloc_strdup(mem_ctx, "Local Monitor");
+       W_ERROR_HAVE_NO_MEMORY(r->monitor_name);
+
+       r->description = talloc_strdup(mem_ctx, SPL_LOCAL_PORT); /* FIXME */
+       W_ERROR_HAVE_NO_MEMORY(r->description);
+
+       r->port_type = SPOOLSS_PORT_TYPE_WRITE;
+       r->reserved = 0;
+
+       return WERR_OK;
 }
 
 
@@ -7632,9 +7304,11 @@ WERROR enumports_hook(TALLOC_CTX *ctx, int *count, char ***lines )
  enumports level 1.
 ****************************************************************************/
 
-static WERROR enumports_level_1(RPC_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+static WERROR enumports_level_1(TALLOC_CTX *mem_ctx,
+                               union spoolss_PortInfo **info_p,
+                               uint32_t *count)
 {
-       PORT_INFO_1 *ports=NULL;
+       union spoolss_PortInfo *info = NULL;
        int i=0;
        WERROR result = WERR_OK;
        char **qlines = NULL;
@@ -7642,167 +7316,152 @@ static WERROR enumports_level_1(RPC_BUFFER *buffer, uint32 offered, uint32 *need
 
        result = enumports_hook(talloc_tos(), &numlines, &qlines );
        if (!W_ERROR_IS_OK(result)) {
-               TALLOC_FREE(qlines);
-               return result;
+               goto out;
        }
 
-       if(numlines) {
-               if((ports=SMB_MALLOC_ARRAY( PORT_INFO_1, numlines )) == NULL) {
-                       DEBUG(10,("Returning WERR_NOMEM [%s]\n",
-                                 win_errstr(WERR_NOMEM)));
-                       TALLOC_FREE(qlines);
-                       return WERR_NOMEM;
+       if (numlines) {
+               info = TALLOC_ARRAY(mem_ctx, union spoolss_PortInfo, numlines);
+               if (!info) {
+                       DEBUG(10,("Returning WERR_NOMEM\n"));
+                       result = WERR_NOMEM;
+                       goto out;
                }
 
                for (i=0; i<numlines; i++) {
                        DEBUG(6,("Filling port number [%d] with port [%s]\n", i, qlines[i]));
-                       fill_port_1(&ports[i], qlines[i]);
+                       result = fill_port_1(info, &info[i].info1, qlines[i]);
+                       if (!W_ERROR_IS_OK(result)) {
+                               goto out;
+                       }
                }
        }
        TALLOC_FREE(qlines);
 
-       *returned = numlines;
-
-       /* 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 (*needed > offered) {
-               result = WERR_INSUFFICIENT_BUFFER;
-               goto out;
-       }
-
-       if (!rpcbuf_alloc_size(buffer, *needed)) {
-               result = WERR_NOMEM;
-               goto out;
-       }
-
-       /* fill the buffer with the ports structures */
-       for (i=0; i<*returned; i++) {
-               DEBUGADD(6,("adding port [%d] to buffer\n", i));
-               smb_io_port_1("", buffer, &ports[i], 0);
-       }
-
 out:
-       SAFE_FREE(ports);
+       if (!W_ERROR_IS_OK(result)) {
+               TALLOC_FREE(info);
+               TALLOC_FREE(qlines);
+               *count = 0;
+               *info_p = NULL;
+               return result;
+       }
 
-       if ( !W_ERROR_IS_OK(result) )
-               *returned = 0;
+       *info_p = info;
+       *count = numlines;
 
-       return result;
+       return WERR_OK;
 }
 
 /****************************************************************************
  enumports level 2.
 ****************************************************************************/
 
-static WERROR enumports_level_2(RPC_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+static WERROR enumports_level_2(TALLOC_CTX *mem_ctx,
+                               union spoolss_PortInfo **info_p,
+                               uint32_t *count)
 {
-       PORT_INFO_2 *ports=NULL;
+       union spoolss_PortInfo *info = NULL;
        int i=0;
        WERROR result = WERR_OK;
        char **qlines = NULL;
        int numlines = 0;
 
        result = enumports_hook(talloc_tos(), &numlines, &qlines );
-       if ( !W_ERROR_IS_OK(result)) {
-               TALLOC_FREE(qlines);
-               return result;
+       if (!W_ERROR_IS_OK(result)) {
+               goto out;
        }
 
-       if(numlines) {
-               if((ports=SMB_MALLOC_ARRAY( PORT_INFO_2, numlines)) == NULL) {
-                       TALLOC_FREE(qlines);
-                       return WERR_NOMEM;
+       if (numlines) {
+               info = TALLOC_ARRAY(mem_ctx, union spoolss_PortInfo, numlines);
+               if (!info) {
+                       DEBUG(10,("Returning WERR_NOMEM\n"));
+                       result = WERR_NOMEM;
+                       goto out;
                }
 
                for (i=0; i<numlines; i++) {
                        DEBUG(6,("Filling port number [%d] with port [%s]\n", i, qlines[i]));
-                       fill_port_2(&(ports[i]), qlines[i]);
+                       result = fill_port_2(info, &info[i].info2, qlines[i]);
+                       if (!W_ERROR_IS_OK(result)) {
+                               goto out;
+                       }
                }
        }
-
        TALLOC_FREE(qlines);
 
-       *returned = numlines;
-
-       /* 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 (*needed > offered) {
-               result = WERR_INSUFFICIENT_BUFFER;
-               goto out;
-       }
-
-       if (!rpcbuf_alloc_size(buffer, *needed)) {
-               result = WERR_NOMEM;
-               goto out;
-       }
-
-       /* fill the buffer with the ports structures */
-       for (i=0; i<*returned; i++) {
-               DEBUGADD(6,("adding port [%d] to buffer\n", i));
-               smb_io_port_2("", buffer, &ports[i], 0);
-       }
-
 out:
-       SAFE_FREE(ports);
+       if (!W_ERROR_IS_OK(result)) {
+               TALLOC_FREE(info);
+               TALLOC_FREE(qlines);
+               *count = 0;
+               *info_p = NULL;
+               return result;
+       }
 
-       if ( !W_ERROR_IS_OK(result) )
-               *returned = 0;
+       *info_p = info;
+       *count = numlines;
 
-       return result;
+       return WERR_OK;
 }
 
-/****************************************************************************
- enumports.
-****************************************************************************/
+/****************************************************************
+ _spoolss_EnumPorts
+****************************************************************/
 
-WERROR _spoolss_enumports( pipes_struct *p, SPOOL_Q_ENUMPORTS *q_u, SPOOL_R_ENUMPORTS *r_u)
+WERROR _spoolss_EnumPorts(pipes_struct *p,
+                         struct spoolss_EnumPorts *r)
 {
-       uint32 level = q_u->level;
-       RPC_BUFFER *buffer = NULL;
-       uint32 offered = q_u->offered;
-       uint32 *needed = &r_u->needed;
-       uint32 *returned = &r_u->returned;
+       WERROR result;
 
        /* that's an [in out] buffer */
 
-       if (!q_u->buffer && (offered!=0)) {
+       if (!r->in.buffer && (r->in.offered != 0)) {
                return WERR_INVALID_PARAM;
        }
 
-       rpcbuf_move(q_u->buffer, &r_u->buffer);
-       buffer = r_u->buffer;
+       DEBUG(4,("_spoolss_EnumPorts\n"));
 
-       DEBUG(4,("_spoolss_enumports\n"));
+       *r->out.count = 0;
+       *r->out.needed = 0;
+       *r->out.info = NULL;
 
-       *returned=0;
-       *needed=0;
-
-       switch (level) {
+       switch (r->in.level) {
        case 1:
-               return enumports_level_1(buffer, offered, needed, returned);
+               result = enumports_level_1(p->mem_ctx, r->out.info,
+                                          r->out.count);
+               break;
        case 2:
-               return enumports_level_2(buffer, offered, needed, returned);
+               result = enumports_level_2(p->mem_ctx, r->out.info,
+                                          r->out.count);
+               break;
        default:
                return WERR_UNKNOWN_LEVEL;
        }
+
+       if (!W_ERROR_IS_OK(result)) {
+               return result;
+       }
+
+       *r->out.needed  = SPOOLSS_BUFFER_UNION_ARRAY(p->mem_ctx,
+                                                    spoolss_EnumPorts, NULL,
+                                                    *r->out.info, r->in.level,
+                                                    *r->out.count);
+       *r->out.info    = SPOOLSS_BUFFER_OK(*r->out.info, NULL);
+       *r->out.count   = SPOOLSS_BUFFER_OK(*r->out.count, 0);
+
+       return SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER);
 }
 
 /****************************************************************************
 ****************************************************************************/
 
-static WERROR spoolss_addprinterex_level_2( pipes_struct *p, const UNISTR2 *uni_srv_name,
-                               const SPOOL_PRINTER_INFO_LEVEL *info,
-                               DEVICEMODE *devmode, SEC_DESC_BUF *sec_desc_buf,
-                               uint32 user_switch, const SPOOL_USER_CTR *user,
-                               POLICY_HND *handle)
+static WERROR spoolss_addprinterex_level_2(pipes_struct *p,
+                                          const char *server,
+                                          struct spoolss_SetPrinterInfoCtr *info_ctr,
+                                          struct spoolss_DeviceMode *devmode,
+                                          struct security_descriptor *sec_desc,
+                                          struct spoolss_UserLevelCtr *user_ctr,
+                                          POLICY_HND *handle)
 {
        NT_PRINTER_INFO_LEVEL *printer = NULL;
        fstring name;
@@ -7815,7 +7474,7 @@ static WERROR spoolss_addprinterex_level_2( pipes_struct *p, const UNISTR2 *uni_
        }
 
        /* convert from UNICODE to ASCII - this allocates the info_2 struct inside *printer.*/
-       if (!convert_printer_info(info, printer, 2)) {
+       if (!convert_printer_info_new(info_ctr, printer)) {
                free_a_printer(&printer, 2);
                return WERR_NOMEM;
        }
@@ -7888,8 +7547,9 @@ static WERROR spoolss_addprinterex_level_2( pipes_struct *p, const UNISTR2 *uni_
                */
                DEBUGADD(10, ("spoolss_addprinterex_level_2: devmode included, converting\n"));
 
-               if (!convert_devicemode(printer->info_2->printername, devmode,
-                               &printer->info_2->devmode))
+               if (!convert_devicemode_new(printer->info_2->printername,
+                                           devmode,
+                                           &printer->info_2->devmode))
                        return  WERR_NOMEM;
        }
 
@@ -7904,6 +7564,7 @@ static WERROR spoolss_addprinterex_level_2( pipes_struct *p, const UNISTR2 *uni_
                /* Handle open failed - remove addition. */
                del_a_printer(printer->info_2->sharename);
                free_a_printer(&printer,2);
+               ZERO_STRUCTP(handle);
                return WERR_ACCESS_DENIED;
        }
 
@@ -7913,45 +7574,65 @@ static WERROR spoolss_addprinterex_level_2( pipes_struct *p, const UNISTR2 *uni_
        return WERR_OK;
 }
 
-/****************************************************************************
-****************************************************************************/
-
-WERROR _spoolss_addprinterex( pipes_struct *p, SPOOL_Q_ADDPRINTEREX *q_u, SPOOL_R_ADDPRINTEREX *r_u)
-{
-       UNISTR2 *uni_srv_name = q_u->server_name;
-       uint32 level = q_u->level;
-       SPOOL_PRINTER_INFO_LEVEL *info = &q_u->info;
-       DEVICEMODE *devmode = q_u->devmode_ctr.devmode;
-       SEC_DESC_BUF *sdb = q_u->secdesc_ctr;
-       uint32 user_switch = q_u->user_switch;
-       SPOOL_USER_CTR *user = &q_u->user_ctr;
-       POLICY_HND *handle = &r_u->handle;
-
-       switch (level) {
-               case 1:
-                       /* we don't handle yet */
-                       /* but I know what to do ... */
-                       return WERR_UNKNOWN_LEVEL;
-               case 2:
-                       return spoolss_addprinterex_level_2(p, uni_srv_name, info,
-                                                           devmode, sdb,
-                                                           user_switch, user, handle);
-               default:
-                       return WERR_UNKNOWN_LEVEL;
+/****************************************************************
+ _spoolss_AddPrinterEx
+****************************************************************/
+
+WERROR _spoolss_AddPrinterEx(pipes_struct *p,
+                            struct spoolss_AddPrinterEx *r)
+{
+       switch (r->in.info_ctr->level) {
+       case 1:
+               /* we don't handle yet */
+               /* but I know what to do ... */
+               return WERR_UNKNOWN_LEVEL;
+       case 2:
+               return spoolss_addprinterex_level_2(p, r->in.server,
+                                                   r->in.info_ctr,
+                                                   r->in.devmode_ctr->devmode,
+                                                   r->in.secdesc_ctr->sd,
+                                                   r->in.userlevel_ctr,
+                                                   r->out.handle);
+       default:
+               return WERR_UNKNOWN_LEVEL;
        }
 }
 
-/****************************************************************************
-****************************************************************************/
+/****************************************************************
+ _spoolss_AddPrinterDriver
+****************************************************************/
 
-WERROR _spoolss_addprinterdriver(pipes_struct *p, SPOOL_Q_ADDPRINTERDRIVER *q_u, SPOOL_R_ADDPRINTERDRIVER *r_u)
+WERROR _spoolss_AddPrinterDriver(pipes_struct *p,
+                                struct spoolss_AddPrinterDriver *r)
 {
-       uint32 level = q_u->level;
-       SPOOL_PRINTER_DRIVER_INFO_LEVEL *info = &q_u->info;
+       uint32_t level = r->in.info_ctr->level;
+       struct spoolss_AddDriverInfoCtr *info = r->in.info_ctr;
        WERROR err = WERR_OK;
        NT_PRINTER_DRIVER_INFO_LEVEL driver;
        fstring driver_name;
        uint32 version;
+       const char *fn;
+
+       switch (p->hdr_req.opnum) {
+               case NDR_SPOOLSS_ADDPRINTERDRIVER:
+                       fn = "_spoolss_AddPrinterDriver";
+                       break;
+               case NDR_SPOOLSS_ADDPRINTERDRIVEREX:
+                       fn = "_spoolss_AddPrinterDriverEx";
+                       break;
+               default:
+                       return WERR_INVALID_PARAM;
+       }
+
+
+       /* FIXME */
+       if (level != 3 && level != 6) {
+               /* Clever hack from Martin Zielinski <mz@seh.de>
+                * to allow downgrade from level 8 (Vista).
+                */
+               DEBUG(0,("%s: level %d not yet implemented\n", fn, level));
+               return WERR_UNKNOWN_LEVEL;
+       }
 
        ZERO_STRUCT(driver);
 
@@ -7995,8 +7676,8 @@ WERROR _spoolss_addprinterdriver(pipes_struct *p, SPOOL_Q_ADDPRINTERDRIVER *q_u,
         */
 
        if (!srv_spoolss_drv_upgrade_printer(driver_name)) {
-               DEBUG(0,("_spoolss_addprinterdriver: Failed to send message about upgrading driver [%s]!\n",
-                       driver_name));
+               DEBUG(0,("%s: Failed to send message about upgrading driver [%s]!\n",
+                       fn, driver_name));
        }
 
        /*
@@ -8020,8 +7701,8 @@ WERROR _spoolss_addprinterdriver(pipes_struct *p, SPOOL_Q_ADDPRINTERDRIVER *q_u,
                 * 9x printer driver - never delete init data
                */
                case 0:
-                       DEBUG(10,("_spoolss_addprinterdriver: init data not deleted for 9x driver [%s]\n",
-                                       driver_name));
+                       DEBUG(10,("%s: init data not deleted for 9x driver [%s]\n",
+                               fn, driver_name));
                        break;
 
                /*
@@ -8037,14 +7718,15 @@ WERROR _spoolss_addprinterdriver(pipes_struct *p, SPOOL_Q_ADDPRINTERDRIVER *q_u,
                                 * No 2k/Xp driver found, delete init data (if any) for the new Nt driver.
                                */
                                if (!del_driver_init(driver_name))
-                                       DEBUG(6,("_spoolss_addprinterdriver: del_driver_init(%s) Nt failed!\n", driver_name));
+                                       DEBUG(6,("%s: del_driver_init(%s) Nt failed!\n",
+                                               fn, driver_name));
                        } else {
                                /*
                                 * a 2k/Xp driver was found, don't delete init data because Nt driver will use it.
                                */
                                free_a_printer_driver(driver1,3);
-                               DEBUG(10,("_spoolss_addprinterdriver: init data not deleted for Nt driver [%s]\n",
-                                               driver_name));
+                               DEBUG(10,("%s: init data not deleted for Nt driver [%s]\n",
+                                       fn, driver_name));
                        }
                }
                break;
@@ -8054,11 +7736,12 @@ WERROR _spoolss_addprinterdriver(pipes_struct *p, SPOOL_Q_ADDPRINTERDRIVER *q_u,
                */
                case 3:
                        if (!del_driver_init(driver_name))
-                               DEBUG(6,("_spoolss_addprinterdriver: del_driver_init(%s) 2k/Xp failed!\n", driver_name));
+                               DEBUG(6,("%s: del_driver_init(%s) 2k/Xp failed!\n",
+                                       fn, driver_name));
                        break;
 
                default:
-                       DEBUG(0,("_spoolss_addprinterdriver: invalid level=%d\n", level));
+                       DEBUG(0,("%s: invalid level=%d\n", fn, level));
                        break;
        }
 
@@ -8068,164 +7751,177 @@ done:
        return err;
 }
 
-/********************************************************************
* spoolss_addprinterdriverex
- ********************************************************************/
+/****************************************************************
_spoolss_AddPrinterDriverEx
+****************************************************************/
 
-WERROR _spoolss_addprinterdriverex(pipes_struct *p, SPOOL_Q_ADDPRINTERDRIVEREX *q_u, SPOOL_R_ADDPRINTERDRIVEREX *r_u)
+WERROR _spoolss_AddPrinterDriverEx(pipes_struct *p,
+                                  struct spoolss_AddPrinterDriverEx *r)
 {
-       SPOOL_Q_ADDPRINTERDRIVER q_u_local;
-       SPOOL_R_ADDPRINTERDRIVER r_u_local;
+       struct spoolss_AddPrinterDriver a;
 
        /*
         * we only support the semantics of AddPrinterDriver()
         * i.e. only copy files that are newer than existing ones
         */
 
-       if ( q_u->copy_flags != APD_COPY_NEW_FILES )
+       if (r->in.flags != APD_COPY_NEW_FILES) {
                return WERR_ACCESS_DENIED;
+       }
 
-       ZERO_STRUCT(q_u_local);
-       ZERO_STRUCT(r_u_local);
-
-       /* just pass the information off to _spoolss_addprinterdriver() */
-       q_u_local.server_name_ptr = q_u->server_name_ptr;
-       copy_unistr2(&q_u_local.server_name, &q_u->server_name);
-       q_u_local.level = q_u->level;
-       memcpy( &q_u_local.info, &q_u->info, sizeof(SPOOL_PRINTER_DRIVER_INFO_LEVEL) );
+       a.in.servername         = r->in.servername;
+       a.in.info_ctr           = r->in.info_ctr;
 
-       return _spoolss_addprinterdriver( p, &q_u_local, &r_u_local );
+       return _spoolss_AddPrinterDriver(p, &a);
 }
 
 /****************************************************************************
 ****************************************************************************/
 
-static void fill_driverdir_1(DRIVER_DIRECTORY_1 *info, char *name)
-{
-       init_unistr(&info->name, name);
-}
+struct _spoolss_paths {
+       int type;
+       const char *share;
+       const char *dir;
+};
 
-/****************************************************************************
-****************************************************************************/
+enum { SPOOLSS_DRIVER_PATH, SPOOLSS_PRTPROCS_PATH };
 
-static WERROR getprinterdriverdir_level_1(UNISTR2 *name, UNISTR2 *uni_environment, RPC_BUFFER *buffer, uint32 offered, uint32 *needed)
+static const struct _spoolss_paths spoolss_paths[]= {
+       { SPOOLSS_DRIVER_PATH,          "print$",       "DRIVERS" },
+       { SPOOLSS_PRTPROCS_PATH,        "prnproc$",     "PRTPROCS" }
+};
+
+static WERROR compose_spoolss_server_path(TALLOC_CTX *mem_ctx,
+                                         const char *servername,
+                                         const char *environment,
+                                         int component,
+                                         char **path)
 {
-       char *path = NULL;
-       char *long_archi = NULL;
-       char *servername = NULL;
        const char *pservername = NULL;
+       const char *long_archi = SPOOLSS_ARCHITECTURE_NT_X86;
        const char *short_archi;
-       DRIVER_DIRECTORY_1 *info=NULL;
-       WERROR result = WERR_OK;
-       TALLOC_CTX *ctx = talloc_tos();
 
-       servername = unistr2_to_ascii_talloc(ctx, name);
-       if (!servername) {
-               return WERR_NOMEM;
-       }
-       long_archi = unistr2_to_ascii_talloc(ctx, uni_environment);
-       if (!long_archi) {
-               return WERR_NOMEM;
+       *path = NULL;
+
+       /* environment may be empty */
+       if (environment && strlen(environment)) {
+               long_archi = environment;
        }
 
-       pservername = canon_servername(servername);
+       /* servername may be empty */
+       if (servername && strlen(servername)) {
+               pservername = canon_servername(servername);
 
-       if ( !is_myname_or_ipaddr(pservername))
-               return WERR_INVALID_PARAM;
+               if (!is_myname_or_ipaddr(pservername)) {
+                       return WERR_INVALID_PARAM;
+               }
+       }
 
-       if (!(short_archi = get_short_archi(long_archi)))
+       if (!(short_archi = get_short_archi(long_archi))) {
                return WERR_INVALID_ENVIRONMENT;
+       }
 
-       if((info=SMB_MALLOC_P(DRIVER_DIRECTORY_1)) == NULL)
-               return WERR_NOMEM;
-
-       path = talloc_asprintf(ctx,
-                       "\\\\%s\\print$\\%s", pservername, short_archi);
-       if (!path) {
-               result = WERR_NOMEM;
-               goto out;
+       switch (component) {
+       case SPOOLSS_PRTPROCS_PATH:
+       case SPOOLSS_DRIVER_PATH:
+               if (pservername) {
+                       *path = talloc_asprintf(mem_ctx,
+                                       "\\\\%s\\%s\\%s",
+                                       pservername,
+                                       spoolss_paths[component].share,
+                                       short_archi);
+               } else {
+                       *path = talloc_asprintf(mem_ctx, "%s\\%s\\%s",
+                                       SPOOLSS_DEFAULT_SERVER_PATH,
+                                       spoolss_paths[component].dir,
+                                       short_archi);
+               }
+               break;
+       default:
+               return WERR_INVALID_PARAM;
        }
 
-       DEBUG(4,("printer driver directory: [%s]\n", path));
+       if (!*path) {
+               return WERR_NOMEM;
+       }
 
-       fill_driverdir_1(info, path);
+       return WERR_OK;
+}
 
-       *needed += spoolss_size_driverdir_info_1(info);
+/****************************************************************************
+****************************************************************************/
 
-       if (*needed > offered) {
-               result = WERR_INSUFFICIENT_BUFFER;
-               goto out;
-       }
+static WERROR getprinterdriverdir_level_1(TALLOC_CTX *mem_ctx,
+                                         const char *servername,
+                                         const char *environment,
+                                         struct spoolss_DriverDirectoryInfo1 *r)
+{
+       WERROR werr;
+       char *path = NULL;
 
-       if (!rpcbuf_alloc_size(buffer, *needed)) {
-               result = WERR_NOMEM;
-               goto out;
+       werr = compose_spoolss_server_path(mem_ctx,
+                                          servername,
+                                          environment,
+                                          SPOOLSS_DRIVER_PATH,
+                                          &path);
+       if (!W_ERROR_IS_OK(werr)) {
+               return werr;
        }
 
-       smb_io_driverdir_1("", buffer, info, 0);
+       DEBUG(4,("printer driver directory: [%s]\n", path));
 
-out:
-       SAFE_FREE(info);
+       r->directory_name = path;
 
-       return result;
+       return WERR_OK;
 }
 
-/****************************************************************************
-****************************************************************************/
+/****************************************************************
+ _spoolss_GetPrinterDriverDirectory
+****************************************************************/
 
-WERROR _spoolss_getprinterdriverdirectory(pipes_struct *p, SPOOL_Q_GETPRINTERDRIVERDIR *q_u, SPOOL_R_GETPRINTERDRIVERDIR *r_u)
+WERROR _spoolss_GetPrinterDriverDirectory(pipes_struct *p,
+                                         struct spoolss_GetPrinterDriverDirectory *r)
 {
-       UNISTR2 *name = &q_u->name;
-       UNISTR2 *uni_environment = &q_u->environment;
-       uint32 level = q_u->level;
-       RPC_BUFFER *buffer = NULL;
-       uint32 offered = q_u->offered;
-       uint32 *needed = &r_u->needed;
+       WERROR werror;
 
        /* that's an [in out] buffer */
 
-       if (!q_u->buffer && (offered!=0)) {
+       if (!r->in.buffer && (r->in.offered != 0)) {
                return WERR_INVALID_PARAM;
        }
 
-       rpcbuf_move(q_u->buffer, &r_u->buffer);
-       buffer = r_u->buffer;
+       DEBUG(5,("_spoolss_GetPrinterDriverDirectory: level %d\n",
+               r->in.level));
 
-       DEBUG(4,("_spoolss_getprinterdriverdirectory\n"));
+       *r->out.needed = 0;
 
-       *needed=0;
+       /* r->in.level is ignored */
 
-       switch(level) {
-       case 1:
-               return getprinterdriverdir_level_1(name, uni_environment, buffer, offered, needed);
-       default:
-               return WERR_UNKNOWN_LEVEL;
+       werror = getprinterdriverdir_level_1(p->mem_ctx,
+                                            r->in.server,
+                                            r->in.environment,
+                                            &r->out.info->info1);
+       if (!W_ERROR_IS_OK(werror)) {
+               TALLOC_FREE(r->out.info);
+               return werror;
        }
+
+       *r->out.needed  = SPOOLSS_BUFFER_UNION(spoolss_DriverDirectoryInfo, NULL,
+                                              r->out.info, r->in.level);
+       r->out.info     = SPOOLSS_BUFFER_OK(r->out.info, NULL);
+
+       return SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER);
 }
 
-/****************************************************************************
-****************************************************************************/
+/****************************************************************
+ _spoolss_EnumPrinterData
+****************************************************************/
 
-WERROR _spoolss_enumprinterdata(pipes_struct *p, SPOOL_Q_ENUMPRINTERDATA *q_u, SPOOL_R_ENUMPRINTERDATA *r_u)
+WERROR _spoolss_EnumPrinterData(pipes_struct *p,
+                               struct spoolss_EnumPrinterData *r)
 {
-       POLICY_HND *handle = &q_u->handle;
-       uint32 idx               = q_u->index;
-       uint32 in_value_len      = q_u->valuesize;
-       uint32 in_data_len       = q_u->datasize;
-       uint32 *out_max_value_len = &r_u->valuesize;
-       uint16 **out_value       = &r_u->value;
-       uint32 *out_value_len    = &r_u->realvaluesize;
-       uint32 *out_type         = &r_u->type;
-       uint32 *out_max_data_len = &r_u->datasize;
-       uint8  **data_out        = &r_u->data;
-       uint32 *out_data_len     = &r_u->realdatasize;
-
        NT_PRINTER_INFO_LEVEL *printer = NULL;
-
-       uint32          biggest_valuesize;
-       uint32          biggest_datasize;
-       uint32          data_len;
-       Printer_entry   *Printer = find_printer_index_by_hnd(p, handle);
+       Printer_entry   *Printer = find_printer_index_by_hnd(p, r->in.handle);
        int             snum;
        WERROR          result;
        REGISTRY_VALUE  *val = NULL;
@@ -8233,25 +7929,26 @@ WERROR _spoolss_enumprinterdata(pipes_struct *p, SPOOL_Q_ENUMPRINTERDATA *q_u, S
        int             i, key_index, num_values;
        int             name_length;
 
-       *out_type = 0;
-
-       *out_max_data_len = 0;
-       *data_out         = NULL;
-       *out_data_len     = 0;
+       *r->out.value_needed    = 0;
+       *r->out.type            = REG_NONE;
+       *r->out.data_needed     = 0;
 
-       DEBUG(5,("spoolss_enumprinterdata\n"));
+       DEBUG(5,("_spoolss_EnumPrinterData\n"));
 
        if (!Printer) {
-               DEBUG(2,("_spoolss_enumprinterdata: Invalid handle (%s:%u:%u).\n", OUR_HANDLE(handle)));
+               DEBUG(2,("_spoolss_EnumPrinterData: Invalid handle (%s:%u:%u).\n",
+                       OUR_HANDLE(r->in.handle)));
                return WERR_BADFID;
        }
 
-       if (!get_printer_snum(p,handle, &snum, NULL))
+       if (!get_printer_snum(p, r->in.handle, &snum, NULL)) {
                return WERR_BADFID;
+       }
 
        result = get_a_printer(Printer, &printer, 2, lp_const_servicename(snum));
-       if (!W_ERROR_IS_OK(result))
+       if (!W_ERROR_IS_OK(result)) {
                return result;
+       }
 
        p_data = printer->info_2->data;
        key_index = lookup_printerkey( p_data, SPOOL_PRINTERDATA_KEY );
@@ -8264,12 +7961,12 @@ WERROR _spoolss_enumprinterdata(pipes_struct *p, SPOOL_Q_ENUMPRINTERDATA *q_u, S
         * cf: MSDN EnumPrinterData remark section
         */
 
-       if ( !in_value_len && !in_data_len && (key_index != -1) )
-       {
-               DEBUGADD(6,("Activating NT mega-hack to find sizes\n"));
+       if (!r->in.value_offered && !r->in.data_offered && (key_index != -1)) {
+
+               uint32_t biggest_valuesize = 0;
+               uint32_t biggest_datasize = 0;
 
-               biggest_valuesize = 0;
-               biggest_datasize  = 0;
+               DEBUGADD(6,("Activating NT mega-hack to find sizes\n"));
 
                num_values = regval_ctr_numvals( p_data->keys[key_index].values );
 
@@ -8291,10 +7988,11 @@ WERROR _spoolss_enumprinterdata(pipes_struct *p, SPOOL_Q_ENUMPRINTERDATA *q_u, S
                /* the value is an UNICODE string but real_value_size is the length
                   in bytes including the trailing 0 */
 
-               *out_value_len = 2 * (1+biggest_valuesize);
-               *out_data_len  = biggest_datasize;
+               *r->out.value_needed = 2 * (1 + biggest_valuesize);
+               *r->out.data_needed  = biggest_datasize;
 
-               DEBUG(6,("final values: [%d], [%d]\n", *out_value_len, *out_data_len));
+               DEBUG(6,("final values: [%d], [%d]\n",
+                       *r->out.value_needed, *r->out.data_needed));
 
                goto done;
        }
@@ -8304,46 +8002,34 @@ WERROR _spoolss_enumprinterdata(pipes_struct *p, SPOOL_Q_ENUMPRINTERDATA *q_u, S
         * that's the number of bytes not the number of unicode chars
         */
 
-       if ( key_index != -1 )
-               val = regval_ctr_specific_value( p_data->keys[key_index].values, idx );
+       if (key_index != -1) {
+               val = regval_ctr_specific_value(p_data->keys[key_index].values,
+                                               r->in.enum_index);
+       }
 
-       if ( !val )
-       {
+       if (!val) {
 
                /* out_value should default to "" or else NT4 has
                   problems unmarshalling the response */
 
-               *out_max_value_len=(in_value_len/sizeof(uint16));
-
-               if (in_value_len) {
-                       if((*out_value=(uint16 *)TALLOC_ZERO(p->mem_ctx, in_value_len*sizeof(uint8))) == NULL)
-                       {
+               if (r->in.value_offered) {
+                       *r->out.value_needed = 1;
+                       r->out.value_name = talloc_strdup(r, "");
+                       if (!r->out.value_name) {
                                result = WERR_NOMEM;
                                goto done;
                        }
-                       *out_value_len = (uint32)rpcstr_push((char *)*out_value, "", in_value_len, 0);
                } else {
-                       *out_value=NULL;
-                       *out_value_len = 0;
+                       r->out.value_name = NULL;
+                       *r->out.value_needed = 0;
                }
 
                /* the data is counted in bytes */
 
-               *out_max_data_len = in_data_len;
-               *out_data_len     = in_data_len;
-
-               /* only allocate when given a non-zero data_len */
-
-               if ( in_data_len && ((*data_out=(uint8 *)TALLOC_ZERO(p->mem_ctx, in_data_len*sizeof(uint8))) == NULL) )
-               {
-                       result = WERR_NOMEM;
-                       goto done;
-               }
+               *r->out.data_needed = r->in.data_offered;
 
                result = WERR_NO_MORE_ITEMS;
-       }
-       else
-       {
+       } else {
                /*
                 * the value is:
                 * - counted in bytes in the request
@@ -8354,36 +8040,29 @@ WERROR _spoolss_enumprinterdata(pipes_struct *p, SPOOL_Q_ENUMPRINTERDATA *q_u, S
                 */
 
                /* name */
-               *out_max_value_len=(in_value_len/sizeof(uint16));
-               if (in_value_len) {
-                       if ( (*out_value = (uint16 *)TALLOC_ZERO(p->mem_ctx, in_value_len*sizeof(uint8))) == NULL )
-                       {
+               if (r->in.value_offered) {
+                       r->out.value_name = talloc_strdup(r, regval_name(val));
+                       if (!r->out.value_name) {
                                result = WERR_NOMEM;
                                goto done;
                        }
-
-                       *out_value_len = (uint32)rpcstr_push((char *)*out_value, regval_name(val), (size_t)in_value_len, 0);
+                       *r->out.value_needed = strlen_m(regval_name(val));
                } else {
-                       *out_value = NULL;
-                       *out_value_len = 0;
+                       r->out.value_name = NULL;
+                       *r->out.value_needed = 0;
                }
 
                /* type */
 
-               *out_type = regval_type( val );
+               *r->out.type = regval_type(val);
 
                /* data - counted in bytes */
 
-               *out_max_data_len = in_data_len;
-               if ( in_data_len && (*data_out = (uint8 *)TALLOC_ZERO(p->mem_ctx, in_data_len*sizeof(uint8))) == NULL)
-               {
-                       result = WERR_NOMEM;
-                       goto done;
+               if (r->out.data && regval_size(val)) {
+                       memcpy(r->out.data, regval_data_p(val), regval_size(val));
                }
-               data_len = regval_size(val);
-               if ( *data_out && data_len )
-                       memcpy( *data_out, regval_data_p(val), data_len );
-               *out_data_len = data_len;
+
+               *r->out.data_needed = regval_size(val);
        }
 
 done:
@@ -8391,37 +8070,36 @@ done:
        return result;
 }
 
-/****************************************************************************
-****************************************************************************/
+/****************************************************************
+ _spoolss_SetPrinterData
+****************************************************************/
 
-WERROR _spoolss_setprinterdata( pipes_struct *p, SPOOL_Q_SETPRINTERDATA *q_u, SPOOL_R_SETPRINTERDATA *r_u)
+WERROR _spoolss_SetPrinterData(pipes_struct *p,
+                              struct spoolss_SetPrinterData *r)
 {
-       POLICY_HND              *handle = &q_u->handle;
-       UNISTR2                 *value = &q_u->value;
-       uint32                  type = q_u->type;
-       uint8                   *data = q_u->data;
-       uint32                  real_len = q_u->real_len;
-
-       NT_PRINTER_INFO_LEVEL   *printer = NULL;
-       int                     snum=0;
-       WERROR                  status = WERR_OK;
-       Printer_entry           *Printer=find_printer_index_by_hnd(p, handle);
-       fstring                 valuename;
+       NT_PRINTER_INFO_LEVEL *printer = NULL;
+       int snum=0;
+       WERROR result = WERR_OK;
+       Printer_entry *Printer = find_printer_index_by_hnd(p, r->in.handle);
+       DATA_BLOB blob;
 
-       DEBUG(5,("spoolss_setprinterdata\n"));
+       DEBUG(5,("_spoolss_SetPrinterData\n"));
 
        if (!Printer) {
-               DEBUG(2,("_spoolss_setprinterdata: Invalid handle (%s:%u:%u).\n", OUR_HANDLE(handle)));
+               DEBUG(2,("_spoolss_SetPrinterData: Invalid handle (%s:%u:%u).\n",
+                       OUR_HANDLE(r->in.handle)));
                return WERR_BADFID;
        }
 
-       if ( Printer->printer_type == SPLHND_SERVER ) {
-               DEBUG(10,("_spoolss_setprinterdata: Not implemented for server handles yet\n"));
+       if (Printer->printer_type == SPLHND_SERVER) {
+               DEBUG(10,("_spoolss_SetPrinterData: "
+                       "Not implemented for server handles yet\n"));
                return WERR_INVALID_PARAM;
        }
 
-       if (!get_printer_snum(p,handle, &snum, NULL))
+       if (!get_printer_snum(p, r->in.handle, &snum, NULL)) {
                return WERR_BADFID;
+       }
 
        /*
         * Access check : NT returns "access denied" if you make a
@@ -8431,55 +8109,63 @@ WERROR _spoolss_setprinterdata( pipes_struct *p, SPOOL_Q_SETPRINTERDATA *q_u, SP
         * when connecting to a printer  --jerry
         */
 
-       if (Printer->access_granted != PRINTER_ACCESS_ADMINISTER)
-       {
-               DEBUG(3, ("_spoolss_setprinterdata: change denied by handle access permissions\n"));
-               status = WERR_ACCESS_DENIED;
+       if (Printer->access_granted != PRINTER_ACCESS_ADMINISTER) {
+               DEBUG(3,("_spoolss_SetPrinterData: "
+                       "change denied by handle access permissions\n"));
+               result = WERR_ACCESS_DENIED;
                goto done;
        }
 
-       status = get_a_printer(Printer, &printer, 2, lp_const_servicename(snum));
-       if (!W_ERROR_IS_OK(status))
-               return status;
+       result = get_a_printer(Printer, &printer, 2, lp_const_servicename(snum));
+       if (!W_ERROR_IS_OK(result)) {
+               return result;
+       }
 
-       unistr2_to_ascii(valuename, value, sizeof(valuename));
+       result = push_spoolss_PrinterData(p->mem_ctx, &blob,
+                                         r->in.type, &r->in.data);
+       if (!W_ERROR_IS_OK(result)) {
+               goto done;
+       }
 
        /*
         * When client side code sets a magic printer data key, detect it and save
         * the current printer data and the magic key's data (its the DEVMODE) for
         * future printer/driver initializations.
         */
-       if ( (type == REG_BINARY) && strequal( valuename, PHANTOM_DEVMODE_KEY))
-       {
+       if ((r->in.type == REG_BINARY) && strequal(r->in.value_name, PHANTOM_DEVMODE_KEY)) {
                /* Set devmode and printer initialization info */
-               status = save_driver_init( printer, 2, data, real_len );
+               result = save_driver_init(printer, 2, blob.data, blob.length);
+
+               srv_spoolss_reset_printerdata(printer->info_2->drivername);
 
-               srv_spoolss_reset_printerdata( printer->info_2->drivername );
+               goto done;
        }
-       else
-       {
-       status = set_printer_dataex( printer, SPOOL_PRINTERDATA_KEY, valuename,
-                                       type, data, real_len );
-               if ( W_ERROR_IS_OK(status) )
-                       status = mod_a_printer(printer, 2);
+
+       result = set_printer_dataex(printer, SPOOL_PRINTERDATA_KEY,
+                                   r->in.value_name, r->in.type,
+                                   blob.data, blob.length);
+       if (W_ERROR_IS_OK(result)) {
+               result = mod_a_printer(printer, 2);
        }
 
 done:
        free_a_printer(&printer, 2);
 
-       return status;
+       return result;
 }
 
-/****************************************************************************
-****************************************************************************/
+/****************************************************************
+ _spoolss_ResetPrinter
+****************************************************************/
 
-WERROR _spoolss_resetprinter(pipes_struct *p, SPOOL_Q_RESETPRINTER *q_u, SPOOL_R_RESETPRINTER *r_u)
+WERROR _spoolss_ResetPrinter(pipes_struct *p,
+                            struct spoolss_ResetPrinter *r)
 {
-       POLICY_HND      *handle = &q_u->handle;
+       POLICY_HND      *handle = r->in.handle;
        Printer_entry   *Printer=find_printer_index_by_hnd(p, handle);
        int             snum;
 
-       DEBUG(5,("_spoolss_resetprinter\n"));
+       DEBUG(5,("_spoolss_ResetPrinter\n"));
 
        /*
         * All we do is to check to see if the handle and queue is valid.
@@ -8488,7 +8174,8 @@ WERROR _spoolss_resetprinter(pipes_struct *p, SPOOL_Q_RESETPRINTER *q_u, SPOOL_R
         */
 
        if (!Printer) {
-               DEBUG(2,("_spoolss_resetprinter: Invalid handle (%s:%u:%u).\n", OUR_HANDLE(handle)));
+               DEBUG(2,("_spoolss_ResetPrinter: Invalid handle (%s:%u:%u).\n",
+                       OUR_HANDLE(handle)));
                return WERR_BADFID;
        }
 
@@ -8767,65 +8454,68 @@ done:
 }
 
 /****************************************************************************
- enumprintprocessors level 1.
+ fill_print_processor1
 ****************************************************************************/
 
-static WERROR enumprintprocessors_level_1(RPC_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+static WERROR fill_print_processor1(TALLOC_CTX *mem_ctx,
+                                   struct spoolss_PrintProcessorInfo1 *r,
+                                   const char *print_processor_name)
 {
-       PRINTPROCESSOR_1 *info_1=NULL;
-       WERROR result = WERR_OK;
+       r->print_processor_name = talloc_strdup(mem_ctx, print_processor_name);
+       W_ERROR_HAVE_NO_MEMORY(r->print_processor_name);
 
-       if((info_1 = SMB_MALLOC_P(PRINTPROCESSOR_1)) == NULL)
-               return WERR_NOMEM;
+       return WERR_OK;
+}
 
-       (*returned) = 0x1;
+/****************************************************************************
+ enumprintprocessors level 1.
+****************************************************************************/
 
-       init_unistr(&info_1->name, "winprint");
+static WERROR enumprintprocessors_level_1(TALLOC_CTX *mem_ctx,
+                                         union spoolss_PrintProcessorInfo **info_p,
+                                         uint32_t *count)
+{
+       union spoolss_PrintProcessorInfo *info;
+       WERROR result;
 
-       *needed += spoolss_size_printprocessor_info_1(info_1);
+       info = TALLOC_ARRAY(mem_ctx, union spoolss_PrintProcessorInfo, 1);
+       W_ERROR_HAVE_NO_MEMORY(info);
 
-       if (*needed > offered) {
-               result = WERR_INSUFFICIENT_BUFFER;
-               goto out;
-       }
+       *count = 1;
 
-       if (!rpcbuf_alloc_size(buffer, *needed)) {
-               result = WERR_NOMEM;
+       result = fill_print_processor1(info, &info[0].info1, "winprint");
+       if (!W_ERROR_IS_OK(result)) {
                goto out;
        }
 
-       smb_io_printprocessor_info_1("", buffer, info_1, 0);
-
-out:
-       SAFE_FREE(info_1);
+ out:
+       if (!W_ERROR_IS_OK(result)) {
+               TALLOC_FREE(info);
+               *count = 0;
+               return result;
+       }
 
-       if ( !W_ERROR_IS_OK(result) )
-               *returned = 0;
+       *info_p = info;
 
-       return result;
+       return WERR_OK;
 }
 
-/****************************************************************************
-****************************************************************************/
+/****************************************************************
+ _spoolss_EnumPrintProcessors
+****************************************************************/
 
-WERROR _spoolss_enumprintprocessors(pipes_struct *p, SPOOL_Q_ENUMPRINTPROCESSORS *q_u, SPOOL_R_ENUMPRINTPROCESSORS *r_u)
+WERROR _spoolss_EnumPrintProcessors(pipes_struct *p,
+                                   struct spoolss_EnumPrintProcessors *r)
 {
-       uint32 level = q_u->level;
-       RPC_BUFFER *buffer = NULL;
-       uint32 offered = q_u->offered;
-       uint32 *needed = &r_u->needed;
-       uint32 *returned = &r_u->returned;
+       WERROR result;
 
        /* that's an [in out] buffer */
 
-       if (!q_u->buffer && (offered!=0)) {
+       if (!r->in.buffer && (r->in.offered != 0)) {
                return WERR_INVALID_PARAM;
        }
 
-       rpcbuf_move(q_u->buffer, &r_u->buffer);
-       buffer = r_u->buffer;
-
-       DEBUG(5,("spoolss_enumprintprocessors\n"));
+       DEBUG(5,("_spoolss_EnumPrintProcessors\n"));
 
        /*
         * Enumerate the print processors ...
@@ -8834,205 +8524,254 @@ WERROR _spoolss_enumprintprocessors(pipes_struct *p, SPOOL_Q_ENUMPRINTPROCESSORS
         * and I can use my nice printer checker.
         */
 
-       *returned=0;
-       *needed=0;
+       *r->out.count = 0;
+       *r->out.needed = 0;
+       *r->out.info = NULL;
 
-       switch (level) {
+       switch (r->in.level) {
        case 1:
-               return enumprintprocessors_level_1(buffer, offered, needed, returned);
+               result = enumprintprocessors_level_1(p->mem_ctx, r->out.info,
+                                                    r->out.count);
+               break;
        default:
                return WERR_UNKNOWN_LEVEL;
        }
+
+       if (!W_ERROR_IS_OK(result)) {
+               return result;
+       }
+
+       *r->out.needed  = SPOOLSS_BUFFER_UNION_ARRAY(p->mem_ctx,
+                                                    spoolss_EnumPrintProcessors, NULL,
+                                                    *r->out.info, r->in.level,
+                                                    *r->out.count);
+       *r->out.info    = SPOOLSS_BUFFER_OK(*r->out.info, NULL);
+       *r->out.count   = SPOOLSS_BUFFER_OK(*r->out.count, 0);
+
+       return SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER);
 }
 
 /****************************************************************************
- enumprintprocdatatypes level 1.
+ fill_printprocdatatype1
 ****************************************************************************/
 
-static WERROR enumprintprocdatatypes_level_1(RPC_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+static WERROR fill_printprocdatatype1(TALLOC_CTX *mem_ctx,
+                                     struct spoolss_PrintProcDataTypesInfo1 *r,
+                                     const char *name_array)
 {
-       PRINTPROCDATATYPE_1 *info_1=NULL;
-       WERROR result = WERR_OK;
+       r->name_array = talloc_strdup(mem_ctx, name_array);
+       W_ERROR_HAVE_NO_MEMORY(r->name_array);
 
-       if((info_1 = SMB_MALLOC_P(PRINTPROCDATATYPE_1)) == NULL)
-               return WERR_NOMEM;
+       return WERR_OK;
+}
 
-       (*returned) = 0x1;
+/****************************************************************************
+ enumprintprocdatatypes level 1.
+****************************************************************************/
 
-       init_unistr(&info_1->name, "RAW");
+static WERROR enumprintprocdatatypes_level_1(TALLOC_CTX *mem_ctx,
+                                            union spoolss_PrintProcDataTypesInfo **info_p,
+                                            uint32_t *count)
+{
+       WERROR result;
+       union spoolss_PrintProcDataTypesInfo *info;
 
-       *needed += spoolss_size_printprocdatatype_info_1(info_1);
+       info = TALLOC_ARRAY(mem_ctx, union spoolss_PrintProcDataTypesInfo, 1);
+       W_ERROR_HAVE_NO_MEMORY(info);
 
-       if (*needed > offered) {
-               result = WERR_INSUFFICIENT_BUFFER;
-               goto out;
-       }
+       *count = 1;
 
-       if (!rpcbuf_alloc_size(buffer, *needed)) {
-               result = WERR_NOMEM;
+       result = fill_printprocdatatype1(info, &info[0].info1, "RAW");
+       if (!W_ERROR_IS_OK(result)) {
                goto out;
        }
 
-       smb_io_printprocdatatype_info_1("", buffer, info_1, 0);
-
-out:
-       SAFE_FREE(info_1);
+ out:
+       if (!W_ERROR_IS_OK(result)) {
+               TALLOC_FREE(info);
+               *count = 0;
+               return result;
+       }
 
-       if ( !W_ERROR_IS_OK(result) )
-               *returned = 0;
+       *info_p = info;
 
-       return result;
+       return WERR_OK;
 }
 
-/****************************************************************************
-****************************************************************************/
+/****************************************************************
+ _spoolss_EnumPrintProcDataTypes
+****************************************************************/
 
-WERROR _spoolss_enumprintprocdatatypes(pipes_struct *p, SPOOL_Q_ENUMPRINTPROCDATATYPES *q_u, SPOOL_R_ENUMPRINTPROCDATATYPES *r_u)
+WERROR _spoolss_EnumPrintProcDataTypes(pipes_struct *p,
+                                      struct spoolss_EnumPrintProcDataTypes *r)
 {
-       uint32 level = q_u->level;
-       RPC_BUFFER *buffer = NULL;
-       uint32 offered = q_u->offered;
-       uint32 *needed = &r_u->needed;
-       uint32 *returned = &r_u->returned;
+       WERROR result;
 
        /* that's an [in out] buffer */
 
-       if (!q_u->buffer && (offered!=0)) {
+       if (!r->in.buffer && (r->in.offered != 0)) {
                return WERR_INVALID_PARAM;
        }
 
-       rpcbuf_move(q_u->buffer, &r_u->buffer);
-       buffer = r_u->buffer;
+       DEBUG(5,("_spoolss_EnumPrintProcDataTypes\n"));
 
-       DEBUG(5,("_spoolss_enumprintprocdatatypes\n"));
+       *r->out.count = 0;
+       *r->out.needed = 0;
+       *r->out.info = NULL;
 
-       *returned=0;
-       *needed=0;
-
-       switch (level) {
+       switch (r->in.level) {
        case 1:
-               return enumprintprocdatatypes_level_1(buffer, offered, needed, returned);
+               result = enumprintprocdatatypes_level_1(p->mem_ctx, r->out.info,
+                                                       r->out.count);
+               break;
        default:
                return WERR_UNKNOWN_LEVEL;
        }
+
+       *r->out.needed  = SPOOLSS_BUFFER_UNION_ARRAY(p->mem_ctx,
+                                                    spoolss_EnumPrintProcDataTypes, NULL,
+                                                    *r->out.info, r->in.level,
+                                                    *r->out.count);
+       *r->out.info    = SPOOLSS_BUFFER_OK(*r->out.info, NULL);
+       *r->out.count   = SPOOLSS_BUFFER_OK(*r->out.count, 0);
+
+       return SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER);
 }
 
 /****************************************************************************
- enumprintmonitors level 1.
+ fill_monitor_1
 ****************************************************************************/
 
-static WERROR enumprintmonitors_level_1(RPC_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+static WERROR fill_monitor_1(TALLOC_CTX *mem_ctx,
+                            struct spoolss_MonitorInfo1 *r,
+                            const char *monitor_name)
 {
-       PRINTMONITOR_1 *info_1;
-       WERROR result = WERR_OK;
-       int i;
+       r->monitor_name                 = talloc_strdup(mem_ctx, monitor_name);
+       W_ERROR_HAVE_NO_MEMORY(r->monitor_name);
 
-       if((info_1 = SMB_MALLOC_ARRAY(PRINTMONITOR_1, 2)) == NULL)
-               return WERR_NOMEM;
+       return WERR_OK;
+}
 
-       *returned = 2;
+/****************************************************************************
+ fill_monitor_2
+****************************************************************************/
 
-       init_unistr(&(info_1[0].name), SPL_LOCAL_PORT );
-       init_unistr(&(info_1[1].name), SPL_TCPIP_PORT );
+static WERROR fill_monitor_2(TALLOC_CTX *mem_ctx,
+                            struct spoolss_MonitorInfo2 *r,
+                            const char *monitor_name,
+                            const char *environment,
+                            const char *dll_name)
+{
+       r->monitor_name                 = talloc_strdup(mem_ctx, monitor_name);
+       W_ERROR_HAVE_NO_MEMORY(r->monitor_name);
+       r->environment                  = talloc_strdup(mem_ctx, environment);
+       W_ERROR_HAVE_NO_MEMORY(r->environment);
+       r->dll_name                     = talloc_strdup(mem_ctx, dll_name);
+       W_ERROR_HAVE_NO_MEMORY(r->dll_name);
 
-       for ( i=0; i<*returned; i++ ) {
-               *needed += spoolss_size_printmonitor_info_1(&info_1[i]);
-       }
+       return WERR_OK;
+}
 
-       if (*needed > offered) {
-               result = WERR_INSUFFICIENT_BUFFER;
-               goto out;
-       }
+/****************************************************************************
+ enumprintmonitors level 1.
+****************************************************************************/
 
-       if (!rpcbuf_alloc_size(buffer, *needed)) {
-               result = WERR_NOMEM;
+static WERROR enumprintmonitors_level_1(TALLOC_CTX *mem_ctx,
+                                       union spoolss_MonitorInfo **info_p,
+                                       uint32_t *count)
+{
+       union spoolss_MonitorInfo *info;
+       WERROR result = WERR_OK;
+
+       info = TALLOC_ARRAY(mem_ctx, union spoolss_MonitorInfo, 2);
+       W_ERROR_HAVE_NO_MEMORY(info);
+
+       *count = 2;
+
+       result = fill_monitor_1(info, &info[0].info1,
+                               SPL_LOCAL_PORT /* FIXME */);
+       if (!W_ERROR_IS_OK(result)) {
                goto out;
        }
 
-       for ( i=0; i<*returned; i++ ) {
-               smb_io_printmonitor_info_1("", buffer, &info_1[i], 0);
+       result = fill_monitor_1(info, &info[1].info1,
+                               SPL_TCPIP_PORT /* FIXME */);
+       if (!W_ERROR_IS_OK(result)) {
+               goto out;
        }
 
 out:
-       SAFE_FREE(info_1);
+       if (!W_ERROR_IS_OK(result)) {
+               TALLOC_FREE(info);
+               *count = 0;
+               return result;
+       }
 
-       if ( !W_ERROR_IS_OK(result) )
-               *returned = 0;
+       *info_p = info;
 
-       return result;
+       return WERR_OK;
 }
 
 /****************************************************************************
  enumprintmonitors level 2.
 ****************************************************************************/
 
-static WERROR enumprintmonitors_level_2(RPC_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+static WERROR enumprintmonitors_level_2(TALLOC_CTX *mem_ctx,
+                                       union spoolss_MonitorInfo **info_p,
+                                       uint32_t *count)
 {
-       PRINTMONITOR_2 *info_2;
+       union spoolss_MonitorInfo *info;
        WERROR result = WERR_OK;
-       int i;
-
-       if((info_2 = SMB_MALLOC_ARRAY(PRINTMONITOR_2, 2)) == NULL)
-               return WERR_NOMEM;
 
-       *returned = 2;
+       info = TALLOC_ARRAY(mem_ctx, union spoolss_MonitorInfo, 2);
+       W_ERROR_HAVE_NO_MEMORY(info);
 
-       init_unistr( &(info_2[0].name), SPL_LOCAL_PORT );
-       init_unistr( &(info_2[0].environment), "Windows NT X86" );
-       init_unistr( &(info_2[0].dll_name), "localmon.dll" );
+       *count = 2;
 
-       init_unistr( &(info_2[1].name), SPL_TCPIP_PORT );
-       init_unistr( &(info_2[1].environment), "Windows NT X86" );
-       init_unistr( &(info_2[1].dll_name), "tcpmon.dll" );
-
-       for ( i=0; i<*returned; i++ ) {
-               *needed += spoolss_size_printmonitor_info_2(&info_2[i]);
-       }
-
-       if (*needed > offered) {
-               result = WERR_INSUFFICIENT_BUFFER;
+       result = fill_monitor_2(info, &info[0].info2,
+                               SPL_LOCAL_PORT, /* FIXME */
+                               "Windows NT X86", /* FIXME */
+                               "localmon.dll");
+       if (!W_ERROR_IS_OK(result)) {
                goto out;
        }
 
-       if (!rpcbuf_alloc_size(buffer, *needed)) {
-               result = WERR_NOMEM;
+       result = fill_monitor_2(info, &info[1].info2,
+                               SPL_TCPIP_PORT, /* FIXME */
+                               "Windows NT X86", /* FIXME */
+                               "tcpmon.dll");
+       if (!W_ERROR_IS_OK(result)) {
                goto out;
        }
 
-       for ( i=0; i<*returned; i++ ) {
-               smb_io_printmonitor_info_2("", buffer, &info_2[i], 0);
-       }
-
 out:
-       SAFE_FREE(info_2);
+       if (!W_ERROR_IS_OK(result)) {
+               TALLOC_FREE(info);
+               *count = 0;
+               return result;
+       }
 
-       if ( !W_ERROR_IS_OK(result) )
-               *returned = 0;
+       *info_p = info;
 
-       return result;
+       return WERR_OK;
 }
 
-/****************************************************************************
-****************************************************************************/
+/****************************************************************
+ _spoolss_EnumMonitors
+****************************************************************/
 
-WERROR _spoolss_enumprintmonitors(pipes_struct *p, SPOOL_Q_ENUMPRINTMONITORS *q_u, SPOOL_R_ENUMPRINTMONITORS *r_u)
+WERROR _spoolss_EnumMonitors(pipes_struct *p,
+                            struct spoolss_EnumMonitors *r)
 {
-       uint32 level = q_u->level;
-       RPC_BUFFER *buffer = NULL;
-       uint32 offered = q_u->offered;
-       uint32 *needed = &r_u->needed;
-       uint32 *returned = &r_u->returned;
+       WERROR result;
 
        /* that's an [in out] buffer */
 
-       if (!q_u->buffer && (offered!=0)) {
+       if (!r->in.buffer && (r->in.offered != 0)) {
                return WERR_INVALID_PARAM;
        }
 
-       rpcbuf_move(q_u->buffer, &r_u->buffer);
-       buffer = r_u->buffer;
-
-       DEBUG(5,("spoolss_enumprintmonitors\n"));
+       DEBUG(5,("_spoolss_EnumMonitors\n"));
 
        /*
         * Enumerate the print monitors ...
@@ -9041,102 +8780,95 @@ WERROR _spoolss_enumprintmonitors(pipes_struct *p, SPOOL_Q_ENUMPRINTMONITORS *q_
         * and I can use my nice printer checker.
         */
 
-       *returned=0;
-       *needed=0;
+       *r->out.count = 0;
+       *r->out.needed = 0;
+       *r->out.info = NULL;
 
-       switch (level) {
+       switch (r->in.level) {
        case 1:
-               return enumprintmonitors_level_1(buffer, offered, needed, returned);
+               result = enumprintmonitors_level_1(p->mem_ctx, r->out.info,
+                                                  r->out.count);
+               break;
        case 2:
-               return enumprintmonitors_level_2(buffer, offered, needed, returned);
+               result = enumprintmonitors_level_2(p->mem_ctx, r->out.info,
+                                                  r->out.count);
+               break;
        default:
                return WERR_UNKNOWN_LEVEL;
        }
+
+       if (!W_ERROR_IS_OK(result)) {
+               return result;
+       }
+
+       *r->out.needed  = SPOOLSS_BUFFER_UNION_ARRAY(p->mem_ctx,
+                                                    spoolss_EnumMonitors, NULL,
+                                                    *r->out.info, r->in.level,
+                                                    *r->out.count);
+       *r->out.info    = SPOOLSS_BUFFER_OK(*r->out.info, NULL);
+       *r->out.count   = SPOOLSS_BUFFER_OK(*r->out.count, 0);
+
+       return SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER);
 }
 
 /****************************************************************************
 ****************************************************************************/
 
-static WERROR getjob_level_1(print_queue_struct **queue, int count, int snum,
-                             NT_PRINTER_INFO_LEVEL *ntprinter,
-                             uint32 jobid, RPC_BUFFER *buffer, uint32 offered,
-                            uint32 *needed)
+static WERROR getjob_level_1(TALLOC_CTX *mem_ctx,
+                            const print_queue_struct *queue,
+                            int count, int snum,
+                            const NT_PRINTER_INFO_LEVEL *ntprinter,
+                            uint32_t jobid,
+                            struct spoolss_JobInfo1 *r)
 {
-       int i=0;
-       bool found=False;
-       JOB_INFO_1 *info_1=NULL;
-       WERROR result = WERR_OK;
+       int i = 0;
+       bool found = false;
 
-       info_1=SMB_MALLOC_P(JOB_INFO_1);
-
-       if (info_1 == NULL) {
-               return WERR_NOMEM;
-       }
-
-       for (i=0; i<count && found==False; i++) {
-               if ((*queue)[i].job==(int)jobid)
-                       found=True;
+       for (i=0; i<count && found == false; i++) {
+               if (queue[i].job == (int)jobid) {
+                       found = true;
+               }
        }
 
-       if (found==False) {
-               SAFE_FREE(info_1);
+       if (found == false) {
                /* NT treats not found as bad param... yet another bad choice */
                return WERR_INVALID_PARAM;
        }
 
-       fill_job_info_1( info_1, &((*queue)[i-1]), i, snum, ntprinter );
-
-       *needed += spoolss_size_job_info_1(info_1);
-
-       if (*needed > offered) {
-               result = WERR_INSUFFICIENT_BUFFER;
-               goto out;
-       }
-
-       if (!rpcbuf_alloc_size(buffer, *needed)) {
-               result = WERR_NOMEM;
-               goto out;
-       }
-
-       smb_io_job_info_1("", buffer, info_1, 0);
-
-out:
-       SAFE_FREE(info_1);
-
-       return result;
+       return fill_job_info1(mem_ctx,
+                             r,
+                             &queue[i-1],
+                             i,
+                             snum,
+                             ntprinter);
 }
 
 /****************************************************************************
 ****************************************************************************/
 
-static WERROR getjob_level_2(print_queue_struct **queue, int count, int snum,
-                             NT_PRINTER_INFO_LEVEL *ntprinter,
-                             uint32 jobid, RPC_BUFFER *buffer, uint32 offered,
-                            uint32 *needed)
-{
-       int             i = 0;
-       bool            found = False;
-       JOB_INFO_2      *info_2;
-       WERROR          result;
-       DEVICEMODE      *devmode = NULL;
-       NT_DEVICEMODE   *nt_devmode = NULL;
-
-       if ( !(info_2=SMB_MALLOC_P(JOB_INFO_2)) )
-               return WERR_NOMEM;
-
-       ZERO_STRUCTP(info_2);
+static WERROR getjob_level_2(TALLOC_CTX *mem_ctx,
+                            const print_queue_struct *queue,
+                            int count, int snum,
+                            const NT_PRINTER_INFO_LEVEL *ntprinter,
+                            uint32_t jobid,
+                            struct spoolss_JobInfo2 *r)
+{
+       int i = 0;
+       bool found = false;
+       struct spoolss_DeviceMode *devmode;
+       NT_DEVICEMODE *nt_devmode;
+       WERROR result;
 
-       for ( i=0; i<count && found==False; i++ )
-       {
-               if ((*queue)[i].job == (int)jobid)
-                       found = True;
+       for (i=0; i<count && found == false; i++) {
+               if (queue[i].job == (int)jobid) {
+                       found = true;
+               }
        }
 
-       if ( !found ) {
+       if (found == false) {
                /* NT treats not found as bad param... yet another bad
                   choice */
-               result = WERR_INVALID_PARAM;
-               goto done;
+               return WERR_INVALID_PARAM;
        }
 
        /*
@@ -9145,54 +8877,36 @@ static WERROR getjob_level_2(print_queue_struct **queue, int count, int snum,
         *  a failure condition
         */
 
-       if ( !(nt_devmode=print_job_devmode( lp_const_servicename(snum), jobid )) )
-               devmode = construct_dev_mode(lp_const_servicename(snum));
-       else {
-               if ((devmode = SMB_MALLOC_P(DEVICEMODE)) != NULL) {
-                       ZERO_STRUCTP( devmode );
-                       convert_nt_devicemode( devmode, nt_devmode );
+       nt_devmode = print_job_devmode(lp_const_servicename(snum), jobid);
+       if (nt_devmode) {
+               devmode = TALLOC_ZERO_P(mem_ctx, struct spoolss_DeviceMode);
+               W_ERROR_HAVE_NO_MEMORY(devmode);
+               result = convert_nt_devicemode_new(devmode, devmode, nt_devmode);
+               if (!W_ERROR_IS_OK(result)) {
+                       return result;
                }
+       } else {
+               devmode = construct_dev_mode_new(mem_ctx, lp_const_servicename(snum));
+               W_ERROR_HAVE_NO_MEMORY(devmode);
        }
 
-       fill_job_info_2(info_2, &((*queue)[i-1]), i, snum, ntprinter, devmode);
-
-       *needed += spoolss_size_job_info_2(info_2);
-
-       if (*needed > offered) {
-               result = WERR_INSUFFICIENT_BUFFER;
-               goto done;
-       }
-
-       if (!rpcbuf_alloc_size(buffer, *needed)) {
-               result = WERR_NOMEM;
-               goto done;
-       }
-
-       smb_io_job_info_2("", buffer, info_2, 0);
-
-       result = WERR_OK;
-
- done:
-       /* Cleanup allocated memory */
-
-       free_job_info_2(info_2);        /* Also frees devmode */
-       SAFE_FREE(info_2);
-
-       return result;
+       return fill_job_info2(mem_ctx,
+                             r,
+                             &queue[i-1],
+                             i,
+                             snum,
+                             ntprinter,
+                             devmode);
 }
 
-/****************************************************************************
-****************************************************************************/
+/****************************************************************
+ _spoolss_GetJob
+****************************************************************/
 
-WERROR _spoolss_getjob( pipes_struct *p, SPOOL_Q_GETJOB *q_u, SPOOL_R_GETJOB *r_u)
+WERROR _spoolss_GetJob(pipes_struct *p,
+                      struct spoolss_GetJob *r)
 {
-       POLICY_HND *handle = &q_u->handle;
-       uint32 jobid = q_u->jobid;
-       uint32 level = q_u->level;
-       RPC_BUFFER *buffer = NULL;
-       uint32 offered = q_u->offered;
-       uint32 *needed = &r_u->needed;
-       WERROR          wstatus = WERR_OK;
+       WERROR result = WERR_OK;
        NT_PRINTER_INFO_LEVEL *ntprinter = NULL;
        int snum;
        int count;
@@ -9201,187 +8915,185 @@ WERROR _spoolss_getjob( pipes_struct *p, SPOOL_Q_GETJOB *q_u, SPOOL_R_GETJOB *r_
 
        /* that's an [in out] buffer */
 
-       if (!q_u->buffer && (offered!=0)) {
+       if (!r->in.buffer && (r->in.offered != 0)) {
                return WERR_INVALID_PARAM;
        }
 
-       rpcbuf_move(q_u->buffer, &r_u->buffer);
-       buffer = r_u->buffer;
-
-       DEBUG(5,("spoolss_getjob\n"));
+       DEBUG(5,("_spoolss_GetJob\n"));
 
-       *needed = 0;
+       *r->out.needed = 0;
 
-       if (!get_printer_snum(p, handle, &snum, NULL))
+       if (!get_printer_snum(p, r->in.handle, &snum, NULL)) {
                return WERR_BADFID;
+       }
 
-       wstatus = get_a_printer(NULL, &ntprinter, 2, lp_servicename(snum));
-       if ( !W_ERROR_IS_OK(wstatus) )
-               return wstatus;
+       result = get_a_printer(NULL, &ntprinter, 2, lp_servicename(snum));
+       if (!W_ERROR_IS_OK(result)) {
+               return result;
+       }
 
        count = print_queue_status(snum, &queue, &prt_status);
 
        DEBUGADD(4,("count:[%d], prt_status:[%d], [%s]\n",
                     count, prt_status.status, prt_status.message));
 
-       switch ( level ) {
+       switch (r->in.level) {
        case 1:
-                       wstatus = getjob_level_1(&queue, count, snum, ntprinter, jobid,
-                               buffer, offered, needed);
-                       break;
+               result = getjob_level_1(p->mem_ctx,
+                                       queue, count, snum, ntprinter,
+                                       r->in.job_id, &r->out.info->info1);
+               break;
        case 2:
-                       wstatus = getjob_level_2(&queue, count, snum, ntprinter, jobid,
-                               buffer, offered, needed);
-                       break;
+               result = getjob_level_2(p->mem_ctx,
+                                       queue, count, snum, ntprinter,
+                                       r->in.job_id, &r->out.info->info2);
+               break;
        default:
-                       wstatus = WERR_UNKNOWN_LEVEL;
-                       break;
+               result = WERR_UNKNOWN_LEVEL;
+               break;
        }
 
        SAFE_FREE(queue);
-       free_a_printer( &ntprinter, 2 );
+       free_a_printer(&ntprinter, 2);
+
+       if (!W_ERROR_IS_OK(result)) {
+               TALLOC_FREE(r->out.info);
+               return result;
+       }
+
+       *r->out.needed  = SPOOLSS_BUFFER_UNION(spoolss_JobInfo, NULL,
+                                              r->out.info, r->in.level);
+       r->out.info     = SPOOLSS_BUFFER_OK(r->out.info, NULL);
 
-       return wstatus;
+       return SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER);
 }
 
-/********************************************************************
spoolss_getprinterdataex
+/****************************************************************
_spoolss_GetPrinterDataEx
 
  From MSDN documentation of GetPrinterDataEx: pass request
  to GetPrinterData if key is "PrinterDriverData".
- ********************************************************************/
+****************************************************************/
 
-WERROR _spoolss_getprinterdataex(pipes_struct *p, SPOOL_Q_GETPRINTERDATAEX *q_u, SPOOL_R_GETPRINTERDATAEX *r_u)
+WERROR _spoolss_GetPrinterDataEx(pipes_struct *p,
+                                struct spoolss_GetPrinterDataEx *r)
 {
-       POLICY_HND      *handle = &q_u->handle;
-       uint32          in_size = q_u->size;
-       uint32          *type = &r_u->type;
-       uint32          *out_size = &r_u->size;
-       uint8           **data = &r_u->data;
-       uint32          *needed = &r_u->needed;
-       fstring         keyname, valuename;
-
-       Printer_entry   *Printer = find_printer_index_by_hnd(p, handle);
 
+       Printer_entry   *Printer = find_printer_index_by_hnd(p, r->in.handle);
+       REGISTRY_VALUE          *val = NULL;
        NT_PRINTER_INFO_LEVEL   *printer = NULL;
        int                     snum = 0;
-       WERROR                  status = WERR_OK;
-
-       DEBUG(4,("_spoolss_getprinterdataex\n"));
+       WERROR result = WERR_OK;
 
-        unistr2_to_ascii(keyname, &q_u->keyname, sizeof(keyname));
-        unistr2_to_ascii(valuename, &q_u->valuename, sizeof(valuename));
+       DEBUG(4,("_spoolss_GetPrinterDataEx\n"));
 
-       DEBUG(10, ("_spoolss_getprinterdataex: key => [%s], value => [%s]\n",
-               keyname, valuename));
+       DEBUG(10, ("_spoolss_GetPrinterDataEx: key => [%s], value => [%s]\n",
+               r->in.key_name, r->in.value_name));
 
        /* in case of problem, return some default values */
 
-       *needed   = 0;
-       *type     = 0;
-       *out_size = in_size;
+       *r->out.needed  = 0;
+       *r->out.type    = REG_NONE;
 
        if (!Printer) {
-               DEBUG(2,("_spoolss_getprinterdataex: Invalid handle (%s:%u:%u).\n", OUR_HANDLE(handle)));
-               status = WERR_BADFID;
+               DEBUG(2,("_spoolss_GetPrinterDataEx: Invalid handle (%s:%u:%u).\n",
+                       OUR_HANDLE(r->in.handle)));
+               result = WERR_BADFID;
                goto done;
        }
 
        /* Is the handle to a printer or to the server? */
 
        if (Printer->printer_type == SPLHND_SERVER) {
-               DEBUG(10,("_spoolss_getprinterdataex: Not implemented for server handles yet\n"));
-               status = WERR_INVALID_PARAM;
+               DEBUG(10,("_spoolss_GetPrinterDataEx: "
+                       "Not implemented for server handles yet\n"));
+               result = WERR_INVALID_PARAM;
                goto done;
        }
 
-       if ( !get_printer_snum(p,handle, &snum, NULL) )
+       if (!get_printer_snum(p, r->in.handle, &snum, NULL)) {
                return WERR_BADFID;
+       }
 
-       status = get_a_printer(Printer, &printer, 2, lp_servicename(snum));
-       if ( !W_ERROR_IS_OK(status) )
+       result = get_a_printer(Printer, &printer, 2, lp_servicename(snum));
+       if (!W_ERROR_IS_OK(result)) {
                goto done;
+       }
 
        /* check to see if the keyname is valid */
-       if ( !strlen(keyname) ) {
-               status = WERR_INVALID_PARAM;
+       if (!strlen(r->in.key_name)) {
+               result = WERR_INVALID_PARAM;
                goto done;
        }
 
-       if ( lookup_printerkey( printer->info_2->data, keyname ) == -1 ) {
-               DEBUG(4,("_spoolss_getprinterdataex: Invalid keyname [%s]\n", keyname ));
-               free_a_printer( &printer, 2 );
-               status = WERR_BADFILE;
+       if (lookup_printerkey(printer->info_2->data, r->in.key_name) == -1) {
+               DEBUG(4,("_spoolss_GetPrinterDataEx: "
+                       "Invalid keyname [%s]\n", r->in.key_name ));
+               result = WERR_BADFILE;
                goto done;
        }
 
        /* When given a new keyname, we should just create it */
 
-       status = get_printer_dataex( p->mem_ctx, printer, keyname, valuename, type, data, needed, in_size );
+       val = get_printer_data(printer->info_2,
+                              r->in.key_name, r->in.value_name);
+       if (!val) {
+               result = WERR_BADFILE;
+               goto done;
+       }
 
-       if (*needed > *out_size)
-               status = WERR_MORE_DATA;
+       *r->out.needed = regval_size(val);
 
-done:
-       if ( !W_ERROR_IS_OK(status) )
-       {
-               DEBUG(5, ("error: allocating %d\n", *out_size));
+       if (*r->out.needed > r->in.offered) {
+               result = WERR_MORE_DATA;
+               goto done;
+       }
 
-               /* reply this param doesn't exist */
+       *r->out.type = regval_type(val);
 
-               if ( *out_size )
-               {
-                       if( (*data=(uint8 *)TALLOC_ZERO(p->mem_ctx, *out_size*sizeof(uint8))) == NULL ) {
-                               status = WERR_NOMEM;
-                               goto done;
-                       }
-               } else {
-                       *data = NULL;
-               }
-       }
+       memcpy(r->out.buffer, regval_data_p(val), regval_size(val));
 
-       if ( printer )
-       free_a_printer( &printer, 2 );
+ done:
+       if (printer) {
+               free_a_printer(&printer, 2);
+       }
 
-       return status;
+       return result;
 }
 
-/********************************************************************
* spoolss_setprinterdataex
- ********************************************************************/
+/****************************************************************
_spoolss_SetPrinterDataEx
+****************************************************************/
 
-WERROR _spoolss_setprinterdataex(pipes_struct *p, SPOOL_Q_SETPRINTERDATAEX *q_u, SPOOL_R_SETPRINTERDATAEX *r_u)
+WERROR _spoolss_SetPrinterDataEx(pipes_struct *p,
+                                struct spoolss_SetPrinterDataEx *r)
 {
-       POLICY_HND              *handle = &q_u->handle;
-       uint32                  type = q_u->type;
-       uint8                   *data = q_u->data;
-       uint32                  real_len = q_u->real_len;
-
        NT_PRINTER_INFO_LEVEL   *printer = NULL;
        int                     snum = 0;
-       WERROR                  status = WERR_OK;
-       Printer_entry           *Printer = find_printer_index_by_hnd(p, handle);
-       fstring                 valuename;
-       fstring                 keyname;
+       WERROR                  result = WERR_OK;
+       Printer_entry           *Printer = find_printer_index_by_hnd(p, r->in.handle);
        char                    *oid_string;
 
-       DEBUG(4,("_spoolss_setprinterdataex\n"));
+       DEBUG(4,("_spoolss_SetPrinterDataEx\n"));
 
         /* From MSDN documentation of SetPrinterDataEx: pass request to
            SetPrinterData if key is "PrinterDriverData" */
 
        if (!Printer) {
-               DEBUG(2,("_spoolss_setprinterdataex: Invalid handle (%s:%u:%u).\n", OUR_HANDLE(handle)));
+               DEBUG(2,("_spoolss_SetPrinterDataEx: Invalid handle (%s:%u:%u).\n",
+                       OUR_HANDLE(r->in.handle)));
                return WERR_BADFID;
        }
 
-       if ( Printer->printer_type == SPLHND_SERVER ) {
-               DEBUG(10,("_spoolss_setprinterdataex: Not implemented for server handles yet\n"));
+       if (Printer->printer_type == SPLHND_SERVER) {
+               DEBUG(10,("_spoolss_SetPrinterDataEx: "
+                       "Not implemented for server handles yet\n"));
                return WERR_INVALID_PARAM;
        }
 
-       if ( !get_printer_snum(p,handle, &snum, NULL) )
+       if (!get_printer_snum(p, r->in.handle, &snum, NULL)) {
                return WERR_BADFID;
+       }
 
        /*
         * Access check : NT returns "access denied" if you make a
@@ -9391,37 +9103,39 @@ WERROR _spoolss_setprinterdataex(pipes_struct *p, SPOOL_Q_SETPRINTERDATAEX *q_u,
         * when connecting to a printer  --jerry
         */
 
-       if (Printer->access_granted != PRINTER_ACCESS_ADMINISTER)
-       {
-               DEBUG(3, ("_spoolss_setprinterdataex: change denied by handle access permissions\n"));
+       if (Printer->access_granted != PRINTER_ACCESS_ADMINISTER) {
+               DEBUG(3, ("_spoolss_SetPrinterDataEx: "
+                       "change denied by handle access permissions\n"));
                return WERR_ACCESS_DENIED;
        }
 
-       status = get_a_printer(Printer, &printer, 2, lp_servicename(snum));
-       if (!W_ERROR_IS_OK(status))
-               return status;
-
-        unistr2_to_ascii( valuename, &q_u->value, sizeof(valuename));
-        unistr2_to_ascii( keyname, &q_u->key, sizeof(keyname));
+       result = get_a_printer(Printer, &printer, 2, lp_servicename(snum));
+       if (!W_ERROR_IS_OK(result)) {
+               return result;
+       }
 
        /* check for OID in valuename */
 
-       if ( (oid_string = strchr( valuename, ',' )) != NULL )
-       {
+       oid_string = strchr(r->in.value_name, ',');
+       if (oid_string) {
                *oid_string = '\0';
                oid_string++;
        }
 
        /* save the registry data */
 
-       status = set_printer_dataex( printer, keyname, valuename, type, data, real_len );
+       result = set_printer_dataex(printer, r->in.key_name, r->in.value_name,
+                                   r->in.type, r->in.buffer, r->in.offered);
 
-       if ( W_ERROR_IS_OK(status) )
-       {
+       if (W_ERROR_IS_OK(result)) {
                /* save the OID if one was specified */
-               if ( oid_string ) {
-                       fstrcat( keyname, "\\" );
-                       fstrcat( keyname, SPOOL_OID_KEY );
+               if (oid_string) {
+                       char *str = talloc_asprintf(p->mem_ctx, "%s\\%s",
+                               r->in.key_name, SPOOL_OID_KEY);
+                       if (!str) {
+                               result = WERR_NOMEM;
+                               goto done;
+                       }
 
                        /*
                         * I'm not checking the status here on purpose.  Don't know
@@ -9430,17 +9144,18 @@ WERROR _spoolss_setprinterdataex(pipes_struct *p, SPOOL_Q_SETPRINTERDATAEX *q_u,
                         * this is right.    --jerry
                         */
 
-                       set_printer_dataex( printer, keyname, valuename,
-                                           REG_SZ, (uint8 *)oid_string,
-                                           strlen(oid_string)+1 );
+                       set_printer_dataex(printer, str, r->in.value_name,
+                                          REG_SZ, (uint8_t *)oid_string,
+                                          strlen(oid_string)+1);
                }
 
-               status = mod_a_printer(printer, 2);
+               result = mod_a_printer(printer, 2);
        }
 
+ done:
        free_a_printer(&printer, 2);
 
-       return status;
+       return result;
 }
 
 /****************************************************************
@@ -9491,76 +9206,88 @@ WERROR _spoolss_DeletePrinterDataEx(pipes_struct *p,
        return status;
 }
 
-/********************************************************************
- * spoolss_enumprinterkey
- ********************************************************************/
-
+/****************************************************************
+ _spoolss_EnumPrinterKey
+****************************************************************/
 
-WERROR _spoolss_enumprinterkey(pipes_struct *p, SPOOL_Q_ENUMPRINTERKEY *q_u, SPOOL_R_ENUMPRINTERKEY *r_u)
+WERROR _spoolss_EnumPrinterKey(pipes_struct *p,
+                              struct spoolss_EnumPrinterKey *r)
 {
-       fstring         key;
        fstring         *keynames = NULL;
-       uint16          *enumkeys = NULL;
-       int             num_keys;
-       int             printerkey_len;
-       POLICY_HND      *handle = &q_u->handle;
-       Printer_entry   *Printer = find_printer_index_by_hnd(p, handle);
+       int             num_keys;
+       Printer_entry   *Printer = find_printer_index_by_hnd(p, r->in.handle);
        NT_PRINTER_DATA *data;
        NT_PRINTER_INFO_LEVEL   *printer = NULL;
        int             snum = 0;
-       WERROR          status = WERR_BADFILE;
+       WERROR          result = WERR_BADFILE;
+       int i;
+       const char **array = NULL;
 
 
-       DEBUG(4,("_spoolss_enumprinterkey\n"));
+       DEBUG(4,("_spoolss_EnumPrinterKey\n"));
 
        if (!Printer) {
-               DEBUG(2,("_spoolss_enumprinterkey: Invalid handle (%s:%u:%u).\n", OUR_HANDLE(handle)));
+               DEBUG(2,("_spoolss_EnumPrinterKey: Invalid handle (%s:%u:%u).\n",
+                       OUR_HANDLE(r->in.handle)));
                return WERR_BADFID;
        }
 
-       if ( !get_printer_snum(p,handle, &snum, NULL) )
+       if (!get_printer_snum(p, r->in.handle, &snum, NULL)) {
                return WERR_BADFID;
+       }
 
-       status = get_a_printer(Printer, &printer, 2, lp_const_servicename(snum));
-       if (!W_ERROR_IS_OK(status))
-               return status;
+       result = get_a_printer(Printer, &printer, 2, lp_const_servicename(snum));
+       if (!W_ERROR_IS_OK(result)) {
+               return result;
+       }
 
        /* get the list of subkey names */
 
-       unistr2_to_ascii(key, &q_u->key, sizeof(key));
        data = printer->info_2->data;
 
-       num_keys = get_printer_subkeys( data, key, &keynames );
-
-       if ( num_keys == -1 ) {
-               status = WERR_BADFILE;
+       num_keys = get_printer_subkeys(data, r->in.key_name, &keynames);
+       if (num_keys == -1) {
+               result = WERR_BADFILE;
                goto done;
        }
 
-       printerkey_len = init_unistr_array( &enumkeys,  keynames, NULL );
+       *r->out.needed = 4;
 
-       r_u->needed = printerkey_len*2;
-
-       if ( q_u->size < r_u->needed ) {
-               status = WERR_MORE_DATA;
+       array = talloc_zero_array(r->out.key_buffer, const char *, num_keys + 1);
+       if (!array) {
+               result = WERR_NOMEM;
                goto done;
        }
 
-       if (!make_spoolss_buffer5(p->mem_ctx, &r_u->keys, printerkey_len, enumkeys)) {
-               status = WERR_NOMEM;
+       for (i=0; i < num_keys; i++) {
+               array[i] = talloc_strdup(array, keynames[i]);
+               if (!array[i]) {
+                       result = WERR_NOMEM;
+                       goto done;
+               }
+
+               *r->out.needed += strlen_m_term(keynames[i]) * 2;
+       }
+
+       if (r->in.offered < *r->out.needed) {
+               result = WERR_MORE_DATA;
                goto done;
        }
 
-       status = WERR_OK;
+       result = WERR_OK;
 
-       if ( q_u->size < r_u->needed )
-               status = WERR_MORE_DATA;
+       *r->out.key_buffer = array;
 
-done:
-       free_a_printer( &printer, 2 );
-       SAFE_FREE( keynames );
+ done:
+       if (!W_ERROR_IS_OK(result)) {
+               TALLOC_FREE(array);
+               ZERO_STRUCTP(r->out.key_buffer);
+       }
+
+       free_a_printer(&printer, 2);
+       SAFE_FREE(keynames);
 
-        return status;
+       return result;
 }
 
 /****************************************************************
@@ -9777,140 +9504,216 @@ done:
 /****************************************************************************
 ****************************************************************************/
 
-static void fill_printprocessordirectory_1(PRINTPROCESSOR_DIRECTORY_1 *info, const char *name)
-{
-       init_unistr(&info->name, name);
-}
-
-static WERROR getprintprocessordirectory_level_1(UNISTR2 *name,
-                                                UNISTR2 *environment,
-                                                RPC_BUFFER *buffer,
-                                                uint32 offered,
-                                                uint32 *needed)
+static WERROR getprintprocessordirectory_level_1(TALLOC_CTX *mem_ctx,
+                                                const char *servername,
+                                                const char *environment,
+                                                struct spoolss_PrintProcessorDirectoryInfo1 *r)
 {
-       char *long_archi = NULL;
-       PRINTPROCESSOR_DIRECTORY_1 *info=NULL;
-       WERROR result = WERR_OK;
-       TALLOC_CTX *ctx = talloc_tos();
-
-       long_archi = unistr2_to_ascii_talloc(ctx, environment);
-       if (!long_archi) {
-               return WERR_NOMEM;
-       }
-
-       if (!get_short_archi(long_archi))
-               return WERR_INVALID_ENVIRONMENT;
-
-       if((info=SMB_MALLOC_P(PRINTPROCESSOR_DIRECTORY_1)) == NULL)
-               return WERR_NOMEM;
-
-       fill_printprocessordirectory_1(info, "C:\\WINNT\\System32\\spool\\PRTPROCS\\W32X86");
-
-       *needed += spoolss_size_printprocessordirectory_info_1(info);
-
-       if (*needed > offered) {
-               result = WERR_INSUFFICIENT_BUFFER;
-               goto out;
-       }
+       WERROR werr;
+       char *path = NULL;
 
-       if (!rpcbuf_alloc_size(buffer, *needed)) {
-               result = WERR_INSUFFICIENT_BUFFER;
-               goto out;
+       werr = compose_spoolss_server_path(mem_ctx,
+                                          servername,
+                                          environment,
+                                          SPOOLSS_PRTPROCS_PATH,
+                                          &path);
+       if (!W_ERROR_IS_OK(werr)) {
+               return werr;
        }
 
-       smb_io_printprocessordirectory_1("", buffer, info, 0);
+       DEBUG(4,("print processor directory: [%s]\n", path));
 
-out:
-       SAFE_FREE(info);
+       r->directory_name = path;
 
-       return result;
+       return WERR_OK;
 }
 
-WERROR _spoolss_getprintprocessordirectory(pipes_struct *p, SPOOL_Q_GETPRINTPROCESSORDIRECTORY *q_u, SPOOL_R_GETPRINTPROCESSORDIRECTORY *r_u)
+/****************************************************************
+ _spoolss_GetPrintProcessorDirectory
+****************************************************************/
+
+WERROR _spoolss_GetPrintProcessorDirectory(pipes_struct *p,
+                                          struct spoolss_GetPrintProcessorDirectory *r)
 {
-       uint32 level = q_u->level;
-       RPC_BUFFER *buffer = NULL;
-       uint32 offered = q_u->offered;
-       uint32 *needed = &r_u->needed;
        WERROR result;
 
        /* that's an [in out] buffer */
 
-       if (!q_u->buffer && (offered!=0)) {
+       if (!r->in.buffer && (r->in.offered != 0)) {
                return WERR_INVALID_PARAM;
        }
 
-       rpcbuf_move(q_u->buffer, &r_u->buffer);
-       buffer = r_u->buffer;
+       DEBUG(5,("_spoolss_GetPrintProcessorDirectory: level %d\n",
+               r->in.level));
 
-       DEBUG(5,("_spoolss_getprintprocessordirectory\n"));
+       *r->out.needed = 0;
 
-       *needed=0;
+       /* r->in.level is ignored */
 
-       switch(level) {
-       case 1:
-               result = getprintprocessordirectory_level_1
-                 (&q_u->name, &q_u->environment, buffer, offered, needed);
-               break;
-       default:
-               result = WERR_UNKNOWN_LEVEL;
+       result = getprintprocessordirectory_level_1(p->mem_ctx,
+                                                   r->in.server,
+                                                   r->in.environment,
+                                                   &r->out.info->info1);
+       if (!W_ERROR_IS_OK(result)) {
+               TALLOC_FREE(r->out.info);
+               return result;
        }
 
-       return result;
+       *r->out.needed  = SPOOLSS_BUFFER_UNION(spoolss_PrintProcessorDirectoryInfo, NULL,
+                                              r->out.info, r->in.level);
+       r->out.info     = SPOOLSS_BUFFER_OK(r->out.info, NULL);
+
+       return SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER);
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+static bool push_monitorui_buf(TALLOC_CTX *mem_ctx, DATA_BLOB *buf,
+                              const char *dllname)
+{
+       enum ndr_err_code ndr_err;
+       struct spoolss_MonitorUi ui;
+
+       ui.dll_name = dllname;
+
+       ndr_err = ndr_push_struct_blob(buf, mem_ctx, NULL, &ui,
+                      (ndr_push_flags_fn_t)ndr_push_spoolss_MonitorUi);
+       if (NDR_ERR_CODE_IS_SUCCESS(ndr_err) && (DEBUGLEVEL >= 10)) {
+               NDR_PRINT_DEBUG(spoolss_MonitorUi, &ui);
+       }
+       return NDR_ERR_CODE_IS_SUCCESS(ndr_err);
 }
 
 /*******************************************************************
  Streams the monitor UI DLL name in UNICODE
 *******************************************************************/
 
-static WERROR xcvtcp_monitorui( NT_USER_TOKEN *token, RPC_BUFFER *in,
-                                RPC_BUFFER *out, uint32 *needed )
+static WERROR xcvtcp_monitorui(TALLOC_CTX *mem_ctx,
+                              NT_USER_TOKEN *token, DATA_BLOB *in,
+                              DATA_BLOB *out, uint32_t *needed)
 {
        const char *dllname = "tcpmonui.dll";
 
        *needed = (strlen(dllname)+1) * 2;
 
-       if ( rpcbuf_get_size(out) < *needed ) {
+       if (out->length < *needed) {
                return WERR_INSUFFICIENT_BUFFER;
        }
 
-       if ( !make_monitorui_buf( out, dllname ) ) {
+       if (!push_monitorui_buf(mem_ctx, out, dllname)) {
                return WERR_NOMEM;
        }
 
        return WERR_OK;
 }
 
+/*******************************************************************
+ ********************************************************************/
+
+static bool pull_port_data_1(TALLOC_CTX *mem_ctx,
+                            struct spoolss_PortData1 *port1,
+                            const DATA_BLOB *buf)
+{
+       enum ndr_err_code ndr_err;
+       ndr_err = ndr_pull_struct_blob(buf, mem_ctx, NULL, port1,
+                      (ndr_pull_flags_fn_t)ndr_pull_spoolss_PortData1);
+       if (NDR_ERR_CODE_IS_SUCCESS(ndr_err) && (DEBUGLEVEL >= 10)) {
+               NDR_PRINT_DEBUG(spoolss_PortData1, port1);
+       }
+       return NDR_ERR_CODE_IS_SUCCESS(ndr_err);
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+static bool pull_port_data_2(TALLOC_CTX *mem_ctx,
+                            struct spoolss_PortData2 *port2,
+                            const DATA_BLOB *buf)
+{
+       enum ndr_err_code ndr_err;
+       ndr_err = ndr_pull_struct_blob(buf, mem_ctx, NULL, port2,
+                      (ndr_pull_flags_fn_t)ndr_pull_spoolss_PortData2);
+       if (NDR_ERR_CODE_IS_SUCCESS(ndr_err) && (DEBUGLEVEL >= 10)) {
+               NDR_PRINT_DEBUG(spoolss_PortData2, port2);
+       }
+       return NDR_ERR_CODE_IS_SUCCESS(ndr_err);
+}
+
 /*******************************************************************
  Create a new TCP/IP port
 *******************************************************************/
 
-static WERROR xcvtcp_addport( NT_USER_TOKEN *token, RPC_BUFFER *in,
-                              RPC_BUFFER *out, uint32 *needed )
+static WERROR xcvtcp_addport(TALLOC_CTX *mem_ctx,
+                            NT_USER_TOKEN *token, DATA_BLOB *in,
+                            DATA_BLOB *out, uint32_t *needed)
 {
-       NT_PORT_DATA_1 port1;
-       TALLOC_CTX *ctx = talloc_tos();
+       struct spoolss_PortData1 port1;
+       struct spoolss_PortData2 port2;
        char *device_uri = NULL;
+       uint32_t version;
 
-       ZERO_STRUCT( port1 );
+       const char *portname;
+       const char *hostaddress;
+       const char *queue;
+       uint32_t port_number;
+       uint32_t protocol;
 
-       /* convert to our internal port data structure */
+       /* peek for spoolss_PortData version */
 
-       if ( !convert_port_data_1( &port1, in ) ) {
-               return WERR_NOMEM;
+       if (!in || (in->length < (128 + 4))) {
+               return WERR_GENERAL_FAILURE;
+       }
+
+       version = IVAL(in->data, 128);
+
+       switch (version) {
+               case 1:
+                       ZERO_STRUCT(port1);
+
+                       if (!pull_port_data_1(mem_ctx, &port1, in)) {
+                               return WERR_NOMEM;
+                       }
+
+                       portname        = port1.portname;
+                       hostaddress     = port1.hostaddress;
+                       queue           = port1.queue;
+                       protocol        = port1.protocol;
+                       port_number     = port1.port_number;
+
+                       break;
+               case 2:
+                       ZERO_STRUCT(port2);
+
+                       if (!pull_port_data_2(mem_ctx, &port2, in)) {
+                               return WERR_NOMEM;
+                       }
+
+                       portname        = port2.portname;
+                       hostaddress     = port2.hostaddress;
+                       queue           = port2.queue;
+                       protocol        = port2.protocol;
+                       port_number     = port2.port_number;
+
+                       break;
+               default:
+                       DEBUG(1,("xcvtcp_addport: "
+                               "unknown version of port_data: %d\n", version));
+                       return WERR_UNKNOWN_PORT;
        }
 
        /* create the device URI and call the add_port_hook() */
 
-       switch ( port1.protocol ) {
-       case PORT_PROTOCOL_DIRECT:
-               device_uri = talloc_asprintf(ctx,
-                               "socket://%s:%d/", port1.hostaddr, port1.port );
+       switch (protocol) {
+       case PROTOCOL_RAWTCP_TYPE:
+               device_uri = talloc_asprintf(mem_ctx,
+                               "socket://%s:%d/", hostaddress,
+                               port_number);
                break;
 
-       case PORT_PROTOCOL_LPR:
-               device_uri = talloc_asprintf(ctx,
-                       "lpr://%s/%s", port1.hostaddr, port1.queue );
+       case PROTOCOL_LPR_TYPE:
+               device_uri = talloc_asprintf(mem_ctx,
+                       "lpr://%s/%s", hostaddress, queue );
                break;
 
        default:
@@ -9921,7 +9724,7 @@ static WERROR xcvtcp_addport( NT_USER_TOKEN *token, RPC_BUFFER *in,
                return WERR_NOMEM;
        }
 
-       return add_port_hook(ctx, token, port1.name, device_uri );
+       return add_port_hook(mem_ctx, token, portname, device_uri);
 }
 
 /*******************************************************************
@@ -9933,9 +9736,11 @@ struct xcv_api_table xcvtcp_cmds[] = {
        { NULL,         NULL }
 };
 
-static WERROR process_xcvtcp_command( NT_USER_TOKEN *token, const char *command,
-                                      RPC_BUFFER *inbuf, RPC_BUFFER *outbuf,
-                                      uint32 *needed )
+static WERROR process_xcvtcp_command(TALLOC_CTX *mem_ctx,
+                                    NT_USER_TOKEN *token, const char *command,
+                                    DATA_BLOB *inbuf,
+                                    DATA_BLOB *outbuf,
+                                    uint32_t *needed )
 {
        int i;
 
@@ -9943,7 +9748,7 @@ static WERROR process_xcvtcp_command( NT_USER_TOKEN *token, const char *command,
 
        for ( i=0; xcvtcp_cmds[i].name; i++ ) {
                if ( strcmp( command, xcvtcp_cmds[i].name ) == 0 )
-                       return xcvtcp_cmds[i].fn( token, inbuf, outbuf, needed );
+                       return xcvtcp_cmds[i].fn(mem_ctx, token, inbuf, outbuf, needed);
        }
 
        return WERR_BADFUNC;
@@ -9953,18 +9758,19 @@ static WERROR process_xcvtcp_command( NT_USER_TOKEN *token, const char *command,
 *******************************************************************/
 #if 0  /* don't support management using the "Local Port" monitor */
 
-static WERROR xcvlocal_monitorui( NT_USER_TOKEN *token, RPC_BUFFER *in,
-                                  RPC_BUFFER *out, uint32 *needed )
+static WERROR xcvlocal_monitorui(TALLOC_CTX *mem_ctx,
+                                NT_USER_TOKEN *token, DATA_BLOB *in,
+                                DATA_BLOB *out, uint32_t *needed)
 {
        const char *dllname = "localui.dll";
 
        *needed = (strlen(dllname)+1) * 2;
 
-       if ( rpcbuf_get_size(out) < *needed ) {
+       if (out->length < *needed) {
                return WERR_INSUFFICIENT_BUFFER;
        }
 
-       if ( !make_monitorui_buf( out, dllname )) {
+       if (!push_monitorui_buf(mem_ctx, out, dllname)) {
                return WERR_NOMEM;
        }
 
@@ -9989,301 +9795,146 @@ struct xcv_api_table xcvlocal_cmds[] = {
 /*******************************************************************
 *******************************************************************/
 
-static WERROR process_xcvlocal_command( NT_USER_TOKEN *token, const char *command,
-                                        RPC_BUFFER *inbuf, RPC_BUFFER *outbuf,
-                                       uint32 *needed )
+static WERROR process_xcvlocal_command(TALLOC_CTX *mem_ctx,
+                                      NT_USER_TOKEN *token, const char *command,
+                                      DATA_BLOB *inbuf, DATA_BLOB *outbuf,
+                                      uint32_t *needed)
 {
        int i;
 
        DEBUG(10,("process_xcvlocal_command: Received command \"%s\"\n", command));
 
-       for ( i=0; xcvlocal_cmds[i].name; i++ ) {
-               if ( strcmp( command, xcvlocal_cmds[i].name ) == 0 )
-                       return xcvlocal_cmds[i].fn( token, inbuf, outbuf , needed );
-       }
-       return WERR_BADFUNC;
-}
-
-/*******************************************************************
-*******************************************************************/
-
-WERROR _spoolss_xcvdataport(pipes_struct *p, SPOOL_Q_XCVDATAPORT *q_u, SPOOL_R_XCVDATAPORT *r_u)
-{
-       Printer_entry *Printer = find_printer_index_by_hnd(p, &q_u->handle);
-       fstring command;
-
-       if (!Printer) {
-               DEBUG(2,("_spoolss_xcvdataport: Invalid handle (%s:%u:%u).\n", OUR_HANDLE(&q_u->handle)));
-               return WERR_BADFID;
-       }
-
-       /* Has to be a handle to the TCP/IP port monitor */
-
-       if ( !(Printer->printer_type & (SPLHND_PORTMON_LOCAL|SPLHND_PORTMON_TCP)) ) {
-               DEBUG(2,("_spoolss_xcvdataport: Call only valid for Port Monitors\n"));
-               return WERR_BADFID;
-       }
-
-       /* requires administrative access to the server */
-
-       if ( !(Printer->access_granted & SERVER_ACCESS_ADMINISTER) ) {
-               DEBUG(2,("_spoolss_xcvdataport: denied by handle permissions.\n"));
-               return WERR_ACCESS_DENIED;
-       }
-
-       /* Get the command name.  There's numerous commands supported by the
-          TCPMON interface. */
-
-       rpcstr_pull(command, q_u->dataname.buffer, sizeof(command),
-               q_u->dataname.uni_str_len*2, 0);
-
-       /* Allocate the outgoing buffer */
-
-       if (!rpcbuf_init( &r_u->outdata, q_u->offered, p->mem_ctx ))
-               return WERR_NOMEM;
-
-       switch ( Printer->printer_type ) {
-       case SPLHND_PORTMON_TCP:
-               return process_xcvtcp_command( p->server_info->ptok, command,
-                       &q_u->indata, &r_u->outdata, &r_u->needed );
-       case SPLHND_PORTMON_LOCAL:
-               return process_xcvlocal_command( p->server_info->ptok, command,
-                       &q_u->indata, &r_u->outdata, &r_u->needed );
-       }
-
-       return WERR_INVALID_PRINT_MONITOR;
-}
-
-/****************************************************************
- _spoolss_AddPrintProcessor
-****************************************************************/
-
-WERROR _spoolss_AddPrintProcessor(pipes_struct *p,
-                                 struct spoolss_AddPrintProcessor *r)
-{
-       /* for now, just indicate success and ignore the add.  We'll
-          automatically set the winprint processor for printer
-          entries later.  Used to debug the LexMark Optra S 1855 PCL
-          driver --jerry */
-
-       return WERR_OK;
-}
-
-/****************************************************************
- _spoolss_EnumPrinters
-****************************************************************/
-
-WERROR _spoolss_EnumPrinters(pipes_struct *p,
-                            struct spoolss_EnumPrinters *r)
-{
-       p->rng_fault_state = true;
-       return WERR_NOT_SUPPORTED;
-}
-
-/****************************************************************
- _spoolss_OpenPrinter
-****************************************************************/
-
-WERROR _spoolss_OpenPrinter(pipes_struct *p,
-                           struct spoolss_OpenPrinter *r)
-{
-       p->rng_fault_state = true;
-       return WERR_NOT_SUPPORTED;
-}
-
-/****************************************************************
- _spoolss_GetJob
-****************************************************************/
-
-WERROR _spoolss_GetJob(pipes_struct *p,
-                      struct spoolss_GetJob *r)
-{
-       p->rng_fault_state = true;
-       return WERR_NOT_SUPPORTED;
-}
-
-/****************************************************************
- _spoolss_EnumJobs
-****************************************************************/
-
-WERROR _spoolss_EnumJobs(pipes_struct *p,
-                        struct spoolss_EnumJobs *r)
-{
-       p->rng_fault_state = true;
-       return WERR_NOT_SUPPORTED;
-}
-
-/****************************************************************
- _spoolss_AddPrinter
-****************************************************************/
-
-WERROR _spoolss_AddPrinter(pipes_struct *p,
-                          struct spoolss_AddPrinter *r)
-{
-       p->rng_fault_state = true;
-       return WERR_NOT_SUPPORTED;
-}
-
-/****************************************************************
- _spoolss_SetPrinter
-****************************************************************/
-
-WERROR _spoolss_SetPrinter(pipes_struct *p,
-                          struct spoolss_SetPrinter *r)
-{
-       p->rng_fault_state = true;
-       return WERR_NOT_SUPPORTED;
-}
-
-/****************************************************************
- _spoolss_GetPrinter
-****************************************************************/
-
-WERROR _spoolss_GetPrinter(pipes_struct *p,
-                          struct spoolss_GetPrinter *r)
-{
-       p->rng_fault_state = true;
-       return WERR_NOT_SUPPORTED;
-}
-
-/****************************************************************
- _spoolss_AddPrinterDriver
-****************************************************************/
-
-WERROR _spoolss_AddPrinterDriver(pipes_struct *p,
-                                struct spoolss_AddPrinterDriver *r)
-{
-       p->rng_fault_state = true;
-       return WERR_NOT_SUPPORTED;
+       for ( i=0; xcvlocal_cmds[i].name; i++ ) {
+               if ( strcmp( command, xcvlocal_cmds[i].name ) == 0 )
+                       return xcvlocal_cmds[i].fn(mem_ctx, token, inbuf, outbuf, needed);
+       }
+       return WERR_BADFUNC;
 }
 
 /****************************************************************
- _spoolss_EnumPrinterDrivers
+ _spoolss_XcvData
 ****************************************************************/
 
-WERROR _spoolss_EnumPrinterDrivers(pipes_struct *p,
-                                  struct spoolss_EnumPrinterDrivers *r)
+WERROR _spoolss_XcvData(pipes_struct *p,
+                       struct spoolss_XcvData *r)
 {
-       p->rng_fault_state = true;
-       return WERR_NOT_SUPPORTED;
-}
+       Printer_entry *Printer = find_printer_index_by_hnd(p, r->in.handle);
+       DATA_BLOB out_data = data_blob_null;
+       WERROR werror;
 
-/****************************************************************
- _spoolss_GetPrinterDriver
-****************************************************************/
+       if (!Printer) {
+               DEBUG(2,("_spoolss_XcvData: Invalid handle (%s:%u:%u).\n",
+                       OUR_HANDLE(r->in.handle)));
+               return WERR_BADFID;
+       }
 
-WERROR _spoolss_GetPrinterDriver(pipes_struct *p,
-                                struct spoolss_GetPrinterDriver *r)
-{
-       p->rng_fault_state = true;
-       return WERR_NOT_SUPPORTED;
-}
+       /* Has to be a handle to the TCP/IP port monitor */
 
-/****************************************************************
- _spoolss_GetPrinterDriverDirectory
-****************************************************************/
+       if ( !(Printer->printer_type & (SPLHND_PORTMON_LOCAL|SPLHND_PORTMON_TCP)) ) {
+               DEBUG(2,("_spoolss_XcvData: Call only valid for Port Monitors\n"));
+               return WERR_BADFID;
+       }
 
-WERROR _spoolss_GetPrinterDriverDirectory(pipes_struct *p,
-                                         struct spoolss_GetPrinterDriverDirectory *r)
-{
-       p->rng_fault_state = true;
-       return WERR_NOT_SUPPORTED;
-}
+       /* requires administrative access to the server */
 
-/****************************************************************
- _spoolss_EnumPrintProcessors
-****************************************************************/
+       if ( !(Printer->access_granted & SERVER_ACCESS_ADMINISTER) ) {
+               DEBUG(2,("_spoolss_XcvData: denied by handle permissions.\n"));
+               return WERR_ACCESS_DENIED;
+       }
 
-WERROR _spoolss_EnumPrintProcessors(pipes_struct *p,
-                                   struct spoolss_EnumPrintProcessors *r)
-{
-       p->rng_fault_state = true;
-       return WERR_NOT_SUPPORTED;
-}
+       /* Allocate the outgoing buffer */
 
-/****************************************************************
- _spoolss_GetPrintProcessorDirectory
-****************************************************************/
+       if (r->in.out_data_size) {
+               out_data = data_blob_talloc_zero(p->mem_ctx, r->in.out_data_size);
+               if (out_data.data == NULL) {
+                       return WERR_NOMEM;
+               }
+       }
 
-WERROR _spoolss_GetPrintProcessorDirectory(pipes_struct *p,
-                                          struct spoolss_GetPrintProcessorDirectory *r)
-{
-       p->rng_fault_state = true;
-       return WERR_NOT_SUPPORTED;
-}
+       switch ( Printer->printer_type ) {
+       case SPLHND_PORTMON_TCP:
+               werror = process_xcvtcp_command(p->mem_ctx,
+                                               p->server_info->ptok,
+                                               r->in.function_name,
+                                               &r->in.in_data, &out_data,
+                                               r->out.needed);
+               break;
+       case SPLHND_PORTMON_LOCAL:
+               werror = process_xcvlocal_command(p->mem_ctx,
+                                                 p->server_info->ptok,
+                                                 r->in.function_name,
+                                                 &r->in.in_data, &out_data,
+                                                 r->out.needed);
+               break;
+       default:
+               werror = WERR_INVALID_PRINT_MONITOR;
+       }
 
-/****************************************************************
- _spoolss_ReadPrinter
-****************************************************************/
+       if (!W_ERROR_IS_OK(werror)) {
+               return werror;
+       }
 
-WERROR _spoolss_ReadPrinter(pipes_struct *p,
-                           struct spoolss_ReadPrinter *r)
-{
-       p->rng_fault_state = true;
-       return WERR_NOT_SUPPORTED;
-}
+       *r->out.status_code = 0;
 
-/****************************************************************
- _spoolss_GetPrinterData
-****************************************************************/
+       memcpy(r->out.out_data, out_data.data, out_data.length);
 
-WERROR _spoolss_GetPrinterData(pipes_struct *p,
-                              struct spoolss_GetPrinterData *r)
-{
-       p->rng_fault_state = true;
-       return WERR_NOT_SUPPORTED;
+       return WERR_OK;
 }
 
 /****************************************************************
- _spoolss_SetPrinterData
+ _spoolss_AddPrintProcessor
 ****************************************************************/
 
-WERROR _spoolss_SetPrinterData(pipes_struct *p,
-                              struct spoolss_SetPrinterData *r)
+WERROR _spoolss_AddPrintProcessor(pipes_struct *p,
+                                 struct spoolss_AddPrintProcessor *r)
 {
-       p->rng_fault_state = true;
-       return WERR_NOT_SUPPORTED;
+       /* for now, just indicate success and ignore the add.  We'll
+          automatically set the winprint processor for printer
+          entries later.  Used to debug the LexMark Optra S 1855 PCL
+          driver --jerry */
+
+       return WERR_OK;
 }
 
 /****************************************************************
- _spoolss_WaitForPrinterChange
+ _spoolss_AddPrinter
 ****************************************************************/
 
-WERROR _spoolss_WaitForPrinterChange(pipes_struct *p,
-                                    struct spoolss_WaitForPrinterChange *r)
+WERROR _spoolss_AddPrinter(pipes_struct *p,
+                          struct spoolss_AddPrinter *r)
 {
        p->rng_fault_state = true;
        return WERR_NOT_SUPPORTED;
 }
 
 /****************************************************************
- _spoolss_EnumForms
+ _spoolss_GetPrinterDriver
 ****************************************************************/
 
-WERROR _spoolss_EnumForms(pipes_struct *p,
-                         struct spoolss_EnumForms *r)
+WERROR _spoolss_GetPrinterDriver(pipes_struct *p,
+                                struct spoolss_GetPrinterDriver *r)
 {
        p->rng_fault_state = true;
        return WERR_NOT_SUPPORTED;
 }
 
 /****************************************************************
- _spoolss_EnumPorts
+ _spoolss_ReadPrinter
 ****************************************************************/
 
-WERROR _spoolss_EnumPorts(pipes_struct *p,
-                         struct spoolss_EnumPorts *r)
+WERROR _spoolss_ReadPrinter(pipes_struct *p,
+                           struct spoolss_ReadPrinter *r)
 {
        p->rng_fault_state = true;
        return WERR_NOT_SUPPORTED;
 }
 
 /****************************************************************
- _spoolss_EnumMonitors
+ _spoolss_WaitForPrinterChange
 ****************************************************************/
 
-WERROR _spoolss_EnumMonitors(pipes_struct *p,
-                            struct spoolss_EnumMonitors *r)
+WERROR _spoolss_WaitForPrinterChange(pipes_struct *p,
+                                    struct spoolss_WaitForPrinterChange *r)
 {
        p->rng_fault_state = true;
        return WERR_NOT_SUPPORTED;
@@ -10443,39 +10094,6 @@ WERROR _spoolss_DeletePrintProvidor(pipes_struct *p,
        return WERR_NOT_SUPPORTED;
 }
 
-/****************************************************************
- _spoolss_EnumPrintProcDataTypes
-****************************************************************/
-
-WERROR _spoolss_EnumPrintProcDataTypes(pipes_struct *p,
-                                      struct spoolss_EnumPrintProcDataTypes *r)
-{
-       p->rng_fault_state = true;
-       return WERR_NOT_SUPPORTED;
-}
-
-/****************************************************************
- _spoolss_ResetPrinter
-****************************************************************/
-
-WERROR _spoolss_ResetPrinter(pipes_struct *p,
-                            struct spoolss_ResetPrinter *r)
-{
-       p->rng_fault_state = true;
-       return WERR_NOT_SUPPORTED;
-}
-
-/****************************************************************
- _spoolss_GetPrinterDriver2
-****************************************************************/
-
-WERROR _spoolss_GetPrinterDriver2(pipes_struct *p,
-                                 struct spoolss_GetPrinterDriver2 *r)
-{
-       p->rng_fault_state = true;
-       return WERR_NOT_SUPPORTED;
-}
-
 /****************************************************************
  _spoolss_FindFirstPrinterChangeNotification
 ****************************************************************/
@@ -10587,33 +10205,11 @@ WERROR _spoolss_ResetPrinterEx(pipes_struct *p,
 }
 
 /****************************************************************
- _spoolss_RemoteFindFirstPrinterChangeNotifyEx
-****************************************************************/
-
-WERROR _spoolss_RemoteFindFirstPrinterChangeNotifyEx(pipes_struct *p,
-                                                    struct spoolss_RemoteFindFirstPrinterChangeNotifyEx *r)
-{
-       p->rng_fault_state = true;
-       return WERR_NOT_SUPPORTED;
-}
-
-/****************************************************************
- _spoolss_RouterRefreshPrinterChangeNotification
-****************************************************************/
-
-WERROR _spoolss_RouterRefreshPrinterChangeNotification(pipes_struct *p,
-                                                      struct spoolss_RouterRefreshPrinterChangeNotification *r)
-{
-       p->rng_fault_state = true;
-       return WERR_NOT_SUPPORTED;
-}
-
-/****************************************************************
- _spoolss_RemoteFindNextPrinterChangeNotifyEx
+ _spoolss_RouterReplyPrinterEx
 ****************************************************************/
 
-WERROR _spoolss_RemoteFindNextPrinterChangeNotifyEx(pipes_struct *p,
-                                                   struct spoolss_RemoteFindNextPrinterChangeNotifyEx *r)
+WERROR _spoolss_RouterReplyPrinterEx(pipes_struct *p,
+                                    struct spoolss_RouterReplyPrinterEx *r)
 {
        p->rng_fault_state = true;
        return WERR_NOT_SUPPORTED;
@@ -10630,17 +10226,6 @@ WERROR _spoolss_44(pipes_struct *p,
        return WERR_NOT_SUPPORTED;
 }
 
-/****************************************************************
- _spoolss_AddPrinterEx
-****************************************************************/
-
-WERROR _spoolss_AddPrinterEx(pipes_struct *p,
-                            struct spoolss_AddPrinterEx *r)
-{
-       p->rng_fault_state = true;
-       return WERR_NOT_SUPPORTED;
-}
-
 /****************************************************************
  _spoolss_47
 ****************************************************************/
@@ -10652,17 +10237,6 @@ WERROR _spoolss_47(pipes_struct *p,
        return WERR_NOT_SUPPORTED;
 }
 
-/****************************************************************
- _spoolss_EnumPrinterData
-****************************************************************/
-
-WERROR _spoolss_EnumPrinterData(pipes_struct *p,
-                               struct spoolss_EnumPrinterData *r)
-{
-       p->rng_fault_state = true;
-       return WERR_NOT_SUPPORTED;
-}
-
 /****************************************************************
  _spoolss_4a
 ****************************************************************/
@@ -10696,28 +10270,6 @@ WERROR _spoolss_4c(pipes_struct *p,
        return WERR_NOT_SUPPORTED;
 }
 
-/****************************************************************
- _spoolss_SetPrinterDataEx
-****************************************************************/
-
-WERROR _spoolss_SetPrinterDataEx(pipes_struct *p,
-                                struct spoolss_SetPrinterDataEx *r)
-{
-       p->rng_fault_state = true;
-       return WERR_NOT_SUPPORTED;
-}
-
-/****************************************************************
- _spoolss_GetPrinterDataEx
-****************************************************************/
-
-WERROR _spoolss_GetPrinterDataEx(pipes_struct *p,
-                                struct spoolss_GetPrinterDataEx *r)
-{
-       p->rng_fault_state = true;
-       return WERR_NOT_SUPPORTED;
-}
-
 /****************************************************************
  _spoolss_EnumPrinterDataEx
 ****************************************************************/
@@ -10729,17 +10281,6 @@ WERROR _spoolss_EnumPrinterDataEx(pipes_struct *p,
        return WERR_NOT_SUPPORTED;
 }
 
-/****************************************************************
- _spoolss_EnumPrinterKey
-****************************************************************/
-
-WERROR _spoolss_EnumPrinterKey(pipes_struct *p,
-                              struct spoolss_EnumPrinterKey *r)
-{
-       p->rng_fault_state = true;
-       return WERR_NOT_SUPPORTED;
-}
-
 /****************************************************************
  _spoolss_53
 ****************************************************************/
@@ -10784,28 +10325,6 @@ WERROR _spoolss_57(pipes_struct *p,
        return WERR_NOT_SUPPORTED;
 }
 
-/****************************************************************
- _spoolss_XcvData
-****************************************************************/
-
-WERROR _spoolss_XcvData(pipes_struct *p,
-                       struct spoolss_XcvData *r)
-{
-       p->rng_fault_state = true;
-       return WERR_NOT_SUPPORTED;
-}
-
-/****************************************************************
- _spoolss_AddPrinterDriverEx
-****************************************************************/
-
-WERROR _spoolss_AddPrinterDriverEx(pipes_struct *p,
-                                  struct spoolss_AddPrinterDriverEx *r)
-{
-       p->rng_fault_state = true;
-       return WERR_NOT_SUPPORTED;
-}
-
 /****************************************************************
  _spoolss_5a
 ****************************************************************/