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