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