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