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