e24fb99e6fdc0a5b20b3bca2e6dddbaa70a2e6ed
[ira/wip.git] / source3 / rpcclient / cmd_spoolss.c
1 /*
2    Unix SMB/CIFS implementation.
3    RPC pipe client
4
5    Copyright (C) Gerald Carter                2001-2005
6    Copyright (C) Tim Potter                        2000
7    Copyright (C) Andrew Tridgell              1992-1999
8    Copyright (C) Luke Kenneth Casson Leighton 1996-1999
9    Copyright (C) Guenther Deschner                 2009
10
11    This program is free software; you can redistribute it and/or modify
12    it under the terms of the GNU General Public License as published by
13    the Free Software Foundation; either version 3 of the License, or
14    (at your option) any later version.
15
16    This program is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19    GNU General Public License for more details.
20
21    You should have received a copy of the GNU General Public License
22    along with this program.  If not, see <http://www.gnu.org/licenses/>.
23 */
24
25 #include "includes.h"
26 #include "rpcclient.h"
27 #include "../librpc/gen_ndr/cli_spoolss.h"
28
29 #define RPCCLIENT_PRINTERNAME(_printername, _cli, _arg) \
30 { \
31         _printername = talloc_asprintf_strupper_m(mem_ctx, "%s\\%s", \
32                 _cli->srv_name_slash, _arg); \
33         W_ERROR_HAVE_NO_MEMORY(_printername); \
34 }
35
36 /* The version int is used by getdrivers.  Note that
37    all architecture strings that support mutliple
38    versions must be grouped together since enumdrivers
39    uses this property to prevent issuing multiple
40    enumdriver calls for the same arch */
41
42
43 static const struct print_architecture_table_node archi_table[]= {
44
45         {"Windows 4.0",          "WIN40",       0 },
46         {"Windows NT x86",       "W32X86",      2 },
47         {"Windows NT x86",       "W32X86",      3 },
48         {"Windows NT R4000",     "W32MIPS",     2 },
49         {"Windows NT Alpha_AXP", "W32ALPHA",    2 },
50         {"Windows NT PowerPC",   "W32PPC",      2 },
51         {"Windows IA64",         "IA64",        3 },
52         {"Windows x64",          "x64",         3 },
53         {NULL,                   "",            -1 }
54 };
55
56 /**
57  * @file
58  *
59  * rpcclient module for SPOOLSS rpc pipe.
60  *
61  * This generally just parses and checks command lines, and then calls
62  * a cli_spoolss function.
63  **/
64
65 /****************************************************************************
66  function to do the mapping between the long architecture name and
67  the short one.
68 ****************************************************************************/
69
70 static const char *cmd_spoolss_get_short_archi(const char *long_archi)
71 {
72         int i=-1;
73
74         DEBUG(107,("Getting architecture dependant directory\n"));
75         do {
76                 i++;
77         } while ( (archi_table[i].long_archi!=NULL ) &&
78                   StrCaseCmp(long_archi, archi_table[i].long_archi) );
79
80         if (archi_table[i].long_archi==NULL) {
81                 DEBUGADD(10,("Unknown architecture [%s] !\n", long_archi));
82                 return NULL;
83         }
84
85         /* this might be client code - but shouldn't this be an fstrcpy etc? */
86
87
88         DEBUGADD(108,("index: [%d]\n", i));
89         DEBUGADD(108,("long architecture: [%s]\n", archi_table[i].long_archi));
90         DEBUGADD(108,("short architecture: [%s]\n", archi_table[i].short_archi));
91
92         return archi_table[i].short_archi;
93 }
94
95 /****************************************************************************
96 ****************************************************************************/
97
98 static WERROR cmd_spoolss_open_printer_ex(struct rpc_pipe_client *cli,
99                                             TALLOC_CTX *mem_ctx,
100                                             int argc, const char **argv)
101 {
102         WERROR          werror;
103         struct policy_handle    hnd;
104
105         if (argc != 2) {
106                 printf("Usage: %s <printername>\n", argv[0]);
107                 return WERR_OK;
108         }
109
110         if (!cli)
111             return WERR_GENERAL_FAILURE;
112
113         /* Open the printer handle */
114
115         werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
116                                                argv[1],
117                                                PRINTER_ALL_ACCESS,
118                                                &hnd);
119         if (W_ERROR_IS_OK(werror)) {
120                 printf("Printer %s opened successfully\n", argv[1]);
121                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &hnd, &werror);
122
123                 if (!W_ERROR_IS_OK(werror)) {
124                         printf("Error closing printer handle! (%s)\n",
125                                 get_dos_error_msg(werror));
126                 }
127         }
128
129         return werror;
130 }
131
132
133 /****************************************************************************
134 ****************************************************************************/
135
136 static void display_print_info0(struct spoolss_PrinterInfo0 *r)
137 {
138         if (!r)
139                 return;
140
141         printf("\tprintername:[%s]\n", r->printername);
142         printf("\tservername:[%s]\n", r->servername);
143         printf("\tcjobs:[0x%x]\n", r->cjobs);
144         printf("\ttotal_jobs:[0x%x]\n", r->total_jobs);
145         printf("\ttotal_bytes:[0x%x]\n", r->total_bytes);
146         printf("\t:date: [%d]-[%d]-[%d] (%d)\n", r->time.year, r->time.month,
147                r->time.day, r->time.day_of_week);
148         printf("\t:time: [%d]-[%d]-[%d]-[%d]\n", r->time.hour, r->time.minute,
149                r->time.second, r->time.millisecond);
150
151         printf("\tglobal_counter:[0x%x]\n", r->global_counter);
152         printf("\ttotal_pages:[0x%x]\n", r->total_pages);
153
154         printf("\tversion:[0x%x]\n", r->version);
155         printf("\tfree_build:[0x%x]\n", r->free_build);
156         printf("\tspooling:[0x%x]\n", r->spooling);
157         printf("\tmax_spooling:[0x%x]\n", r->max_spooling);
158         printf("\tsession_counter:[0x%x]\n", r->session_counter);
159         printf("\tnum_error_out_of_paper:[0x%x]\n", r->num_error_out_of_paper);
160         printf("\tnum_error_not_ready:[0x%x]\n", r->num_error_not_ready);
161         printf("\tjob_error:[0x%x]\n", r->job_error);
162         printf("\tnumber_of_processors:[0x%x]\n", r->number_of_processors);
163         printf("\tprocessor_type:[0x%x]\n", r->processor_type);
164         printf("\thigh_part_total_bytes:[0x%x]\n", r->high_part_total_bytes);
165         printf("\tchange_id:[0x%x]\n", r->change_id);
166         printf("\tlast_error: %s\n", win_errstr(r->last_error));
167         printf("\tstatus:[0x%x]\n", r->status);
168         printf("\tenumerate_network_printers:[0x%x]\n", r->enumerate_network_printers);
169         printf("\tc_setprinter:[0x%x]\n", r->c_setprinter);
170         printf("\tprocessor_architecture:[0x%x]\n", r->processor_architecture);
171         printf("\tprocessor_level:[0x%x]\n", r->processor_level);
172         printf("\tref_ic:[0x%x]\n", r->ref_ic);
173         printf("\treserved2:[0x%x]\n", r->reserved2);
174         printf("\treserved3:[0x%x]\n", r->reserved3);
175
176         printf("\n");
177 }
178
179 /****************************************************************************
180 ****************************************************************************/
181
182 static void display_print_info1(struct spoolss_PrinterInfo1 *r)
183 {
184         printf("\tflags:[0x%x]\n", r->flags);
185         printf("\tname:[%s]\n", r->name);
186         printf("\tdescription:[%s]\n", r->description);
187         printf("\tcomment:[%s]\n", r->comment);
188
189         printf("\n");
190 }
191
192 /****************************************************************************
193 ****************************************************************************/
194
195 static void display_print_info2(struct spoolss_PrinterInfo2 *r)
196 {
197         printf("\tservername:[%s]\n", r->servername);
198         printf("\tprintername:[%s]\n", r->printername);
199         printf("\tsharename:[%s]\n", r->sharename);
200         printf("\tportname:[%s]\n", r->portname);
201         printf("\tdrivername:[%s]\n", r->drivername);
202         printf("\tcomment:[%s]\n", r->comment);
203         printf("\tlocation:[%s]\n", r->location);
204         printf("\tsepfile:[%s]\n", r->sepfile);
205         printf("\tprintprocessor:[%s]\n", r->printprocessor);
206         printf("\tdatatype:[%s]\n", r->datatype);
207         printf("\tparameters:[%s]\n", r->parameters);
208         printf("\tattributes:[0x%x]\n", r->attributes);
209         printf("\tpriority:[0x%x]\n", r->priority);
210         printf("\tdefaultpriority:[0x%x]\n", r->defaultpriority);
211         printf("\tstarttime:[0x%x]\n", r->starttime);
212         printf("\tuntiltime:[0x%x]\n", r->untiltime);
213         printf("\tstatus:[0x%x]\n", r->status);
214         printf("\tcjobs:[0x%x]\n", r->cjobs);
215         printf("\taverageppm:[0x%x]\n", r->averageppm);
216
217         if (r->secdesc)
218                 display_sec_desc(r->secdesc);
219
220         printf("\n");
221 }
222
223 /****************************************************************************
224 ****************************************************************************/
225
226 static void display_print_info3(struct spoolss_PrinterInfo3 *r)
227 {
228         display_sec_desc(r->secdesc);
229
230         printf("\n");
231 }
232
233 /****************************************************************************
234 ****************************************************************************/
235
236 static void display_print_info4(struct spoolss_PrinterInfo4 *r)
237 {
238         printf("\tservername:[%s]\n", r->servername);
239         printf("\tprintername:[%s]\n", r->printername);
240         printf("\tattributes:[0x%x]\n", r->attributes);
241         printf("\n");
242 }
243
244 /****************************************************************************
245 ****************************************************************************/
246
247 static void display_print_info5(struct spoolss_PrinterInfo5 *r)
248 {
249         printf("\tprintername:[%s]\n", r->printername);
250         printf("\tportname:[%s]\n", r->portname);
251         printf("\tattributes:[0x%x]\n", r->attributes);
252         printf("\tdevice_not_selected_timeout:[0x%x]\n", r->device_not_selected_timeout);
253         printf("\ttransmission_retry_timeout:[0x%x]\n", r->transmission_retry_timeout);
254         printf("\n");
255 }
256
257 /****************************************************************************
258 ****************************************************************************/
259
260 static void display_print_info6(struct spoolss_PrinterInfo6 *r)
261 {
262         printf("\tstatus:[0x%x]\n", r->status);
263         printf("\n");
264 }
265
266 /****************************************************************************
267 ****************************************************************************/
268
269 static void display_print_info7(struct spoolss_PrinterInfo7 *r)
270 {
271         printf("\tguid:[%s]\n", r->guid);
272         printf("\taction:[0x%x]\n", r->action);
273         printf("\n");
274 }
275
276 /****************************************************************************
277 ****************************************************************************/
278
279 static WERROR cmd_spoolss_enum_printers(struct rpc_pipe_client *cli,
280                                         TALLOC_CTX *mem_ctx,
281                                         int argc, const char **argv)
282 {
283         WERROR                  result;
284         uint32_t                level = 1;
285         union spoolss_PrinterInfo *info;
286         uint32_t                i, count;
287         const char *name;
288         uint32_t flags = PRINTER_ENUM_LOCAL;
289
290         if (argc > 4) {
291                 printf("Usage: %s [level] [name] [flags]\n", argv[0]);
292                 return WERR_OK;
293         }
294
295         if (argc >= 2) {
296                 level = atoi(argv[1]);
297         }
298
299         if (argc >= 3) {
300                 name = argv[2];
301         } else {
302                 name = cli->srv_name_slash;
303         }
304
305         if (argc == 4) {
306                 flags = atoi(argv[3]);
307         }
308
309         result = rpccli_spoolss_enumprinters(cli, mem_ctx,
310                                              flags,
311                                              name,
312                                              level,
313                                              0,
314                                              &count,
315                                              &info);
316         if (W_ERROR_IS_OK(result)) {
317
318                 if (!count) {
319                         printf ("No printers returned.\n");
320                         goto done;
321                 }
322
323                 for (i = 0; i < count; i++) {
324                         switch (level) {
325                         case 0:
326                                 display_print_info0(&info[i].info0);
327                                 break;
328                         case 1:
329                                 display_print_info1(&info[i].info1);
330                                 break;
331                         case 2:
332                                 display_print_info2(&info[i].info2);
333                                 break;
334                         case 3:
335                                 display_print_info3(&info[i].info3);
336                                 break;
337                         case 4:
338                                 display_print_info4(&info[i].info4);
339                                 break;
340                         case 5:
341                                 display_print_info5(&info[i].info5);
342                                 break;
343                         case 6:
344                                 display_print_info6(&info[i].info6);
345                                 break;
346                         default:
347                                 printf("unknown info level %d\n", level);
348                                 goto done;
349                         }
350                 }
351         }
352  done:
353
354         return result;
355 }
356
357 /****************************************************************************
358 ****************************************************************************/
359
360 static void display_port_info_1(struct spoolss_PortInfo1 *r)
361 {
362         printf("\tPort Name:\t[%s]\n", r->port_name);
363 }
364
365 /****************************************************************************
366 ****************************************************************************/
367
368 static void display_port_info_2(struct spoolss_PortInfo2 *r)
369 {
370         printf("\tPort Name:\t[%s]\n", r->port_name);
371         printf("\tMonitor Name:\t[%s]\n", r->monitor_name);
372         printf("\tDescription:\t[%s]\n", r->description);
373         printf("\tPort Type:\t" );
374         if (r->port_type) {
375                 int comma = 0; /* hack */
376                 printf( "[" );
377                 if (r->port_type & SPOOLSS_PORT_TYPE_READ) {
378                         printf( "Read" );
379                         comma = 1;
380                 }
381                 if (r->port_type & SPOOLSS_PORT_TYPE_WRITE) {
382                         printf( "%sWrite", comma ? ", " : "" );
383                         comma = 1;
384                 }
385                 /* These two have slightly different interpretations
386                  on 95/98/ME but I'm disregarding that for now */
387                 if (r->port_type & SPOOLSS_PORT_TYPE_REDIRECTED) {
388                         printf( "%sRedirected", comma ? ", " : "" );
389                         comma = 1;
390                 }
391                 if (r->port_type & SPOOLSS_PORT_TYPE_NET_ATTACHED) {
392                         printf( "%sNet-Attached", comma ? ", " : "" );
393                 }
394                 printf( "]\n" );
395         } else {
396                 printf( "[Unset]\n" );
397         }
398         printf("\tReserved:\t[%d]\n", r->reserved);
399         printf("\n");
400 }
401
402 /****************************************************************************
403 ****************************************************************************/
404
405 static WERROR cmd_spoolss_enum_ports(struct rpc_pipe_client *cli,
406                                        TALLOC_CTX *mem_ctx, int argc,
407                                        const char **argv)
408 {
409         WERROR                  result;
410         uint32_t                level = 1;
411         uint32_t                count;
412         union spoolss_PortInfo *info;
413
414         if (argc > 2) {
415                 printf("Usage: %s [level]\n", argv[0]);
416                 return WERR_OK;
417         }
418
419         if (argc == 2) {
420                 level = atoi(argv[1]);
421         }
422
423         /* Enumerate ports */
424
425         result = rpccli_spoolss_enumports(cli, mem_ctx,
426                                           cli->srv_name_slash,
427                                           level,
428                                           0,
429                                           &count,
430                                           &info);
431         if (W_ERROR_IS_OK(result)) {
432                 int i;
433
434                 for (i = 0; i < count; i++) {
435                         switch (level) {
436                         case 1:
437                                 display_port_info_1(&info[i].info1);
438                                 break;
439                         case 2:
440                                 display_port_info_2(&info[i].info2);
441                                 break;
442                         default:
443                                 printf("unknown info level %d\n", level);
444                                 break;
445                         }
446                 }
447         }
448
449         return result;
450 }
451
452 /****************************************************************************
453 ****************************************************************************/
454
455 static WERROR cmd_spoolss_setprinter(struct rpc_pipe_client *cli,
456                                        TALLOC_CTX *mem_ctx,
457                                        int argc, const char **argv)
458 {
459         struct policy_handle pol;
460         WERROR          result;
461         NTSTATUS        status;
462         uint32_t        info_level = 2;
463         union spoolss_PrinterInfo info;
464         struct spoolss_SetPrinterInfoCtr info_ctr;
465         const char      *printername, *comment = NULL;
466         struct spoolss_DevmodeContainer devmode_ctr;
467         struct sec_desc_buf secdesc_ctr;
468
469         if (argc == 1 || argc > 3) {
470                 printf("Usage: %s printername comment\n", argv[0]);
471
472                 return WERR_OK;
473         }
474
475         /* Open a printer handle */
476         if (argc == 3) {
477                 comment = argv[2];
478         }
479
480         ZERO_STRUCT(devmode_ctr);
481         ZERO_STRUCT(secdesc_ctr);
482
483         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
484
485         /* get a printer handle */
486         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
487                                                printername,
488                                                PRINTER_ALL_ACCESS,
489                                                &pol);
490         if (!W_ERROR_IS_OK(result))
491                 goto done;
492
493         /* Get printer info */
494         result = rpccli_spoolss_getprinter(cli, mem_ctx,
495                                            &pol,
496                                            info_level,
497                                            0,
498                                            &info);
499         if (!W_ERROR_IS_OK(result))
500                 goto done;
501
502
503         /* Modify the comment. */
504         info.info2.comment = comment;
505         info.info2.secdesc = NULL;
506         info.info2.devmode = NULL;
507
508         info_ctr.level = 2;
509         info_ctr.info.info2 = (struct spoolss_SetPrinterInfo2 *)&info.info2;
510
511         status = rpccli_spoolss_SetPrinter(cli, mem_ctx,
512                                            &pol,
513                                            &info_ctr,
514                                            &devmode_ctr,
515                                            &secdesc_ctr,
516                                            0, /* command */
517                                            &result);
518         if (W_ERROR_IS_OK(result))
519                 printf("Success in setting comment.\n");
520
521  done:
522         if (is_valid_policy_hnd(&pol))
523                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &pol, NULL);
524
525         return result;
526 }
527
528 /****************************************************************************
529 ****************************************************************************/
530
531 static WERROR cmd_spoolss_setprintername(struct rpc_pipe_client *cli,
532                                        TALLOC_CTX *mem_ctx,
533                                        int argc, const char **argv)
534 {
535         struct policy_handle pol;
536         WERROR          result;
537         NTSTATUS        status;
538         uint32_t        info_level = 2;
539         union spoolss_PrinterInfo info;
540         const char      *printername,
541                         *new_printername = NULL;
542         struct spoolss_SetPrinterInfoCtr info_ctr;
543         struct spoolss_DevmodeContainer devmode_ctr;
544         struct sec_desc_buf secdesc_ctr;
545
546         ZERO_STRUCT(devmode_ctr);
547         ZERO_STRUCT(secdesc_ctr);
548
549         if (argc == 1 || argc > 3) {
550                 printf("Usage: %s printername new_printername\n", argv[0]);
551
552                 return WERR_OK;
553         }
554
555         /* Open a printer handle */
556         if (argc == 3) {
557                 new_printername = argv[2];
558         }
559
560         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
561
562         /* get a printer handle */
563         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
564                                                printername,
565                                                PRINTER_ALL_ACCESS,
566                                                &pol);
567         if (!W_ERROR_IS_OK(result))
568                 goto done;
569
570         /* Get printer info */
571         result = rpccli_spoolss_getprinter(cli, mem_ctx,
572                                            &pol,
573                                            info_level,
574                                            0,
575                                            &info);
576         if (!W_ERROR_IS_OK(result))
577                 goto done;
578
579         /* Modify the printername. */
580         info.info2.printername = new_printername;
581         info.info2.devmode = NULL;
582         info.info2.secdesc = NULL;
583
584         info_ctr.level = info_level;
585         info_ctr.info.info2 = (struct spoolss_SetPrinterInfo2 *)&info.info2;
586
587         status = rpccli_spoolss_SetPrinter(cli, mem_ctx,
588                                            &pol,
589                                            &info_ctr,
590                                            &devmode_ctr,
591                                            &secdesc_ctr,
592                                            0, /* command */
593                                            &result);
594         if (W_ERROR_IS_OK(result))
595                 printf("Success in setting printername.\n");
596
597  done:
598         if (is_valid_policy_hnd(&pol))
599                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &pol, NULL);
600
601         return result;
602 }
603
604 /****************************************************************************
605 ****************************************************************************/
606
607 static WERROR cmd_spoolss_getprinter(struct rpc_pipe_client *cli,
608                                        TALLOC_CTX *mem_ctx,
609                                        int argc, const char **argv)
610 {
611         struct policy_handle pol;
612         WERROR          result;
613         uint32_t        level = 1;
614         const char      *printername;
615         union spoolss_PrinterInfo info;
616
617         if (argc == 1 || argc > 3) {
618                 printf("Usage: %s <printername> [level]\n", argv[0]);
619                 return WERR_OK;
620         }
621
622         /* Open a printer handle */
623         if (argc == 3) {
624                 level = atoi(argv[2]);
625         }
626
627         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
628
629         /* get a printer handle */
630
631         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
632                                                printername,
633                                                SEC_FLAG_MAXIMUM_ALLOWED,
634                                                &pol);
635         if (!W_ERROR_IS_OK(result)) {
636                 goto done;
637         }
638
639         /* Get printer info */
640
641         result = rpccli_spoolss_getprinter(cli, mem_ctx,
642                                            &pol,
643                                            level,
644                                            0,
645                                            &info);
646         if (!W_ERROR_IS_OK(result)) {
647                 goto done;
648         }
649
650         /* Display printer info */
651         switch (level) {
652         case 0:
653                 display_print_info0(&info.info0);
654                 break;
655         case 1:
656                 display_print_info1(&info.info1);
657                 break;
658         case 2:
659                 display_print_info2(&info.info2);
660                 break;
661         case 3:
662                 display_print_info3(&info.info3);
663                 break;
664         case 4:
665                 display_print_info4(&info.info4);
666                 break;
667         case 5:
668                 display_print_info5(&info.info5);
669                 break;
670         case 6:
671                 display_print_info6(&info.info6);
672                 break;
673         case 7:
674                 display_print_info7(&info.info7);
675                 break;
676         default:
677                 printf("unknown info level %d\n", level);
678                 break;
679         }
680  done:
681         if (is_valid_policy_hnd(&pol)) {
682                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &pol, NULL);
683         }
684
685         return result;
686 }
687
688 /****************************************************************************
689 ****************************************************************************/
690
691 static void display_reg_value(struct regval_blob value)
692 {
693         const char *text = NULL;
694         DATA_BLOB blob;
695
696         switch(value.type) {
697         case REG_DWORD:
698                 printf("%s: REG_DWORD: 0x%08x\n", value.valuename,
699                        *((uint32_t *) value.data_p));
700                 break;
701         case REG_SZ:
702                 blob = data_blob_const(value.data_p, value.size);
703                 pull_reg_sz(talloc_tos(), &blob, &text);
704                 printf("%s: REG_SZ: %s\n", value.valuename, text ? text : "");
705                 break;
706         case REG_BINARY: {
707                 char *hex = hex_encode_talloc(NULL, value.data_p, value.size);
708                 size_t i, len;
709                 printf("%s: REG_BINARY:", value.valuename);
710                 len = strlen(hex);
711                 for (i=0; i<len; i++) {
712                         if (hex[i] == '\0') {
713                                 break;
714                         }
715                         if (i%40 == 0) {
716                                 putchar('\n');
717                         }
718                         putchar(hex[i]);
719                 }
720                 TALLOC_FREE(hex);
721                 putchar('\n');
722                 break;
723         }
724         case REG_MULTI_SZ: {
725                 uint32_t i;
726                 const char **values;
727                 blob = data_blob_const(value.data_p, value.size);
728
729                 if (!pull_reg_multi_sz(NULL, &blob, &values)) {
730                         d_printf("pull_reg_multi_sz failed\n");
731                         break;
732                 }
733
734                 printf("%s: REG_MULTI_SZ: \n", value.valuename);
735                 for (i=0; values[i] != NULL; i++) {
736                         d_printf("%s\n", values[i]);
737                 }
738                 TALLOC_FREE(values);
739                 break;
740         }
741         default:
742                 printf("%s: unknown type %d\n", value.valuename, value.type);
743         }
744
745 }
746
747 /****************************************************************************
748 ****************************************************************************/
749
750 static void display_printer_data(const char *v,
751                                  enum winreg_Type type,
752                                  union spoolss_PrinterData *r)
753 {
754         int i;
755
756         switch (type) {
757         case REG_DWORD:
758                 printf("%s: REG_DWORD: 0x%08x\n", v, r->value);
759                 break;
760         case REG_SZ:
761                 printf("%s: REG_SZ: %s\n", v, r->string);
762                 break;
763         case REG_BINARY: {
764                 char *hex = hex_encode_talloc(NULL,
765                         r->binary.data, r->binary.length);
766                 size_t len;
767                 printf("%s: REG_BINARY:", v);
768                 len = strlen(hex);
769                 for (i=0; i<len; i++) {
770                         if (hex[i] == '\0') {
771                                 break;
772                         }
773                         if (i%40 == 0) {
774                                 putchar('\n');
775                         }
776                         putchar(hex[i]);
777                 }
778                 TALLOC_FREE(hex);
779                 putchar('\n');
780                 break;
781         }
782         case REG_MULTI_SZ:
783                 printf("%s: REG_MULTI_SZ: ", v);
784                 for (i=0; r->string_array[i] != NULL; i++) {
785                         printf("%s ", r->string_array[i]);
786                 }
787                 printf("\n");
788                 break;
789         default:
790                 printf("%s: unknown type 0x%02x:\n", v, type);
791                 break;
792         }
793 }
794
795 /****************************************************************************
796 ****************************************************************************/
797
798 static WERROR cmd_spoolss_getprinterdata(struct rpc_pipe_client *cli,
799                                            TALLOC_CTX *mem_ctx,
800                                            int argc, const char **argv)
801 {
802         struct policy_handle pol;
803         WERROR          result;
804         fstring         printername;
805         const char *valuename;
806         enum winreg_Type type;
807         union spoolss_PrinterData data;
808
809         if (argc != 3) {
810                 printf("Usage: %s <printername> <valuename>\n", argv[0]);
811                 printf("<printername> of . queries print server\n");
812                 return WERR_OK;
813         }
814         valuename = argv[2];
815
816         /* Open a printer handle */
817
818         if (strncmp(argv[1], ".", sizeof(".")) == 0)
819                 fstrcpy(printername, cli->srv_name_slash);
820         else
821                 slprintf(printername, sizeof(printername)-1, "%s\\%s",
822                           cli->srv_name_slash, argv[1]);
823
824         /* get a printer handle */
825
826         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
827                                                printername,
828                                                SEC_FLAG_MAXIMUM_ALLOWED,
829                                                &pol);
830         if (!W_ERROR_IS_OK(result))
831                 goto done;
832
833         /* Get printer info */
834
835         result = rpccli_spoolss_getprinterdata(cli, mem_ctx,
836                                                &pol,
837                                                valuename,
838                                                0,
839                                                &type,
840                                                &data);
841         if (!W_ERROR_IS_OK(result))
842                 goto done;
843
844         /* Display printer data */
845
846         display_printer_data(valuename, type, &data);
847
848  done:
849         if (is_valid_policy_hnd(&pol))
850                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &pol, NULL);
851
852         return result;
853 }
854
855 /****************************************************************************
856 ****************************************************************************/
857
858 static WERROR cmd_spoolss_getprinterdataex(struct rpc_pipe_client *cli,
859                                              TALLOC_CTX *mem_ctx,
860                                              int argc, const char **argv)
861 {
862         struct policy_handle pol;
863         WERROR          result;
864         NTSTATUS        status;
865         fstring         printername;
866         const char *valuename, *keyname;
867         struct regval_blob value;
868
869         enum winreg_Type type;
870         uint8_t *buffer = NULL;
871         uint32_t offered = 0;
872         uint32_t needed;
873
874         if (argc != 4) {
875                 printf("Usage: %s <printername> <keyname> <valuename>\n",
876                        argv[0]);
877                 printf("<printername> of . queries print server\n");
878                 return WERR_OK;
879         }
880         valuename = argv[3];
881         keyname = argv[2];
882
883         /* Open a printer handle */
884
885         if (strncmp(argv[1], ".", sizeof(".")) == 0)
886                 fstrcpy(printername, cli->srv_name_slash);
887         else
888                 slprintf(printername, sizeof(printername)-1, "%s\\%s",
889                           cli->srv_name_slash, argv[1]);
890
891         /* get a printer handle */
892
893         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
894                                                printername,
895                                                SEC_FLAG_MAXIMUM_ALLOWED,
896                                                &pol);
897         if (!W_ERROR_IS_OK(result))
898                 goto done;
899
900         /* Get printer info */
901
902         status = rpccli_spoolss_GetPrinterDataEx(cli, mem_ctx,
903                                                  &pol,
904                                                  keyname,
905                                                  valuename,
906                                                  &type,
907                                                  buffer,
908                                                  offered,
909                                                  &needed,
910                                                  &result);
911         if (W_ERROR_EQUAL(result, WERR_MORE_DATA)) {
912                 offered = needed;
913                 buffer = talloc_array(mem_ctx, uint8_t, needed);
914                 status = rpccli_spoolss_GetPrinterDataEx(cli, mem_ctx,
915                                                          &pol,
916                                                          keyname,
917                                                          valuename,
918                                                          &type,
919                                                          buffer,
920                                                          offered,
921                                                          &needed,
922                                                          &result);
923         }
924
925         if (!NT_STATUS_IS_OK(status)) {
926                 goto done;
927         }
928
929         if (!W_ERROR_IS_OK(result)) {
930                 goto done;
931         }
932
933
934         if (!W_ERROR_IS_OK(result))
935                 goto done;
936
937         /* Display printer data */
938
939         fstrcpy(value.valuename, valuename);
940         value.type = type;
941         value.size = needed;
942         value.data_p = buffer;
943
944         display_reg_value(value);
945
946  done:
947         if (is_valid_policy_hnd(&pol))
948                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &pol, NULL);
949
950         return result;
951 }
952
953 /****************************************************************************
954 ****************************************************************************/
955
956 static void display_print_driver1(struct spoolss_DriverInfo1 *r)
957 {
958         if (!r) {
959                 return;
960         }
961
962         printf("Printer Driver Info 1:\n");
963         printf("\tDriver Name: [%s]\n", r->driver_name);
964         printf("\n");
965 }
966
967 /****************************************************************************
968 ****************************************************************************/
969
970 static void display_print_driver2(struct spoolss_DriverInfo2 *r)
971 {
972         if (!r) {
973                 return;
974         }
975
976         printf("Printer Driver Info 2:\n");
977         printf("\tVersion: [%x]\n", r->version);
978         printf("\tDriver Name: [%s]\n", r->driver_name);
979         printf("\tArchitecture: [%s]\n", r->architecture);
980         printf("\tDriver Path: [%s]\n", r->driver_path);
981         printf("\tDatafile: [%s]\n", r->data_file);
982         printf("\tConfigfile: [%s]\n", r->config_file);
983         printf("\n");
984 }
985
986 /****************************************************************************
987 ****************************************************************************/
988
989 static void display_print_driver3(struct spoolss_DriverInfo3 *r)
990 {
991         int i;
992
993         if (!r) {
994                 return;
995         }
996
997         printf("Printer Driver Info 3:\n");
998         printf("\tVersion: [%x]\n", r->version);
999         printf("\tDriver Name: [%s]\n", r->driver_name);
1000         printf("\tArchitecture: [%s]\n", r->architecture);
1001         printf("\tDriver Path: [%s]\n", r->driver_path);
1002         printf("\tDatafile: [%s]\n", r->data_file);
1003         printf("\tConfigfile: [%s]\n", r->config_file);
1004         printf("\tHelpfile: [%s]\n", r->help_file);
1005
1006         for (i=0; r->dependent_files && r->dependent_files[i] != NULL; i++) {
1007                 printf("\tDependentfiles: [%s]\n", r->dependent_files[i]);
1008         }
1009
1010         printf("\tMonitorname: [%s]\n", r->monitor_name);
1011         printf("\tDefaultdatatype: [%s]\n", r->default_datatype);
1012         printf("\n");
1013 }
1014
1015 /****************************************************************************
1016 ****************************************************************************/
1017
1018 static void display_print_driver4(struct spoolss_DriverInfo4 *r)
1019 {
1020         int i;
1021
1022         if (!r) {
1023                 return;
1024         }
1025
1026         printf("Printer Driver Info 4:\n");
1027         printf("\tVersion: [%x]\n", r->version);
1028         printf("\tDriver Name: [%s]\n", r->driver_name);
1029         printf("\tArchitecture: [%s]\n", r->architecture);
1030         printf("\tDriver Path: [%s]\n", r->driver_path);
1031         printf("\tDatafile: [%s]\n", r->data_file);
1032         printf("\tConfigfile: [%s]\n", r->config_file);
1033         printf("\tHelpfile: [%s]\n", r->help_file);
1034
1035         for (i=0; r->dependent_files && r->dependent_files[i] != NULL; i++) {
1036                 printf("\tDependentfiles: [%s]\n", r->dependent_files[i]);
1037         }
1038
1039         printf("\tMonitorname: [%s]\n", r->monitor_name);
1040         printf("\tDefaultdatatype: [%s]\n", r->default_datatype);
1041
1042         for (i=0; r->previous_names && r->previous_names[i] != NULL; i++) {
1043                 printf("\tPrevious Names: [%s]\n", r->previous_names[i]);
1044         }
1045         printf("\n");
1046 }
1047
1048 /****************************************************************************
1049 ****************************************************************************/
1050
1051 static void display_print_driver5(struct spoolss_DriverInfo5 *r)
1052 {
1053         if (!r) {
1054                 return;
1055         }
1056
1057         printf("Printer Driver Info 5:\n");
1058         printf("\tVersion: [%x]\n", r->version);
1059         printf("\tDriver Name: [%s]\n", r->driver_name);
1060         printf("\tArchitecture: [%s]\n", r->architecture);
1061         printf("\tDriver Path: [%s]\n", r->driver_path);
1062         printf("\tDatafile: [%s]\n", r->data_file);
1063         printf("\tConfigfile: [%s]\n", r->config_file);
1064         printf("\tDriver Attributes: [0x%x]\n", r->driver_attributes);
1065         printf("\tConfig Version: [0x%x]\n", r->config_version);
1066         printf("\tDriver Version: [0x%x]\n", r->driver_version);
1067         printf("\n");
1068 }
1069
1070 /****************************************************************************
1071 ****************************************************************************/
1072
1073 static void display_print_driver6(struct spoolss_DriverInfo6 *r)
1074 {
1075         int i;
1076
1077         if (!r) {
1078                 return;
1079         }
1080
1081         printf("Printer Driver Info 6:\n");
1082         printf("\tVersion: [%x]\n", r->version);
1083         printf("\tDriver Name: [%s]\n", r->driver_name);
1084         printf("\tArchitecture: [%s]\n", r->architecture);
1085         printf("\tDriver Path: [%s]\n", r->driver_path);
1086         printf("\tDatafile: [%s]\n", r->data_file);
1087         printf("\tConfigfile: [%s]\n", r->config_file);
1088         printf("\tHelpfile: [%s]\n", r->help_file);
1089
1090         for (i=0; r->dependent_files && r->dependent_files[i] != NULL; i++) {
1091                 printf("\tDependentfiles: [%s]\n", r->dependent_files[i]);
1092         }
1093
1094         printf("\tMonitorname: [%s]\n", r->monitor_name);
1095         printf("\tDefaultdatatype: [%s]\n", r->default_datatype);
1096
1097         for (i=0; r->previous_names && r->previous_names[i] != NULL; i++) {
1098                 printf("\tPrevious Names: [%s]\n", r->previous_names[i]);
1099         }
1100
1101         printf("\tDriver Date: [%s]\n", nt_time_string(talloc_tos(), r->driver_date));
1102         printf("\tDriver Version: [0x%016llx]\n", (long long unsigned int)r->driver_version);
1103         printf("\tManufacturer Name: [%s]\n", r->manufacturer_name);
1104         printf("\tManufacturer Url: [%s]\n", r->manufacturer_url);
1105         printf("\tHardware ID: [%s]\n", r->hardware_id);
1106         printf("\tProvider: [%s]\n", r->provider);
1107
1108         printf("\n");
1109 }
1110
1111 /****************************************************************************
1112 ****************************************************************************/
1113
1114 static void display_print_driver8(struct spoolss_DriverInfo8 *r)
1115 {
1116         int i;
1117
1118         if (!r) {
1119                 return;
1120         }
1121
1122         printf("Printer Driver Info 8:\n");
1123         printf("\tVersion: [%x]\n", r->version);
1124         printf("\tDriver Name: [%s]\n", r->driver_name);
1125         printf("\tArchitecture: [%s]\n", r->architecture);
1126         printf("\tDriver Path: [%s]\n", r->driver_path);
1127         printf("\tDatafile: [%s]\n", r->data_file);
1128         printf("\tConfigfile: [%s]\n", r->config_file);
1129         printf("\tHelpfile: [%s]\n", r->help_file);
1130         printf("\tMonitorname: [%s]\n", r->monitor_name);
1131         printf("\tDefaultdatatype: [%s]\n", r->default_datatype);
1132
1133         for (i=0; r->dependent_files && r->dependent_files[i] != NULL; i++) {
1134                 printf("\tDependentfiles: [%s]\n", r->dependent_files[i]);
1135         }
1136
1137         for (i=0; r->previous_names && r->previous_names[i] != NULL; i++) {
1138                 printf("\tPrevious Names: [%s]\n", r->previous_names[i]);
1139         }
1140
1141         printf("\tDriver Date: [%s]\n", nt_time_string(talloc_tos(), r->driver_date));
1142         printf("\tDriver Version: [0x%016llx]\n", (long long unsigned int)r->driver_version);
1143         printf("\tManufacturer Name: [%s]\n", r->manufacturer_name);
1144         printf("\tManufacturer Url: [%s]\n", r->manufacturer_url);
1145         printf("\tHardware ID: [%s]\n", r->hardware_id);
1146         printf("\tProvider: [%s]\n", r->provider);
1147         printf("\tPrint Processor: [%s]\n", r->print_processor);
1148         printf("\tVendor Setup: [%s]\n", r->vendor_setup);
1149         for (i=0; r->color_profiles && r->color_profiles[i] != NULL; i++) {
1150                 printf("\tColor Profiles: [%s]\n", r->color_profiles[i]);
1151         }
1152         printf("\tInf Path: [%s]\n", r->inf_path);
1153         printf("\tPrinter Driver Attributes: [0x%x]\n", r->printer_driver_attributes);
1154         for (i=0; r->core_driver_dependencies && r->core_driver_dependencies[i] != NULL; i++) {
1155                 printf("\tCore Driver Dependencies: [%s]\n", r->core_driver_dependencies[i]);
1156         }
1157         printf("\tMin Driver Inbox Driver Version Date: [%s]\n", nt_time_string(talloc_tos(), r->min_inbox_driver_ver_date));
1158         printf("\tMin Driver Inbox Driver Version Version: [0x%016llx]\n",
1159                 (long long unsigned int)r->min_inbox_driver_ver_version);
1160
1161         printf("\n");
1162 }
1163
1164 /****************************************************************************
1165 ****************************************************************************/
1166
1167 static WERROR cmd_spoolss_getdriver(struct rpc_pipe_client *cli,
1168                                     TALLOC_CTX *mem_ctx,
1169                                     int argc, const char **argv)
1170 {
1171         struct policy_handle pol;
1172         WERROR          werror;
1173         uint32_t        level = 3;
1174         const char      *printername;
1175         uint32_t        i;
1176         bool            success = false;
1177         union spoolss_DriverInfo info;
1178         uint32_t server_major_version;
1179         uint32_t server_minor_version;
1180
1181         if ((argc == 1) || (argc > 3)) {
1182                 printf("Usage: %s <printername> [level]\n", argv[0]);
1183                 return WERR_OK;
1184         }
1185
1186         /* get the arguments need to open the printer handle */
1187
1188         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
1189
1190         if (argc == 3) {
1191                 level = atoi(argv[2]);
1192         }
1193
1194         /* Open a printer handle */
1195
1196         werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
1197                                                printername,
1198                                                PRINTER_ACCESS_USE,
1199                                                &pol);
1200         if (!W_ERROR_IS_OK(werror)) {
1201                 printf("Error opening printer handle for %s!\n", printername);
1202                 return werror;
1203         }
1204
1205         /* loop through and print driver info level for each architecture */
1206
1207         for (i=0; archi_table[i].long_archi!=NULL; i++) {
1208
1209                 werror = rpccli_spoolss_getprinterdriver2(cli, mem_ctx,
1210                                                           &pol,
1211                                                           archi_table[i].long_archi,
1212                                                           level,
1213                                                           0, /* offered */
1214                                                           archi_table[i].version,
1215                                                           2,
1216                                                           &info,
1217                                                           &server_major_version,
1218                                                           &server_minor_version);
1219                 if (!W_ERROR_IS_OK(werror)) {
1220                         continue;
1221                 }
1222
1223                 /* need at least one success */
1224
1225                 success = true;
1226
1227                 printf("\n[%s]\n", archi_table[i].long_archi);
1228
1229                 switch (level) {
1230                 case 1:
1231                         display_print_driver1(&info.info1);
1232                         break;
1233                 case 2:
1234                         display_print_driver2(&info.info2);
1235                         break;
1236                 case 3:
1237                         display_print_driver3(&info.info3);
1238                         break;
1239                 case 4:
1240                         display_print_driver4(&info.info4);
1241                         break;
1242                 case 5:
1243                         display_print_driver5(&info.info5);
1244                         break;
1245                 case 6:
1246                         display_print_driver6(&info.info6);
1247                         break;
1248                 case 8:
1249                         display_print_driver8(&info.info8);
1250                         break;
1251                 default:
1252                         printf("unknown info level %d\n", level);
1253                         break;
1254                 }
1255         }
1256
1257         /* Cleanup */
1258
1259         if (is_valid_policy_hnd(&pol)) {
1260                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &pol, NULL);
1261         }
1262
1263         if (success) {
1264                 werror = WERR_OK;
1265         }
1266
1267         return werror;
1268 }
1269
1270 /****************************************************************************
1271 ****************************************************************************/
1272
1273 static WERROR enum_driver_by_architecture(struct rpc_pipe_client *cli,
1274                                           TALLOC_CTX *mem_ctx,
1275                                           const char *architecture,
1276                                           uint32_t level)
1277 {
1278         WERROR werror;
1279         uint32_t count = 0;
1280         union spoolss_DriverInfo *info = NULL;
1281         uint32_t j;
1282
1283         werror = rpccli_spoolss_enumprinterdrivers(cli, mem_ctx,
1284                                                    cli->srv_name_slash,
1285                                                    architecture,
1286                                                    level,
1287                                                    0,
1288                                                    &count,
1289                                                    &info);
1290
1291         if (W_ERROR_EQUAL(werror, WERR_INVALID_ENVIRONMENT)) {
1292                 printf("Server does not support environment [%s]\n",
1293                         architecture);
1294                 return WERR_OK;
1295         }
1296
1297         if (count == 0) {
1298                 return WERR_OK;
1299         }
1300
1301         if (!W_ERROR_IS_OK(werror)) {
1302                 printf("Error getting driver for environment [%s] - %s\n",
1303                         architecture, win_errstr(werror));
1304                 return werror;
1305         }
1306
1307         printf("\n[%s]\n", architecture);
1308
1309         switch (level) {
1310         case 1:
1311                 for (j=0; j < count; j++) {
1312                         display_print_driver1(&info[j].info1);
1313                 }
1314                 break;
1315         case 2:
1316                 for (j=0; j < count; j++) {
1317                         display_print_driver2(&info[j].info2);
1318                 }
1319                 break;
1320         case 3:
1321                 for (j=0; j < count; j++) {
1322                         display_print_driver3(&info[j].info3);
1323                 }
1324                 break;
1325         case 4:
1326                 for (j=0; j < count; j++) {
1327                         display_print_driver4(&info[j].info4);
1328                 }
1329                 break;
1330         case 5:
1331                 for (j=0; j < count; j++) {
1332                         display_print_driver5(&info[j].info5);
1333                 }
1334                 break;
1335         case 6:
1336                 for (j=0; j < count; j++) {
1337                         display_print_driver6(&info[j].info6);
1338                 }
1339                 break;
1340         case 8:
1341                 for (j=0; j < count; j++) {
1342                         display_print_driver8(&info[j].info8);
1343                 }
1344                 break;
1345         default:
1346                 printf("unknown info level %d\n", level);
1347                 return WERR_UNKNOWN_LEVEL;
1348         }
1349
1350         return werror;
1351 }
1352
1353 static WERROR cmd_spoolss_enum_drivers(struct rpc_pipe_client *cli,
1354                                          TALLOC_CTX *mem_ctx,
1355                                          int argc, const char **argv)
1356 {
1357         WERROR werror = WERR_OK;
1358         uint32_t        level = 1;
1359         uint32_t        i;
1360         const char *architecture = NULL;
1361
1362         if (argc > 3) {
1363                 printf("Usage: enumdrivers [level] [architecture]\n");
1364                 return WERR_OK;
1365         }
1366
1367         if (argc >= 2) {
1368                 level = atoi(argv[1]);
1369         }
1370
1371         if (argc == 3) {
1372                 architecture = argv[2];
1373         }
1374
1375         if (architecture) {
1376                 return enum_driver_by_architecture(cli, mem_ctx,
1377                                                    architecture,
1378                                                    level);
1379         }
1380
1381         /* loop through and print driver info level for each architecture */
1382         for (i=0; archi_table[i].long_archi!=NULL; i++) {
1383                 /* check to see if we already asked for this architecture string */
1384
1385                 if (i>0 && strequal(archi_table[i].long_archi, archi_table[i-1].long_archi)) {
1386                         continue;
1387                 }
1388
1389                 werror = enum_driver_by_architecture(cli, mem_ctx,
1390                                                      archi_table[i].long_archi,
1391                                                      level);
1392                 if (!W_ERROR_IS_OK(werror)) {
1393                         break;
1394                 }
1395         }
1396
1397         return werror;
1398 }
1399
1400 /****************************************************************************
1401 ****************************************************************************/
1402
1403 static void display_printdriverdir_1(struct spoolss_DriverDirectoryInfo1 *r)
1404 {
1405         printf("\tDirectory Name:[%s]\n", r->directory_name);
1406 }
1407
1408 /****************************************************************************
1409 ****************************************************************************/
1410
1411 static WERROR cmd_spoolss_getdriverdir(struct rpc_pipe_client *cli,
1412                                          TALLOC_CTX *mem_ctx,
1413                                          int argc, const char **argv)
1414 {
1415         WERROR result;
1416         NTSTATUS status;
1417         const char *env = SPOOLSS_ARCHITECTURE_NT_X86;
1418         DATA_BLOB buffer;
1419         uint32_t offered;
1420         union spoolss_DriverDirectoryInfo info;
1421         uint32_t needed;
1422
1423         if (argc > 2) {
1424                 printf("Usage: %s [environment]\n", argv[0]);
1425                 return WERR_OK;
1426         }
1427
1428         /* Get the arguments need to open the printer handle */
1429
1430         if (argc == 2) {
1431                 env = argv[1];
1432         }
1433
1434         /* Get the directory.  Only use Info level 1 */
1435
1436         status = rpccli_spoolss_GetPrinterDriverDirectory(cli, mem_ctx,
1437                                                           cli->srv_name_slash,
1438                                                           env,
1439                                                           1,
1440                                                           NULL, /* buffer */
1441                                                           0, /* offered */
1442                                                           NULL, /* info */
1443                                                           &needed,
1444                                                           &result);
1445         if (W_ERROR_EQUAL(result, WERR_INSUFFICIENT_BUFFER)) {
1446                 offered = needed;
1447                 buffer = data_blob_talloc_zero(mem_ctx, needed);
1448
1449                 status = rpccli_spoolss_GetPrinterDriverDirectory(cli, mem_ctx,
1450                                                                   cli->srv_name_slash,
1451                                                                   env,
1452                                                                   1,
1453                                                                   &buffer,
1454                                                                   offered,
1455                                                                   &info,
1456                                                                   &needed,
1457                                                                   &result);
1458         }
1459
1460         if (W_ERROR_IS_OK(result)) {
1461                 display_printdriverdir_1(&info.info1);
1462         }
1463
1464         return result;
1465 }
1466
1467 /****************************************************************************
1468 ****************************************************************************/
1469
1470 static void set_drv_info_3_env(TALLOC_CTX *mem_ctx,
1471                                struct spoolss_AddDriverInfo3 *info,
1472                                const char *arch)
1473 {
1474
1475         int i;
1476
1477         for (i=0; archi_table[i].long_archi != NULL; i++)
1478         {
1479                 if (strcmp(arch, archi_table[i].short_archi) == 0)
1480                 {
1481                         info->version = archi_table[i].version;
1482                         info->architecture = talloc_strdup(mem_ctx, archi_table[i].long_archi);
1483                         break;
1484                 }
1485         }
1486
1487         if (archi_table[i].long_archi == NULL)
1488         {
1489                 DEBUG(0, ("set_drv_info_3_env: Unknown arch [%s]\n", arch));
1490         }
1491
1492         return;
1493 }
1494
1495
1496 /**************************************************************************
1497  wrapper for strtok to get the next parameter from a delimited list.
1498  Needed to handle the empty parameter string denoted by "NULL"
1499  *************************************************************************/
1500
1501 static char *get_driver_3_param(TALLOC_CTX *mem_ctx, char *str,
1502                                 const char *delim, const char **dest,
1503                                 char **saveptr)
1504 {
1505         char    *ptr;
1506
1507         /* get the next token */
1508         ptr = strtok_r(str, delim, saveptr);
1509
1510         /* a string of 'NULL' is used to represent an empty
1511            parameter because two consecutive delimiters
1512            will not return an empty string.  See man strtok(3)
1513            for details */
1514         if (ptr && (StrCaseCmp(ptr, "NULL") == 0)) {
1515                 ptr = NULL;
1516         }
1517
1518         if (dest != NULL) {
1519                 *dest = talloc_strdup(mem_ctx, ptr);
1520         }
1521
1522         return ptr;
1523 }
1524
1525 /********************************************************************************
1526  fill in the members of a spoolss_AddDriverInfo3 struct using a character
1527  string in the form of
1528          <Long Printer Name>:<Driver File Name>:<Data File Name>:\
1529              <Config File Name>:<Help File Name>:<Language Monitor Name>:\
1530              <Default Data Type>:<Comma Separated list of Files>
1531  *******************************************************************************/
1532
1533 static bool init_drv_info_3_members(TALLOC_CTX *mem_ctx, struct spoolss_AddDriverInfo3 *r,
1534                                     char *args)
1535 {
1536         char    *str, *str2;
1537         int count = 0;
1538         char *saveptr = NULL;
1539         struct spoolss_StringArray *deps;
1540         const char **file_array = NULL;
1541         int i;
1542
1543         /* fill in the UNISTR fields */
1544         str = get_driver_3_param(mem_ctx, args, ":", &r->driver_name, &saveptr);
1545         str = get_driver_3_param(mem_ctx, NULL, ":", &r->driver_path, &saveptr);
1546         str = get_driver_3_param(mem_ctx, NULL, ":", &r->data_file, &saveptr);
1547         str = get_driver_3_param(mem_ctx, NULL, ":", &r->config_file, &saveptr);
1548         str = get_driver_3_param(mem_ctx, NULL, ":", &r->help_file, &saveptr);
1549         str = get_driver_3_param(mem_ctx, NULL, ":", &r->monitor_name, &saveptr);
1550         str = get_driver_3_param(mem_ctx, NULL, ":", &r->default_datatype, &saveptr);
1551
1552         /* <Comma Separated List of Dependent Files> */
1553         /* save the beginning of the string */
1554         str2 = get_driver_3_param(mem_ctx, NULL, ":", NULL, &saveptr);
1555         str = str2;
1556
1557         /* begin to strip out each filename */
1558         str = strtok_r(str, ",", &saveptr);
1559
1560         /* no dependent files, we are done */
1561         if (!str) {
1562                 return true;
1563         }
1564
1565         deps = talloc_zero(mem_ctx, struct spoolss_StringArray);
1566         if (!deps) {
1567                 return false;
1568         }
1569
1570         while (str != NULL) {
1571                 add_string_to_array(deps, str, &file_array, &count);
1572                 str = strtok_r(NULL, ",", &saveptr);
1573         }
1574
1575         deps->string = talloc_zero_array(deps, const char *, count + 1);
1576         if (!deps->string) {
1577                 return false;
1578         }
1579
1580         for (i=0; i < count; i++) {
1581                 deps->string[i] = file_array[i];
1582         }
1583
1584         r->dependent_files = deps;
1585
1586         return true;
1587 }
1588
1589 /****************************************************************************
1590 ****************************************************************************/
1591
1592 static WERROR cmd_spoolss_addprinterdriver(struct rpc_pipe_client *cli,
1593                                              TALLOC_CTX *mem_ctx,
1594                                              int argc, const char **argv)
1595 {
1596         WERROR result;
1597         NTSTATUS status;
1598         uint32_t                  level = 3;
1599         struct spoolss_AddDriverInfoCtr info_ctr;
1600         struct spoolss_AddDriverInfo3 info3;
1601         const char              *arch;
1602         char                    *driver_args;
1603
1604         /* parse the command arguments */
1605         if (argc != 3 && argc != 4)
1606         {
1607                 printf ("Usage: %s <Environment> \\\n", argv[0]);
1608                 printf ("\t<Long Printer Name>:<Driver File Name>:<Data File Name>:\\\n");
1609                 printf ("\t<Config File Name>:<Help File Name>:<Language Monitor Name>:\\\n");
1610                 printf ("\t<Default Data Type>:<Comma Separated list of Files> \\\n");
1611                 printf ("\t[version]\n");
1612
1613             return WERR_OK;
1614         }
1615
1616         /* Fill in the spoolss_AddDriverInfo3 struct */
1617         ZERO_STRUCT(info3);
1618
1619         arch = cmd_spoolss_get_short_archi(argv[1]);
1620         if (!arch) {
1621                 printf ("Error Unknown architechture [%s]\n", argv[1]);
1622                 return WERR_INVALID_PARAM;
1623         }
1624
1625         set_drv_info_3_env(mem_ctx, &info3, arch);
1626
1627         driver_args = talloc_strdup( mem_ctx, argv[2] );
1628         if (!init_drv_info_3_members(mem_ctx, &info3, driver_args ))
1629         {
1630                 printf ("Error Invalid parameter list - %s.\n", argv[2]);
1631                 return WERR_INVALID_PARAM;
1632         }
1633
1634         /* if printer driver version specified, override the default version
1635          * used by the architecture.  This allows installation of Windows
1636          * 2000 (version 3) printer drivers. */
1637         if (argc == 4)
1638         {
1639                 info3.version = atoi(argv[3]);
1640         }
1641
1642
1643         info_ctr.level          = level;
1644         info_ctr.info.info3     = &info3;
1645
1646         status = rpccli_spoolss_AddPrinterDriver(cli, mem_ctx,
1647                                                  cli->srv_name_slash,
1648                                                  &info_ctr,
1649                                                  &result);
1650         if (!NT_STATUS_IS_OK(status)) {
1651                 return ntstatus_to_werror(status);
1652         }
1653         if (W_ERROR_IS_OK(result)) {
1654                 printf ("Printer Driver %s successfully installed.\n",
1655                         info3.driver_name);
1656         }
1657
1658         return result;
1659 }
1660
1661
1662 /****************************************************************************
1663 ****************************************************************************/
1664
1665 static WERROR cmd_spoolss_addprinterex(struct rpc_pipe_client *cli,
1666                                          TALLOC_CTX *mem_ctx,
1667                                          int argc, const char **argv)
1668 {
1669         WERROR result;
1670         struct spoolss_SetPrinterInfoCtr info_ctr;
1671         struct spoolss_SetPrinterInfo2 info2;
1672
1673         /* parse the command arguments */
1674         if (argc != 5)
1675         {
1676                 printf ("Usage: %s <name> <shared name> <driver> <port>\n", argv[0]);
1677                 return WERR_OK;
1678         }
1679
1680         /* Fill in the DRIVER_INFO_2 struct */
1681         ZERO_STRUCT(info2);
1682
1683         info2.printername       = argv[1];
1684         info2.drivername        = argv[3];
1685         info2.sharename         = argv[2];
1686         info2.portname          = argv[4];
1687         info2.comment           = "Created by rpcclient";
1688         info2.printprocessor    = "winprint";
1689         info2.datatype          = "RAW";
1690         info2.devmode           = NULL;
1691         info2.secdesc           = NULL;
1692         info2.attributes        = PRINTER_ATTRIBUTE_SHARED;
1693         info2.priority          = 0;
1694         info2.defaultpriority   = 0;
1695         info2.starttime         = 0;
1696         info2.untiltime         = 0;
1697
1698         /* These three fields must not be used by AddPrinter()
1699            as defined in the MS Platform SDK documentation..
1700            --jerry
1701         info2.status            = 0;
1702         info2.cjobs             = 0;
1703         info2.averageppm        = 0;
1704         */
1705
1706         info_ctr.level = 2;
1707         info_ctr.info.info2 = &info2;
1708
1709         result = rpccli_spoolss_addprinterex(cli, mem_ctx,
1710                                              &info_ctr);
1711         if (W_ERROR_IS_OK(result))
1712                 printf ("Printer %s successfully installed.\n", argv[1]);
1713
1714         return result;
1715 }
1716
1717 /****************************************************************************
1718 ****************************************************************************/
1719
1720 static WERROR cmd_spoolss_setdriver(struct rpc_pipe_client *cli,
1721                                       TALLOC_CTX *mem_ctx,
1722                                       int argc, const char **argv)
1723 {
1724         struct policy_handle    pol;
1725         WERROR                  result;
1726         NTSTATUS                status;
1727         uint32_t                level = 2;
1728         const char              *printername;
1729         union spoolss_PrinterInfo info;
1730         struct spoolss_SetPrinterInfoCtr info_ctr;
1731         struct spoolss_DevmodeContainer devmode_ctr;
1732         struct sec_desc_buf secdesc_ctr;
1733
1734         ZERO_STRUCT(devmode_ctr);
1735         ZERO_STRUCT(secdesc_ctr);
1736
1737         /* parse the command arguments */
1738         if (argc != 3)
1739         {
1740                 printf ("Usage: %s <printer> <driver>\n", argv[0]);
1741                 return WERR_OK;
1742         }
1743
1744         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
1745
1746         /* Get a printer handle */
1747
1748         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
1749                                                printername,
1750                                                PRINTER_ALL_ACCESS,
1751                                                &pol);
1752         if (!W_ERROR_IS_OK(result))
1753                 goto done;
1754
1755         /* Get printer info */
1756
1757         result = rpccli_spoolss_getprinter(cli, mem_ctx,
1758                                            &pol,
1759                                            level,
1760                                            0,
1761                                            &info);
1762         if (!W_ERROR_IS_OK(result)) {
1763                 printf ("Unable to retrieve printer information!\n");
1764                 goto done;
1765         }
1766
1767         /* Set the printer driver */
1768
1769         info.info2.drivername = argv[2];
1770         info.info2.devmode = NULL;
1771         info.info2.secdesc = NULL;
1772
1773         info_ctr.level = 2;
1774         info_ctr.info.info2 = (struct spoolss_SetPrinterInfo2 *)&info.info2;
1775
1776         status = rpccli_spoolss_SetPrinter(cli, mem_ctx,
1777                                            &pol,
1778                                            &info_ctr,
1779                                            &devmode_ctr,
1780                                            &secdesc_ctr,
1781                                            0, /* command */
1782                                            &result);
1783         if (!W_ERROR_IS_OK(result)) {
1784                 printf("SetPrinter call failed!\n");
1785                 goto done;;
1786         }
1787
1788         printf("Successfully set %s to driver %s.\n", argv[1], argv[2]);
1789
1790 done:
1791         /* Cleanup */
1792
1793         if (is_valid_policy_hnd(&pol))
1794                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &pol, NULL);
1795
1796         return result;
1797 }
1798
1799
1800 /****************************************************************************
1801 ****************************************************************************/
1802
1803 static WERROR cmd_spoolss_deletedriverex(struct rpc_pipe_client *cli,
1804                                          TALLOC_CTX *mem_ctx,
1805                                          int argc, const char **argv)
1806 {
1807         WERROR result, ret = WERR_UNKNOWN_PRINTER_DRIVER;
1808         NTSTATUS status;
1809
1810         int   i;
1811         int vers = -1;
1812
1813         const char *arch = NULL;
1814         uint32_t delete_flags = 0;
1815
1816         /* parse the command arguments */
1817         if (argc < 2 || argc > 4) {
1818                 printf ("Usage: %s <driver> [arch] [version]\n", argv[0]);
1819                 return WERR_OK;
1820         }
1821
1822         if (argc >= 3)
1823                 arch = argv[2];
1824         if (argc == 4)
1825                 vers = atoi (argv[3]);
1826
1827         if (vers >= 0) {
1828                 delete_flags |= DPD_DELETE_SPECIFIC_VERSION;
1829         }
1830
1831         /* delete the driver for all architectures */
1832         for (i=0; archi_table[i].long_archi; i++) {
1833
1834                 if (arch &&  !strequal( archi_table[i].long_archi, arch))
1835                         continue;
1836
1837                 if (vers >= 0 && archi_table[i].version != vers)
1838                         continue;
1839
1840                 /* make the call to remove the driver */
1841                 status = rpccli_spoolss_DeletePrinterDriverEx(cli, mem_ctx,
1842                                                               cli->srv_name_slash,
1843                                                               archi_table[i].long_archi,
1844                                                               argv[1],
1845                                                               delete_flags,
1846                                                               archi_table[i].version,
1847                                                               &result);
1848
1849                 if ( !W_ERROR_IS_OK(result) )
1850                 {
1851                         if ( !W_ERROR_EQUAL(result, WERR_UNKNOWN_PRINTER_DRIVER) ) {
1852                                 printf ("Failed to remove driver %s for arch [%s] (version: %d): %s\n",
1853                                         argv[1], archi_table[i].long_archi, archi_table[i].version, win_errstr(result));
1854                         }
1855                 }
1856                 else
1857                 {
1858                         printf ("Driver %s and files removed for arch [%s] (version: %d).\n", argv[1],
1859                         archi_table[i].long_archi, archi_table[i].version);
1860                         ret = WERR_OK;
1861                 }
1862         }
1863
1864         return ret;
1865 }
1866
1867
1868 /****************************************************************************
1869 ****************************************************************************/
1870
1871 static WERROR cmd_spoolss_deletedriver(struct rpc_pipe_client *cli,
1872                                          TALLOC_CTX *mem_ctx,
1873                                          int argc, const char **argv)
1874 {
1875         WERROR result = WERR_OK;
1876         NTSTATUS status;
1877         int                     i;
1878
1879         /* parse the command arguments */
1880         if (argc != 2) {
1881                 printf ("Usage: %s <driver>\n", argv[0]);
1882                 return WERR_OK;
1883         }
1884
1885         /* delete the driver for all architectures */
1886         for (i=0; archi_table[i].long_archi; i++) {
1887                 /* make the call to remove the driver */
1888                 status = rpccli_spoolss_DeletePrinterDriver(cli, mem_ctx,
1889                                                             cli->srv_name_slash,
1890                                                             archi_table[i].long_archi,
1891                                                             argv[1],
1892                                                             &result);
1893                 if (!NT_STATUS_IS_OK(status)) {
1894                         return result;
1895                 }
1896                 if ( !W_ERROR_IS_OK(result) ) {
1897                         if ( !W_ERROR_EQUAL(result, WERR_UNKNOWN_PRINTER_DRIVER) ) {
1898                                 printf ("Failed to remove driver %s for arch [%s] - error 0x%x!\n",
1899                                         argv[1], archi_table[i].long_archi,
1900                                         W_ERROR_V(result));
1901                         }
1902                 } else {
1903                         printf ("Driver %s removed for arch [%s].\n", argv[1],
1904                                 archi_table[i].long_archi);
1905                 }
1906         }
1907
1908         return result;
1909 }
1910
1911 /****************************************************************************
1912 ****************************************************************************/
1913
1914 static WERROR cmd_spoolss_getprintprocdir(struct rpc_pipe_client *cli,
1915                                             TALLOC_CTX *mem_ctx,
1916                                             int argc, const char **argv)
1917 {
1918         WERROR result;
1919         NTSTATUS status;
1920         const char *environment = SPOOLSS_ARCHITECTURE_NT_X86;
1921         DATA_BLOB buffer;
1922         uint32_t offered;
1923         union spoolss_PrintProcessorDirectoryInfo info;
1924         uint32_t needed;
1925
1926         /* parse the command arguments */
1927         if (argc > 2) {
1928                 printf ("Usage: %s [environment]\n", argv[0]);
1929                 return WERR_OK;
1930         }
1931
1932         if (argc == 2) {
1933                 environment = argv[1];
1934         }
1935
1936         status = rpccli_spoolss_GetPrintProcessorDirectory(cli, mem_ctx,
1937                                                            cli->srv_name_slash,
1938                                                            environment,
1939                                                            1,
1940                                                            NULL, /* buffer */
1941                                                            0, /* offered */
1942                                                            NULL, /* info */
1943                                                            &needed,
1944                                                            &result);
1945         if (W_ERROR_EQUAL(result, WERR_INSUFFICIENT_BUFFER)) {
1946                 offered = needed;
1947                 buffer = data_blob_talloc_zero(mem_ctx, needed);
1948
1949                 status = rpccli_spoolss_GetPrintProcessorDirectory(cli, mem_ctx,
1950                                                                    cli->srv_name_slash,
1951                                                                    environment,
1952                                                                    1,
1953                                                                    &buffer,
1954                                                                    offered,
1955                                                                    &info,
1956                                                                    &needed,
1957                                                                    &result);
1958         }
1959
1960         if (W_ERROR_IS_OK(result)) {
1961                 printf("%s\n", info.info1.directory_name);
1962         }
1963
1964         return result;
1965 }
1966
1967 /****************************************************************************
1968 ****************************************************************************/
1969
1970 static WERROR cmd_spoolss_addform(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
1971                                     int argc, const char **argv)
1972 {
1973         struct policy_handle handle;
1974         WERROR werror;
1975         NTSTATUS status;
1976         const char *printername;
1977         union spoolss_AddFormInfo info;
1978         struct spoolss_AddFormInfo1 info1;
1979         struct spoolss_AddFormInfo2 info2;
1980         uint32_t level = 1;
1981
1982         /* Parse the command arguments */
1983
1984         if (argc < 3 || argc > 5) {
1985                 printf ("Usage: %s <printer> <formname> [level]\n", argv[0]);
1986                 return WERR_OK;
1987         }
1988
1989         /* Get a printer handle */
1990
1991         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
1992
1993         werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
1994                                                printername,
1995                                                PRINTER_ALL_ACCESS,
1996                                                &handle);
1997         if (!W_ERROR_IS_OK(werror))
1998                 goto done;
1999
2000         /* Dummy up some values for the form data */
2001
2002         if (argc == 4) {
2003                 level = atoi(argv[3]);
2004         }
2005
2006         switch (level) {
2007         case 1:
2008                 info1.flags             = SPOOLSS_FORM_USER;
2009                 info1.form_name         = argv[2];
2010                 info1.size.width        = 100;
2011                 info1.size.height       = 100;
2012                 info1.area.left         = 0;
2013                 info1.area.top          = 10;
2014                 info1.area.right        = 20;
2015                 info1.area.bottom       = 30;
2016
2017                 info.info1 = &info1;
2018
2019                 break;
2020         case 2:
2021                 info2.flags             = SPOOLSS_FORM_USER;
2022                 info2.form_name         = argv[2];
2023                 info2.size.width        = 100;
2024                 info2.size.height       = 100;
2025                 info2.area.left         = 0;
2026                 info2.area.top          = 10;
2027                 info2.area.right        = 20;
2028                 info2.area.bottom       = 30;
2029                 info2.keyword           = argv[2];
2030                 info2.string_type       = SPOOLSS_FORM_STRING_TYPE_NONE;
2031                 info2.mui_dll           = NULL;
2032                 info2.ressource_id      = 0;
2033                 info2.display_name      = argv[2];
2034                 info2.lang_id           = 0;
2035
2036                 info.info2 = &info2;
2037
2038                 break;
2039         }
2040
2041         /* Add the form */
2042
2043
2044         status = rpccli_spoolss_AddForm(cli, mem_ctx,
2045                                         &handle,
2046                                         level,
2047                                         info,
2048                                         &werror);
2049
2050  done:
2051         if (is_valid_policy_hnd(&handle))
2052                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
2053
2054         return werror;
2055 }
2056
2057 /****************************************************************************
2058 ****************************************************************************/
2059
2060 static WERROR cmd_spoolss_setform(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
2061                                     int argc, const char **argv)
2062 {
2063         struct policy_handle handle;
2064         WERROR werror;
2065         NTSTATUS status;
2066         const char *printername;
2067         union spoolss_AddFormInfo info;
2068         struct spoolss_AddFormInfo1 info1;
2069
2070         /* Parse the command arguments */
2071
2072         if (argc != 3) {
2073                 printf ("Usage: %s <printer> <formname>\n", argv[0]);
2074                 return WERR_OK;
2075         }
2076
2077         /* Get a printer handle */
2078
2079         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2080
2081         werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2082                                                printername,
2083                                                SEC_FLAG_MAXIMUM_ALLOWED,
2084                                                &handle);
2085         if (!W_ERROR_IS_OK(werror))
2086                 goto done;
2087
2088         /* Dummy up some values for the form data */
2089
2090         info1.flags             = SPOOLSS_FORM_PRINTER;
2091         info1.size.width        = 100;
2092         info1.size.height       = 100;
2093         info1.area.left         = 0;
2094         info1.area.top          = 1000;
2095         info1.area.right        = 2000;
2096         info1.area.bottom       = 3000;
2097         info1.form_name         = argv[2];
2098
2099         info.info1 = &info1;
2100
2101         /* Set the form */
2102
2103         status = rpccli_spoolss_SetForm(cli, mem_ctx,
2104                                         &handle,
2105                                         argv[2],
2106                                         1,
2107                                         info,
2108                                         &werror);
2109
2110  done:
2111         if (is_valid_policy_hnd(&handle))
2112                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
2113
2114         return werror;
2115 }
2116
2117 /****************************************************************************
2118 ****************************************************************************/
2119
2120 static const char *get_form_flag(int form_flag)
2121 {
2122         switch (form_flag) {
2123         case SPOOLSS_FORM_USER:
2124                 return "FORM_USER";
2125         case SPOOLSS_FORM_BUILTIN:
2126                 return "FORM_BUILTIN";
2127         case SPOOLSS_FORM_PRINTER:
2128                 return "FORM_PRINTER";
2129         default:
2130                 return "unknown";
2131         }
2132 }
2133
2134 /****************************************************************************
2135 ****************************************************************************/
2136
2137 static void display_form_info1(struct spoolss_FormInfo1 *r)
2138 {
2139         printf("%s\n" \
2140                 "\tflag: %s (%d)\n" \
2141                 "\twidth: %d, length: %d\n" \
2142                 "\tleft: %d, right: %d, top: %d, bottom: %d\n\n",
2143                 r->form_name, get_form_flag(r->flags), r->flags,
2144                 r->size.width, r->size.height,
2145                 r->area.left, r->area.right,
2146                 r->area.top, r->area.bottom);
2147 }
2148
2149 /****************************************************************************
2150 ****************************************************************************/
2151
2152 static void display_form_info2(struct spoolss_FormInfo2 *r)
2153 {
2154         printf("%s\n" \
2155                 "\tflag: %s (%d)\n" \
2156                 "\twidth: %d, length: %d\n" \
2157                 "\tleft: %d, right: %d, top: %d, bottom: %d\n",
2158                 r->form_name, get_form_flag(r->flags), r->flags,
2159                 r->size.width, r->size.height,
2160                 r->area.left, r->area.right,
2161                 r->area.top, r->area.bottom);
2162         printf("\tkeyword: %s\n", r->keyword);
2163         printf("\tstring_type: 0x%08x\n", r->string_type);
2164         printf("\tmui_dll: %s\n", r->mui_dll);
2165         printf("\tressource_id: 0x%08x\n", r->ressource_id);
2166         printf("\tdisplay_name: %s\n", r->display_name);
2167         printf("\tlang_id: %d\n", r->lang_id);
2168         printf("\n");
2169 }
2170
2171 /****************************************************************************
2172 ****************************************************************************/
2173
2174 static WERROR cmd_spoolss_getform(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
2175                                     int argc, const char **argv)
2176 {
2177         struct policy_handle handle;
2178         WERROR werror;
2179         NTSTATUS status;
2180         const char *printername;
2181         DATA_BLOB buffer;
2182         uint32_t offered = 0;
2183         union spoolss_FormInfo info;
2184         uint32_t needed;
2185         uint32_t level = 1;
2186
2187         /* Parse the command arguments */
2188
2189         if (argc < 3 || argc > 5) {
2190                 printf ("Usage: %s <printer> <formname> [level]\n", argv[0]);
2191                 return WERR_OK;
2192         }
2193
2194         /* Get a printer handle */
2195
2196         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2197
2198         werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2199                                                printername,
2200                                                SEC_FLAG_MAXIMUM_ALLOWED,
2201                                                &handle);
2202         if (!W_ERROR_IS_OK(werror))
2203                 goto done;
2204
2205         if (argc == 4) {
2206                 level = atoi(argv[3]);
2207         }
2208
2209         /* Get the form */
2210
2211         status = rpccli_spoolss_GetForm(cli, mem_ctx,
2212                                         &handle,
2213                                         argv[2],
2214                                         level,
2215                                         NULL,
2216                                         offered,
2217                                         &info,
2218                                         &needed,
2219                                         &werror);
2220         if (W_ERROR_EQUAL(werror, WERR_INSUFFICIENT_BUFFER)) {
2221                 buffer = data_blob_talloc_zero(mem_ctx, needed);
2222                 offered = needed;
2223                 status = rpccli_spoolss_GetForm(cli, mem_ctx,
2224                                                 &handle,
2225                                                 argv[2],
2226                                                 level,
2227                                                 &buffer,
2228                                                 offered,
2229                                                 &info,
2230                                                 &needed,
2231                                                 &werror);
2232         }
2233
2234         if (!NT_STATUS_IS_OK(status)) {
2235                 return werror;
2236         }
2237
2238         switch (level) {
2239         case 1:
2240                 display_form_info1(&info.info1);
2241                 break;
2242         case 2:
2243                 display_form_info2(&info.info2);
2244                 break;
2245         }
2246
2247  done:
2248         if (is_valid_policy_hnd(&handle))
2249                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
2250
2251         return werror;
2252 }
2253
2254 /****************************************************************************
2255 ****************************************************************************/
2256
2257 static WERROR cmd_spoolss_deleteform(struct rpc_pipe_client *cli,
2258                                        TALLOC_CTX *mem_ctx, int argc,
2259                                        const char **argv)
2260 {
2261         struct policy_handle handle;
2262         WERROR werror;
2263         NTSTATUS status;
2264         const char *printername;
2265
2266         /* Parse the command arguments */
2267
2268         if (argc != 3) {
2269                 printf ("Usage: %s <printer> <formname>\n", argv[0]);
2270                 return WERR_OK;
2271         }
2272
2273         /* Get a printer handle */
2274
2275         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2276
2277         werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2278                                                printername,
2279                                                SEC_FLAG_MAXIMUM_ALLOWED,
2280                                                &handle);
2281         if (!W_ERROR_IS_OK(werror))
2282                 goto done;
2283
2284         /* Delete the form */
2285
2286         status = rpccli_spoolss_DeleteForm(cli, mem_ctx,
2287                                            &handle,
2288                                            argv[2],
2289                                            &werror);
2290         if (!NT_STATUS_IS_OK(status)) {
2291                 return ntstatus_to_werror(status);
2292         }
2293
2294  done:
2295         if (is_valid_policy_hnd(&handle))
2296                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
2297
2298         return werror;
2299 }
2300
2301 /****************************************************************************
2302 ****************************************************************************/
2303
2304 static WERROR cmd_spoolss_enum_forms(struct rpc_pipe_client *cli,
2305                                        TALLOC_CTX *mem_ctx, int argc,
2306                                        const char **argv)
2307 {
2308         struct policy_handle handle;
2309         WERROR werror;
2310         const char *printername;
2311         uint32_t num_forms, level = 1, i;
2312         union spoolss_FormInfo *forms;
2313
2314         /* Parse the command arguments */
2315
2316         if (argc < 2 || argc > 4) {
2317                 printf ("Usage: %s <printer> [level]\n", argv[0]);
2318                 return WERR_OK;
2319         }
2320
2321         /* Get a printer handle */
2322
2323         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2324
2325         werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2326                                                printername,
2327                                                SEC_FLAG_MAXIMUM_ALLOWED,
2328                                                &handle);
2329         if (!W_ERROR_IS_OK(werror))
2330                 goto done;
2331
2332         if (argc == 3) {
2333                 level = atoi(argv[2]);
2334         }
2335
2336         /* Enumerate forms */
2337
2338         werror = rpccli_spoolss_enumforms(cli, mem_ctx,
2339                                           &handle,
2340                                           level,
2341                                           0,
2342                                           &num_forms,
2343                                           &forms);
2344
2345         if (!W_ERROR_IS_OK(werror))
2346                 goto done;
2347
2348         /* Display output */
2349
2350         for (i = 0; i < num_forms; i++) {
2351                 switch (level) {
2352                 case 1:
2353                         display_form_info1(&forms[i].info1);
2354                         break;
2355                 case 2:
2356                         display_form_info2(&forms[i].info2);
2357                         break;
2358                 }
2359         }
2360
2361  done:
2362         if (is_valid_policy_hnd(&handle))
2363                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
2364
2365         return werror;
2366 }
2367
2368 /****************************************************************************
2369 ****************************************************************************/
2370
2371 static WERROR cmd_spoolss_setprinterdata(struct rpc_pipe_client *cli,
2372                                             TALLOC_CTX *mem_ctx,
2373                                             int argc, const char **argv)
2374 {
2375         WERROR result;
2376         NTSTATUS status;
2377         const char *printername;
2378         struct policy_handle pol;
2379         union spoolss_PrinterInfo info;
2380         enum winreg_Type type;
2381         union spoolss_PrinterData data;
2382
2383         /* parse the command arguments */
2384         if (argc < 5) {
2385                 printf ("Usage: %s <printer> <string|binary|dword|multistring>"
2386                         " <value> <data>\n",
2387                         argv[0]);
2388                 result = WERR_INVALID_PARAM;
2389                 goto done;
2390         }
2391
2392         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2393
2394         type = REG_NONE;
2395
2396         if (strequal(argv[2], "string")) {
2397                 type = REG_SZ;
2398         }
2399
2400         if (strequal(argv[2], "binary")) {
2401                 type = REG_BINARY;
2402         }
2403
2404         if (strequal(argv[2], "dword")) {
2405                 type = REG_DWORD;
2406         }
2407
2408         if (strequal(argv[2], "multistring")) {
2409                 type = REG_MULTI_SZ;
2410         }
2411
2412         if (type == REG_NONE) {
2413                 printf("Unknown data type: %s\n", argv[2]);
2414                 result =  WERR_INVALID_PARAM;
2415                 goto done;
2416         }
2417
2418         /* get a printer handle */
2419
2420         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2421                                                printername,
2422                                                SEC_FLAG_MAXIMUM_ALLOWED,
2423                                                &pol);
2424         if (!W_ERROR_IS_OK(result)) {
2425                 goto done;
2426         }
2427
2428         result = rpccli_spoolss_getprinter(cli, mem_ctx,
2429                                            &pol,
2430                                            0,
2431                                            0,
2432                                            &info);
2433         if (!W_ERROR_IS_OK(result)) {
2434                 goto done;
2435         }
2436
2437         printf("%s\n", current_timestring(mem_ctx, true));
2438         printf("\tchange_id (before set)\t:[0x%x]\n", info.info0.change_id);
2439
2440         /* Set the printer data */
2441
2442         switch (type) {
2443         case REG_SZ:
2444                 data.string = talloc_strdup(mem_ctx, argv[4]);
2445                 W_ERROR_HAVE_NO_MEMORY(data.string);
2446                 break;
2447         case REG_DWORD:
2448                 data.value = strtoul(argv[4], NULL, 10);
2449                 break;
2450         case REG_BINARY:
2451                 data.binary = strhex_to_data_blob(mem_ctx, argv[4]);
2452                 break;
2453         case REG_MULTI_SZ: {
2454                 int i, num_strings;
2455                 const char **strings = NULL;
2456
2457                 for (i=4; i<argc; i++) {
2458                         if (strcmp(argv[i], "NULL") == 0) {
2459                                 argv[i] = "";
2460                         }
2461                         if (!add_string_to_array(mem_ctx, argv[i],
2462                                                  &strings,
2463                                                  &num_strings)) {
2464                                 result = WERR_NOMEM;
2465                                 goto done;
2466                         }
2467                 }
2468                 data.string_array = talloc_zero_array(mem_ctx, const char *, num_strings + 1);
2469                 if (!data.string_array) {
2470                         result = WERR_NOMEM;
2471                         goto done;
2472                 }
2473                 for (i=0; i < num_strings; i++) {
2474                         data.string_array[i] = strings[i];
2475                 }
2476                 break;
2477                 }
2478         default:
2479                 printf("Unknown data type: %s\n", argv[2]);
2480                 result = WERR_INVALID_PARAM;
2481                 goto done;
2482         }
2483
2484         status = rpccli_spoolss_SetPrinterData(cli, mem_ctx,
2485                                                &pol,
2486                                                argv[3], /* value_name */
2487                                                type,
2488                                                data,
2489                                                0, /* autocalculated size */
2490                                                &result);
2491         if (!W_ERROR_IS_OK(result)) {
2492                 printf ("Unable to set [%s=%s]!\n", argv[3], argv[4]);
2493                 goto done;
2494         }
2495         printf("\tSetPrinterData succeeded [%s: %s]\n", argv[3], argv[4]);
2496
2497         result = rpccli_spoolss_getprinter(cli, mem_ctx,
2498                                            &pol,
2499                                            0,
2500                                            0,
2501                                            &info);
2502         if (!W_ERROR_IS_OK(result)) {
2503                 goto done;
2504         }
2505
2506         printf("%s\n", current_timestring(mem_ctx, true));
2507         printf("\tchange_id (after set)\t:[0x%x]\n", info.info0.change_id);
2508
2509 done:
2510         /* cleanup */
2511         if (is_valid_policy_hnd(&pol)) {
2512                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &pol, NULL);
2513         }
2514
2515         return result;
2516 }
2517
2518 /****************************************************************************
2519 ****************************************************************************/
2520
2521 static void display_job_info1(struct spoolss_JobInfo1 *r)
2522 {
2523         printf("%d: jobid[%d]: %s %s %s %d/%d pages\n", r->position, r->job_id,
2524                r->user_name, r->document_name, r->text_status, r->pages_printed,
2525                r->total_pages);
2526 }
2527
2528 /****************************************************************************
2529 ****************************************************************************/
2530
2531 static void display_job_info2(struct spoolss_JobInfo2 *r)
2532 {
2533         printf("%d: jobid[%d]: %s %s %s %d/%d pages, %d bytes\n",
2534                r->position, r->job_id,
2535                r->user_name, r->document_name, r->text_status, r->pages_printed,
2536                r->total_pages, r->size);
2537 }
2538
2539 /****************************************************************************
2540 ****************************************************************************/
2541
2542 static void display_job_info3(struct spoolss_JobInfo3 *r)
2543 {
2544         printf("jobid[%d], next_jobid[%d]\n",
2545                 r->job_id, r->next_job_id);
2546 }
2547
2548 /****************************************************************************
2549 ****************************************************************************/
2550
2551 static void display_job_info4(struct spoolss_JobInfo4 *r)
2552 {
2553         printf("%d: jobid[%d]: %s %s %s %d/%d pages, %d/%d bytes\n",
2554                r->position, r->job_id,
2555                r->user_name, r->document_name, r->text_status, r->pages_printed,
2556                r->total_pages, r->size, r->size_high);
2557 }
2558
2559 /****************************************************************************
2560 ****************************************************************************/
2561
2562 static WERROR cmd_spoolss_enum_jobs(struct rpc_pipe_client *cli,
2563                                       TALLOC_CTX *mem_ctx, int argc,
2564                                       const char **argv)
2565 {
2566         WERROR result;
2567         uint32_t level = 1, count, i;
2568         const char *printername;
2569         struct policy_handle hnd;
2570         union spoolss_JobInfo *info;
2571
2572         if (argc < 2 || argc > 3) {
2573                 printf("Usage: %s printername [level]\n", argv[0]);
2574                 return WERR_OK;
2575         }
2576
2577         if (argc == 3) {
2578                 level = atoi(argv[2]);
2579         }
2580
2581         /* Open printer handle */
2582
2583         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2584
2585         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2586                                                printername,
2587                                                SEC_FLAG_MAXIMUM_ALLOWED,
2588                                                &hnd);
2589         if (!W_ERROR_IS_OK(result))
2590                 goto done;
2591
2592         /* Enumerate ports */
2593
2594         result = rpccli_spoolss_enumjobs(cli, mem_ctx,
2595                                          &hnd,
2596                                          0, /* firstjob */
2597                                          1000, /* numjobs */
2598                                          level,
2599                                          0,
2600                                          &count,
2601                                          &info);
2602         if (!W_ERROR_IS_OK(result)) {
2603                 goto done;
2604         }
2605
2606         for (i = 0; i < count; i++) {
2607                 switch (level) {
2608                 case 1:
2609                         display_job_info1(&info[i].info1);
2610                         break;
2611                 case 2:
2612                         display_job_info2(&info[i].info2);
2613                         break;
2614                 default:
2615                         d_printf("unknown info level %d\n", level);
2616                         break;
2617                 }
2618         }
2619
2620 done:
2621         if (is_valid_policy_hnd(&hnd)) {
2622                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &hnd, NULL);
2623         }
2624
2625         return result;
2626 }
2627
2628 /****************************************************************************
2629 ****************************************************************************/
2630
2631 static WERROR cmd_spoolss_get_job(struct rpc_pipe_client *cli,
2632                                   TALLOC_CTX *mem_ctx, int argc,
2633                                   const char **argv)
2634 {
2635         WERROR result;
2636         const char *printername;
2637         struct policy_handle hnd;
2638         uint32_t job_id;
2639         uint32_t level = 1;
2640         union spoolss_JobInfo info;
2641
2642         if (argc < 3 || argc > 4) {
2643                 printf("Usage: %s printername job_id [level]\n", argv[0]);
2644                 return WERR_OK;
2645         }
2646
2647         job_id = atoi(argv[2]);
2648
2649         if (argc == 4) {
2650                 level = atoi(argv[3]);
2651         }
2652
2653         /* Open printer handle */
2654
2655         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2656
2657         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2658                                                printername,
2659                                                SEC_FLAG_MAXIMUM_ALLOWED,
2660                                                &hnd);
2661         if (!W_ERROR_IS_OK(result)) {
2662                 goto done;
2663         }
2664
2665         /* Enumerate ports */
2666
2667         result = rpccli_spoolss_getjob(cli, mem_ctx,
2668                                        &hnd,
2669                                        job_id,
2670                                        level,
2671                                        0,
2672                                        &info);
2673
2674         if (!W_ERROR_IS_OK(result)) {
2675                 goto done;
2676         }
2677
2678         switch (level) {
2679         case 1:
2680                 display_job_info1(&info.info1);
2681                 break;
2682         case 2:
2683                 display_job_info2(&info.info2);
2684                 break;
2685         case 3:
2686                 display_job_info3(&info.info3);
2687                 break;
2688         case 4:
2689                 display_job_info4(&info.info4);
2690                 break;
2691         default:
2692                 d_printf("unknown info level %d\n", level);
2693                 break;
2694         }
2695
2696 done:
2697         if (is_valid_policy_hnd(&hnd)) {
2698                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &hnd, NULL);
2699         }
2700
2701         return result;
2702 }
2703
2704 /****************************************************************************
2705 ****************************************************************************/
2706
2707 static WERROR cmd_spoolss_set_job(struct rpc_pipe_client *cli,
2708                                   TALLOC_CTX *mem_ctx, int argc,
2709                                   const char **argv)
2710 {
2711         WERROR result;
2712         NTSTATUS status;
2713         const char *printername;
2714         struct policy_handle hnd;
2715         uint32_t job_id;
2716         enum spoolss_JobControl command;
2717
2718         if (argc != 4) {
2719                 printf("Usage: %s printername job_id command\n", argv[0]);
2720                 return WERR_OK;
2721         }
2722
2723         job_id = atoi(argv[2]);
2724         command = atoi(argv[3]);
2725
2726         /* Open printer handle */
2727
2728         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2729
2730         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2731                                                printername,
2732                                                SEC_FLAG_MAXIMUM_ALLOWED,
2733                                                &hnd);
2734         if (!W_ERROR_IS_OK(result)) {
2735                 goto done;
2736         }
2737
2738         /* Set Job */
2739
2740         status = rpccli_spoolss_SetJob(cli, mem_ctx,
2741                                        &hnd,
2742                                        job_id,
2743                                        NULL,
2744                                        command,
2745                                        &result);
2746
2747         if (!W_ERROR_IS_OK(result)) {
2748                 goto done;
2749         }
2750
2751 done:
2752         if (is_valid_policy_hnd(&hnd)) {
2753                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &hnd, NULL);
2754         }
2755
2756         return result;
2757 }
2758
2759 /****************************************************************************
2760 ****************************************************************************/
2761
2762 static WERROR cmd_spoolss_enum_data(struct rpc_pipe_client *cli,
2763                                     TALLOC_CTX *mem_ctx, int argc,
2764                                     const char **argv)
2765 {
2766         WERROR result;
2767         NTSTATUS status;
2768         uint32_t i = 0;
2769         const char *printername;
2770         struct policy_handle hnd;
2771         uint32_t value_offered = 0;
2772         const char *value_name = NULL;
2773         uint32_t value_needed;
2774         enum winreg_Type type;
2775         uint8_t *data = NULL;
2776         uint32_t data_offered = 0;
2777         uint32_t data_needed;
2778
2779         if (argc != 2) {
2780                 printf("Usage: %s printername\n", argv[0]);
2781                 return WERR_OK;
2782         }
2783
2784         /* Open printer handle */
2785
2786         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2787
2788         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2789                                                printername,
2790                                                SEC_FLAG_MAXIMUM_ALLOWED,
2791                                                &hnd);
2792         if (!W_ERROR_IS_OK(result)) {
2793                 goto done;
2794         }
2795
2796         /* Enumerate data */
2797
2798         status = rpccli_spoolss_EnumPrinterData(cli, mem_ctx,
2799                                                 &hnd,
2800                                                 i,
2801                                                 value_name,
2802                                                 value_offered,
2803                                                 &value_needed,
2804                                                 &type,
2805                                                 data,
2806                                                 data_offered,
2807                                                 &data_needed,
2808                                                 &result);
2809
2810         data_offered    = data_needed;
2811         value_offered   = value_needed;
2812         data            = talloc_zero_array(mem_ctx, uint8_t, data_needed);
2813         value_name      = talloc_zero_array(mem_ctx, char, value_needed);
2814
2815         while (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(result)) {
2816
2817                 status = rpccli_spoolss_EnumPrinterData(cli, mem_ctx,
2818                                                         &hnd,
2819                                                         i++,
2820                                                         value_name,
2821                                                         value_offered,
2822                                                         &value_needed,
2823                                                         &type,
2824                                                         data,
2825                                                         data_offered,
2826                                                         &data_needed,
2827                                                         &result);
2828                 if (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(result)) {
2829                         struct regval_blob v;
2830                         fstrcpy(v.valuename, value_name);
2831                         v.type = type;
2832                         v.size = data_offered;
2833                         v.data_p = data;
2834                         display_reg_value(v);
2835                 }
2836         }
2837
2838         if (W_ERROR_V(result) == ERRnomoreitems) {
2839                 result = W_ERROR(ERRsuccess);
2840         }
2841
2842 done:
2843         if (is_valid_policy_hnd(&hnd)) {
2844                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &hnd, NULL);
2845         }
2846
2847         return result;
2848 }
2849
2850 /****************************************************************************
2851 ****************************************************************************/
2852
2853 static WERROR cmd_spoolss_enum_data_ex( struct rpc_pipe_client *cli,
2854                                           TALLOC_CTX *mem_ctx, int argc,
2855                                           const char **argv)
2856 {
2857         WERROR result;
2858         uint32_t i;
2859         const char *printername;
2860         struct policy_handle hnd;
2861         uint32_t count;
2862         struct spoolss_PrinterEnumValues *info;
2863
2864         if (argc != 3) {
2865                 printf("Usage: %s printername <keyname>\n", argv[0]);
2866                 return WERR_OK;
2867         }
2868
2869         /* Open printer handle */
2870
2871         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2872
2873         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2874                                                printername,
2875                                                SEC_FLAG_MAXIMUM_ALLOWED,
2876                                                &hnd);
2877         if (!W_ERROR_IS_OK(result)) {
2878                 goto done;
2879         }
2880
2881         /* Enumerate subkeys */
2882
2883         result = rpccli_spoolss_enumprinterdataex(cli, mem_ctx,
2884                                                   &hnd,
2885                                                   argv[2],
2886                                                   0,
2887                                                   &count,
2888                                                   &info);
2889         if (!W_ERROR_IS_OK(result)) {
2890                 goto done;
2891         }
2892
2893         for (i=0; i < count; i++) {
2894                 display_printer_data(info[i].value_name,
2895                                      info[i].type,
2896                                      info[i].data);
2897         }
2898
2899  done:
2900         if (is_valid_policy_hnd(&hnd)) {
2901                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &hnd, NULL);
2902         }
2903
2904         return result;
2905 }
2906
2907 /****************************************************************************
2908 ****************************************************************************/
2909
2910 static WERROR cmd_spoolss_enum_printerkey(struct rpc_pipe_client *cli,
2911                                           TALLOC_CTX *mem_ctx, int argc,
2912                                           const char **argv)
2913 {
2914         WERROR result;
2915         const char *printername;
2916         const char *keyname = NULL;
2917         struct policy_handle hnd;
2918         const char **key_buffer = NULL;
2919         int i;
2920
2921         if (argc < 2 || argc > 3) {
2922                 printf("Usage: %s printername [keyname]\n", argv[0]);
2923                 return WERR_OK;
2924         }
2925
2926         if (argc == 3) {
2927                 keyname = argv[2];
2928         } else {
2929                 keyname = "";
2930         }
2931
2932         /* Open printer handle */
2933
2934         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2935
2936         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2937                                                printername,
2938                                                SEC_FLAG_MAXIMUM_ALLOWED,
2939                                                &hnd);
2940         if (!W_ERROR_IS_OK(result)) {
2941                 goto done;
2942         }
2943
2944         /* Enumerate subkeys */
2945
2946         result = rpccli_spoolss_enumprinterkey(cli, mem_ctx,
2947                                                &hnd,
2948                                                keyname,
2949                                                &key_buffer,
2950                                                0);
2951
2952         if (!W_ERROR_IS_OK(result)) {
2953                 goto done;
2954         }
2955
2956         for (i=0; key_buffer && key_buffer[i]; i++) {
2957                 printf("%s\n", key_buffer[i]);
2958         }
2959
2960  done:
2961
2962         if (is_valid_policy_hnd(&hnd)) {
2963                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &hnd, NULL);
2964         }
2965
2966         return result;
2967 }
2968
2969 /****************************************************************************
2970 ****************************************************************************/
2971
2972 static WERROR cmd_spoolss_rffpcnex(struct rpc_pipe_client *cli,
2973                                      TALLOC_CTX *mem_ctx, int argc,
2974                                      const char **argv)
2975 {
2976         const char *printername;
2977         const char *clientname;
2978         struct policy_handle hnd;
2979         WERROR result;
2980         NTSTATUS status;
2981         struct spoolss_NotifyOption option;
2982
2983         if (argc != 2) {
2984                 printf("Usage: %s printername\n", argv[0]);
2985                 result = WERR_OK;
2986                 goto done;
2987         }
2988
2989         /* Open printer */
2990
2991         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2992
2993         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2994                                                printername,
2995                                                SEC_FLAG_MAXIMUM_ALLOWED,
2996                                                &hnd);
2997         if (!W_ERROR_IS_OK(result)) {
2998                 printf("Error opening %s\n", argv[1]);
2999                 goto done;
3000         }
3001
3002         /* Create spool options */
3003
3004         option.version = 2;
3005         option.count = 2;
3006
3007         option.types = talloc_array(mem_ctx, struct spoolss_NotifyOptionType, 2);
3008         if (option.types == NULL) {
3009                 result = WERR_NOMEM;
3010                 goto done;
3011         }
3012
3013         option.types[0].type = PRINTER_NOTIFY_TYPE;
3014         option.types[0].count = 1;
3015         option.types[0].fields = talloc_array(mem_ctx, union spoolss_Field, 1);
3016         if (option.types[0].fields == NULL) {
3017                 result = WERR_NOMEM;
3018                 goto done;
3019         }
3020         option.types[0].fields[0].field = PRINTER_NOTIFY_FIELD_SERVER_NAME;
3021
3022         option.types[1].type = JOB_NOTIFY_TYPE;
3023         option.types[1].count = 1;
3024         option.types[1].fields = talloc_array(mem_ctx, union spoolss_Field, 1);
3025         if (option.types[1].fields == NULL) {
3026                 result = WERR_NOMEM;
3027                 goto done;
3028         }
3029         option.types[1].fields[0].field = JOB_NOTIFY_FIELD_PRINTER_NAME;
3030
3031         clientname = talloc_asprintf(mem_ctx, "\\\\%s", global_myname());
3032         if (!clientname) {
3033                 result = WERR_NOMEM;
3034                 goto done;
3035         }
3036
3037         /* Send rffpcnex */
3038
3039         status = rpccli_spoolss_RemoteFindFirstPrinterChangeNotifyEx(cli, mem_ctx,
3040                                                                      &hnd,
3041                                                                      0,
3042                                                                      0,
3043                                                                      clientname,
3044                                                                      123,
3045                                                                      &option,
3046                                                                      &result);
3047         if (!W_ERROR_IS_OK(result)) {
3048                 printf("Error rffpcnex %s\n", argv[1]);
3049                 goto done;
3050         }
3051
3052 done:
3053         if (is_valid_policy_hnd(&hnd))
3054                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &hnd, NULL);
3055
3056         return result;
3057 }
3058
3059 /****************************************************************************
3060 ****************************************************************************/
3061
3062 static bool compare_printer( struct rpc_pipe_client *cli1, struct policy_handle *hnd1,
3063                              struct rpc_pipe_client *cli2, struct policy_handle *hnd2 )
3064 {
3065         union spoolss_PrinterInfo info1, info2;
3066         WERROR werror;
3067         TALLOC_CTX *mem_ctx = talloc_init("compare_printer");
3068
3069         printf("Retrieving printer propertiesfor %s...", cli1->desthost);
3070         werror = rpccli_spoolss_getprinter(cli1, mem_ctx,
3071                                            hnd1,
3072                                            2,
3073                                            0,
3074                                            &info1);
3075         if ( !W_ERROR_IS_OK(werror) ) {
3076                 printf("failed (%s)\n", win_errstr(werror));
3077                 talloc_destroy(mem_ctx);
3078                 return false;
3079         }
3080         printf("ok\n");
3081
3082         printf("Retrieving printer properties for %s...", cli2->desthost);
3083         werror = rpccli_spoolss_getprinter(cli2, mem_ctx,
3084                                            hnd2,
3085                                            2,
3086                                            0,
3087                                            &info2);
3088         if ( !W_ERROR_IS_OK(werror) ) {
3089                 printf("failed (%s)\n", win_errstr(werror));
3090                 talloc_destroy(mem_ctx);
3091                 return false;
3092         }
3093         printf("ok\n");
3094
3095         talloc_destroy(mem_ctx);
3096
3097         return true;
3098 }
3099
3100 /****************************************************************************
3101 ****************************************************************************/
3102
3103 static bool compare_printer_secdesc( struct rpc_pipe_client *cli1, struct policy_handle *hnd1,
3104                                      struct rpc_pipe_client *cli2, struct policy_handle *hnd2 )
3105 {
3106         union spoolss_PrinterInfo info1, info2;
3107         WERROR werror;
3108         TALLOC_CTX *mem_ctx = talloc_init("compare_printer_secdesc");
3109         SEC_DESC *sd1, *sd2;
3110         bool result = true;
3111
3112
3113         printf("Retrieving printer security for %s...", cli1->desthost);
3114         werror = rpccli_spoolss_getprinter(cli1, mem_ctx,
3115                                            hnd1,
3116                                            3,
3117                                            0,
3118                                            &info1);
3119         if ( !W_ERROR_IS_OK(werror) ) {
3120                 printf("failed (%s)\n", win_errstr(werror));
3121                 result = false;
3122                 goto done;
3123         }
3124         printf("ok\n");
3125
3126         printf("Retrieving printer security for %s...", cli2->desthost);
3127         werror = rpccli_spoolss_getprinter(cli2, mem_ctx,
3128                                            hnd2,
3129                                            3,
3130                                            0,
3131                                            &info2);
3132         if ( !W_ERROR_IS_OK(werror) ) {
3133                 printf("failed (%s)\n", win_errstr(werror));
3134                 result = false;
3135                 goto done;
3136         }
3137         printf("ok\n");
3138
3139
3140         printf("++ ");
3141
3142         sd1 = info1.info3.secdesc;
3143         sd2 = info2.info3.secdesc;
3144
3145         if ( (sd1 != sd2) && ( !sd1 || !sd2 ) ) {
3146                 printf("NULL secdesc!\n");
3147                 result = false;
3148                 goto done;
3149         }
3150
3151         if (!security_descriptor_equal( sd1, sd2 ) ) {
3152                 printf("Security Descriptors *not* equal!\n");
3153                 result = false;
3154                 goto done;
3155         }
3156
3157         printf("Security descriptors match\n");
3158
3159 done:
3160         talloc_destroy(mem_ctx);
3161         return result;
3162 }
3163
3164
3165 /****************************************************************************
3166 ****************************************************************************/
3167
3168 extern struct user_auth_info *rpcclient_auth_info;
3169
3170 static WERROR cmd_spoolss_printercmp(struct rpc_pipe_client *cli,
3171                                      TALLOC_CTX *mem_ctx, int argc,
3172                                      const char **argv)
3173 {
3174         const char *printername;
3175         char *printername_path = NULL;
3176         struct cli_state *cli_server2 = NULL;
3177         struct rpc_pipe_client *cli2 = NULL;
3178         struct policy_handle hPrinter1, hPrinter2;
3179         NTSTATUS nt_status;
3180         WERROR werror;
3181
3182         if ( argc != 3 )  {
3183                 printf("Usage: %s <printer> <server>\n", argv[0]);
3184                 return WERR_OK;
3185         }
3186
3187         printername = argv[1];
3188
3189         /* first get the connection to the remote server */
3190
3191         nt_status = cli_full_connection(&cli_server2, global_myname(), argv[2],
3192                                         NULL, 0,
3193                                         "IPC$", "IPC",
3194                                         get_cmdline_auth_info_username(rpcclient_auth_info),
3195                                         lp_workgroup(),
3196                                         get_cmdline_auth_info_password(rpcclient_auth_info),
3197                                         get_cmdline_auth_info_use_kerberos(rpcclient_auth_info) ? CLI_FULL_CONNECTION_USE_KERBEROS : 0,
3198                                         get_cmdline_auth_info_signing_state(rpcclient_auth_info), NULL);
3199
3200         if ( !NT_STATUS_IS_OK(nt_status) )
3201                 return WERR_GENERAL_FAILURE;
3202
3203         nt_status = cli_rpc_pipe_open_noauth(cli_server2, &ndr_table_spoolss.syntax_id,
3204                                              &cli2);
3205         if (!NT_STATUS_IS_OK(nt_status)) {
3206                 printf("failed to open spoolss pipe on server %s (%s)\n",
3207                         argv[2], nt_errstr(nt_status));
3208                 return WERR_GENERAL_FAILURE;
3209         }
3210
3211         /* now open up both printers */
3212
3213         RPCCLIENT_PRINTERNAME(printername_path, cli, printername);
3214
3215         printf("Opening %s...", printername_path);
3216
3217         werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
3218                                                printername_path,
3219                                                PRINTER_ALL_ACCESS,
3220                                                &hPrinter1);
3221         if ( !W_ERROR_IS_OK(werror) ) {
3222                 printf("failed (%s)\n", win_errstr(werror));
3223                 goto done;
3224         }
3225         printf("ok\n");
3226
3227         RPCCLIENT_PRINTERNAME(printername_path, cli2, printername);
3228
3229         printf("Opening %s...", printername_path);
3230         werror = rpccli_spoolss_openprinter_ex(cli2, mem_ctx,
3231                                                printername_path,
3232                                                PRINTER_ALL_ACCESS,
3233                                                &hPrinter2);
3234         if ( !W_ERROR_IS_OK(werror) ) {
3235                  printf("failed (%s)\n", win_errstr(werror));
3236                 goto done;
3237         }
3238         printf("ok\n");
3239
3240         compare_printer( cli, &hPrinter1, cli2, &hPrinter2 );
3241         compare_printer_secdesc( cli, &hPrinter1, cli2, &hPrinter2 );
3242 #if 0
3243         compare_printerdata( cli_server1, &hPrinter1, cli_server2, &hPrinter2 );
3244 #endif
3245
3246
3247 done:
3248         /* cleanup */
3249
3250         printf("Closing printers...");
3251         rpccli_spoolss_ClosePrinter( cli, mem_ctx, &hPrinter1, NULL );
3252         rpccli_spoolss_ClosePrinter( cli2, mem_ctx, &hPrinter2, NULL );
3253         printf("ok\n");
3254
3255         /* close the second remote connection */
3256
3257         cli_shutdown( cli_server2 );
3258         return WERR_OK;
3259 }
3260
3261 static void display_proc_info1(struct spoolss_PrintProcessorInfo1 *r)
3262 {
3263         printf("print_processor_name: %s\n", r->print_processor_name);
3264 }
3265
3266 static WERROR cmd_spoolss_enum_procs(struct rpc_pipe_client *cli,
3267                                      TALLOC_CTX *mem_ctx, int argc,
3268                                      const char **argv)
3269 {
3270         WERROR werror;
3271         const char *environment = SPOOLSS_ARCHITECTURE_NT_X86;
3272         uint32_t num_procs, level = 1, i;
3273         union spoolss_PrintProcessorInfo *procs;
3274
3275         /* Parse the command arguments */
3276
3277         if (argc < 1 || argc > 4) {
3278                 printf ("Usage: %s [environment] [level]\n", argv[0]);
3279                 return WERR_OK;
3280         }
3281
3282         if (argc >= 2) {
3283                 environment = argv[1];
3284         }
3285
3286         if (argc == 3) {
3287                 level = atoi(argv[2]);
3288         }
3289
3290         /* Enumerate Print Processors */
3291
3292         werror = rpccli_spoolss_enumprintprocessors(cli, mem_ctx,
3293                                                     cli->srv_name_slash,
3294                                                     environment,
3295                                                     level,
3296                                                     0,
3297                                                     &num_procs,
3298                                                     &procs);
3299         if (!W_ERROR_IS_OK(werror))
3300                 goto done;
3301
3302         /* Display output */
3303
3304         for (i = 0; i < num_procs; i++) {
3305                 switch (level) {
3306                 case 1:
3307                         display_proc_info1(&procs[i].info1);
3308                         break;
3309                 }
3310         }
3311
3312  done:
3313         return werror;
3314 }
3315
3316 static void display_proc_data_types_info1(struct spoolss_PrintProcDataTypesInfo1 *r)
3317 {
3318         printf("name_array: %s\n", r->name_array);
3319 }
3320
3321 static WERROR cmd_spoolss_enum_proc_data_types(struct rpc_pipe_client *cli,
3322                                                TALLOC_CTX *mem_ctx, int argc,
3323                                                const char **argv)
3324 {
3325         WERROR werror;
3326         const char *print_processor_name = "winprint";
3327         uint32_t num_procs, level = 1, i;
3328         union spoolss_PrintProcDataTypesInfo *procs;
3329
3330         /* Parse the command arguments */
3331
3332         if (argc < 1 || argc > 4) {
3333                 printf ("Usage: %s [environment] [level]\n", argv[0]);
3334                 return WERR_OK;
3335         }
3336
3337         if (argc >= 2) {
3338                 print_processor_name = argv[1];
3339         }
3340
3341         if (argc == 3) {
3342                 level = atoi(argv[2]);
3343         }
3344
3345         /* Enumerate Print Processor Data Types */
3346
3347         werror = rpccli_spoolss_enumprintprocessordatatypes(cli, mem_ctx,
3348                                                             cli->srv_name_slash,
3349                                                             print_processor_name,
3350                                                             level,
3351                                                             0,
3352                                                             &num_procs,
3353                                                             &procs);
3354         if (!W_ERROR_IS_OK(werror))
3355                 goto done;
3356
3357         /* Display output */
3358
3359         for (i = 0; i < num_procs; i++) {
3360                 switch (level) {
3361                 case 1:
3362                         display_proc_data_types_info1(&procs[i].info1);
3363                         break;
3364                 }
3365         }
3366
3367  done:
3368         return werror;
3369 }
3370
3371 static void display_monitor1(const struct spoolss_MonitorInfo1 *r)
3372 {
3373         printf("monitor_name: %s\n", r->monitor_name);
3374 }
3375
3376 static void display_monitor2(const struct spoolss_MonitorInfo2 *r)
3377 {
3378         printf("monitor_name: %s\n", r->monitor_name);
3379         printf("environment: %s\n", r->environment);
3380         printf("dll_name: %s\n", r->dll_name);
3381 }
3382
3383 static WERROR cmd_spoolss_enum_monitors(struct rpc_pipe_client *cli,
3384                                         TALLOC_CTX *mem_ctx, int argc,
3385                                         const char **argv)
3386 {
3387         WERROR werror;
3388         uint32_t count, level = 1, i;
3389         union spoolss_MonitorInfo *info;
3390
3391         /* Parse the command arguments */
3392
3393         if (argc > 2) {
3394                 printf("Usage: %s [level]\n", argv[0]);
3395                 return WERR_OK;
3396         }
3397
3398         if (argc == 2) {
3399                 level = atoi(argv[1]);
3400         }
3401
3402         /* Enumerate Print Monitors */
3403
3404         werror = rpccli_spoolss_enummonitors(cli, mem_ctx,
3405                                              cli->srv_name_slash,
3406                                              level,
3407                                              0,
3408                                              &count,
3409                                              &info);
3410         if (!W_ERROR_IS_OK(werror)) {
3411                 goto done;
3412         }
3413
3414         /* Display output */
3415
3416         for (i = 0; i < count; i++) {
3417                 switch (level) {
3418                 case 1:
3419                         display_monitor1(&info[i].info1);
3420                         break;
3421                 case 2:
3422                         display_monitor2(&info[i].info2);
3423                         break;
3424                 }
3425         }
3426
3427  done:
3428         return werror;
3429 }
3430
3431 static WERROR cmd_spoolss_create_printer_ic(struct rpc_pipe_client *cli,
3432                                             TALLOC_CTX *mem_ctx, int argc,
3433                                             const char **argv)
3434 {
3435         WERROR result;
3436         NTSTATUS status;
3437         struct policy_handle handle, gdi_handle;
3438         const char *printername;
3439         struct spoolss_DevmodeContainer devmode_ctr;
3440
3441         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
3442
3443         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
3444                                                printername,
3445                                                SEC_FLAG_MAXIMUM_ALLOWED,
3446                                                &handle);
3447         if (!W_ERROR_IS_OK(result)) {
3448                 return result;
3449         }
3450
3451         ZERO_STRUCT(devmode_ctr);
3452
3453         status = rpccli_spoolss_CreatePrinterIC(cli, mem_ctx,
3454                                                 &handle,
3455                                                 &gdi_handle,
3456                                                 &devmode_ctr,
3457                                                 &result);
3458         if (!W_ERROR_IS_OK(result)) {
3459                 goto done;
3460         }
3461
3462  done:
3463         if (is_valid_policy_hnd(&gdi_handle)) {
3464                 rpccli_spoolss_DeletePrinterIC(cli, mem_ctx, &gdi_handle, NULL);
3465         }
3466         if (is_valid_policy_hnd(&handle)) {
3467                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3468         }
3469
3470         return result;
3471 }
3472
3473 /* List of commands exported by this module */
3474 struct cmd_set spoolss_commands[] = {
3475
3476         { "SPOOLSS"  },
3477
3478         { "adddriver",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_addprinterdriver,   &ndr_table_spoolss.syntax_id, NULL, "Add a print driver",                  "" },
3479         { "addprinter",         RPC_RTYPE_WERROR, NULL, cmd_spoolss_addprinterex,       &ndr_table_spoolss.syntax_id, NULL, "Add a printer",                       "" },
3480         { "deldriver",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_deletedriver,       &ndr_table_spoolss.syntax_id, NULL, "Delete a printer driver",             "" },
3481         { "deldriverex",        RPC_RTYPE_WERROR, NULL, cmd_spoolss_deletedriverex,     &ndr_table_spoolss.syntax_id, NULL, "Delete a printer driver with files",  "" },
3482         { "enumdata",           RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_data,          &ndr_table_spoolss.syntax_id, NULL, "Enumerate printer data",              "" },
3483         { "enumdataex",         RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_data_ex,       &ndr_table_spoolss.syntax_id, NULL, "Enumerate printer data for a key",    "" },
3484         { "enumkey",            RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_printerkey,    &ndr_table_spoolss.syntax_id, NULL, "Enumerate printer keys",              "" },
3485         { "enumjobs",           RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_jobs,          &ndr_table_spoolss.syntax_id, NULL, "Enumerate print jobs",                "" },
3486         { "getjob",             RPC_RTYPE_WERROR, NULL, cmd_spoolss_get_job,            &ndr_table_spoolss.syntax_id, NULL, "Get print job",                       "" },
3487         { "setjob",             RPC_RTYPE_WERROR, NULL, cmd_spoolss_set_job,            &ndr_table_spoolss.syntax_id, NULL, "Set print job",                       "" },
3488         { "enumports",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_ports,         &ndr_table_spoolss.syntax_id, NULL, "Enumerate printer ports",             "" },
3489         { "enumdrivers",        RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_drivers,       &ndr_table_spoolss.syntax_id, NULL, "Enumerate installed printer drivers", "" },
3490         { "enumprinters",       RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_printers,      &ndr_table_spoolss.syntax_id, NULL, "Enumerate printers",                  "" },
3491         { "getdata",            RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprinterdata,     &ndr_table_spoolss.syntax_id, NULL, "Get print driver data",               "" },
3492         { "getdataex",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprinterdataex,   &ndr_table_spoolss.syntax_id, NULL, "Get printer driver data with keyname", ""},
3493         { "getdriver",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_getdriver,          &ndr_table_spoolss.syntax_id, NULL, "Get print driver information",        "" },
3494         { "getdriverdir",       RPC_RTYPE_WERROR, NULL, cmd_spoolss_getdriverdir,       &ndr_table_spoolss.syntax_id, NULL, "Get print driver upload directory",   "" },
3495         { "getprinter",         RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprinter,         &ndr_table_spoolss.syntax_id, NULL, "Get printer info",                    "" },
3496         { "openprinter",        RPC_RTYPE_WERROR, NULL, cmd_spoolss_open_printer_ex,    &ndr_table_spoolss.syntax_id, NULL, "Open printer handle",                 "" },
3497         { "setdriver",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_setdriver,          &ndr_table_spoolss.syntax_id, NULL, "Set printer driver",                  "" },
3498         { "getprintprocdir",    RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprintprocdir,    &ndr_table_spoolss.syntax_id, NULL, "Get print processor directory",       "" },
3499         { "addform",            RPC_RTYPE_WERROR, NULL, cmd_spoolss_addform,            &ndr_table_spoolss.syntax_id, NULL, "Add form",                            "" },
3500         { "setform",            RPC_RTYPE_WERROR, NULL, cmd_spoolss_setform,            &ndr_table_spoolss.syntax_id, NULL, "Set form",                            "" },
3501         { "getform",            RPC_RTYPE_WERROR, NULL, cmd_spoolss_getform,            &ndr_table_spoolss.syntax_id, NULL, "Get form",                            "" },
3502         { "deleteform",         RPC_RTYPE_WERROR, NULL, cmd_spoolss_deleteform,         &ndr_table_spoolss.syntax_id, NULL, "Delete form",                         "" },
3503         { "enumforms",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_forms,         &ndr_table_spoolss.syntax_id, NULL, "Enumerate forms",                     "" },
3504         { "setprinter",         RPC_RTYPE_WERROR, NULL, cmd_spoolss_setprinter,         &ndr_table_spoolss.syntax_id, NULL, "Set printer comment",                 "" },
3505         { "setprintername",     RPC_RTYPE_WERROR, NULL, cmd_spoolss_setprintername,     &ndr_table_spoolss.syntax_id, NULL, "Set printername",                 "" },
3506         { "setprinterdata",     RPC_RTYPE_WERROR, NULL, cmd_spoolss_setprinterdata,     &ndr_table_spoolss.syntax_id, NULL, "Set REG_SZ printer data",             "" },
3507         { "rffpcnex",           RPC_RTYPE_WERROR, NULL, cmd_spoolss_rffpcnex,           &ndr_table_spoolss.syntax_id, NULL, "Rffpcnex test", "" },
3508         { "printercmp",         RPC_RTYPE_WERROR, NULL, cmd_spoolss_printercmp,         &ndr_table_spoolss.syntax_id, NULL, "Printer comparison test", "" },
3509         { "enumprocs",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_procs,         &ndr_table_spoolss.syntax_id, NULL, "Enumerate Print Processors",          "" },
3510         { "enumprocdatatypes",  RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_proc_data_types, &ndr_table_spoolss.syntax_id, NULL, "Enumerate Print Processor Data Types", "" },
3511         { "enummonitors",       RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_monitors,      &ndr_table_spoolss.syntax_id, NULL, "Enumerate Print Monitors", "" },
3512         { "createprinteric",    RPC_RTYPE_WERROR, NULL, cmd_spoolss_create_printer_ic,  &ndr_table_spoolss.syntax_id, NULL, "Create Printer IC", "" },
3513
3514         { NULL }
3515 };