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