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