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