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