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