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