s3-rpcclient: use new rpccli_spoolss_enumforms wrapper.
[Samba/gbeck.git] / source3 / rpcclient / cmd_spoolss.c
blobc88cf89367a809e924fed9864d8cbaff3a1d57af
1 /*
2 Unix SMB/CIFS implementation.
3 RPC pipe client
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
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.
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.
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/>.
24 #include "includes.h"
25 #include "rpcclient.h"
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); \
34 struct table_node {
35 const char *long_archi;
36 const char *short_archi;
37 int version;
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 */
47 static const struct table_node archi_table[]= {
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 }
60 /**
61 * @file
63 * rpcclient module for SPOOLSS rpc pipe.
65 * This generally just parses and checks command lines, and then calls
66 * a cli_spoolss function.
67 **/
69 /****************************************************************************
70 function to do the mapping between the long architecture name and
71 the short one.
72 ****************************************************************************/
74 static const char *cmd_spoolss_get_short_archi(const char *long_archi)
76 int i=-1;
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) );
84 if (archi_table[i].long_archi==NULL) {
85 DEBUGADD(10,("Unknown architecture [%s] !\n", long_archi));
86 return NULL;
89 /* this might be client code - but shouldn't this be an fstrcpy etc? */
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));
96 return archi_table[i].short_archi;
99 /****************************************************************************
100 ****************************************************************************/
102 static WERROR cmd_spoolss_open_printer_ex(struct rpc_pipe_client *cli,
103 TALLOC_CTX *mem_ctx,
104 int argc, const char **argv)
106 WERROR werror;
107 POLICY_HND hnd;
109 if (argc != 2) {
110 printf("Usage: %s <printername>\n", argv[0]);
111 return WERR_OK;
114 if (!cli)
115 return WERR_GENERAL_FAILURE;
117 /* Open the printer handle */
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);
127 if (!W_ERROR_IS_OK(werror)) {
128 printf("Error closing printer handle! (%s)\n",
129 get_dos_error_msg(werror));
133 return werror;
137 /****************************************************************************
138 ****************************************************************************/
140 static void display_print_info_0(PRINTER_INFO_0 *i0)
142 fstring name = "";
143 fstring servername = "";
145 if (!i0)
146 return;
148 rpcstr_pull(name, i0->printername.buffer, sizeof(name), -1, STR_TERMINATE);
150 rpcstr_pull(servername, i0->servername.buffer, sizeof(servername), -1,STR_TERMINATE);
152 printf("\tprintername:[%s]\n", name);
153 printf("\tservername:[%s]\n", servername);
154 printf("\tcjobs:[0x%x]\n", i0->cjobs);
155 printf("\ttotal_jobs:[0x%x]\n", i0->total_jobs);
157 printf("\t:date: [%d]-[%d]-[%d] (%d)\n", i0->year, i0->month,
158 i0->day, i0->dayofweek);
159 printf("\t:time: [%d]-[%d]-[%d]-[%d]\n", i0->hour, i0->minute,
160 i0->second, i0->milliseconds);
162 printf("\tglobal_counter:[0x%x]\n", i0->global_counter);
163 printf("\ttotal_pages:[0x%x]\n", i0->total_pages);
165 printf("\tmajorversion:[0x%x]\n", i0->major_version);
166 printf("\tbuildversion:[0x%x]\n", i0->build_version);
168 printf("\tunknown7:[0x%x]\n", i0->unknown7);
169 printf("\tunknown8:[0x%x]\n", i0->unknown8);
170 printf("\tunknown9:[0x%x]\n", i0->unknown9);
171 printf("\tsession_counter:[0x%x]\n", i0->session_counter);
172 printf("\tunknown11:[0x%x]\n", i0->unknown11);
173 printf("\tprinter_errors:[0x%x]\n", i0->printer_errors);
174 printf("\tunknown13:[0x%x]\n", i0->unknown13);
175 printf("\tunknown14:[0x%x]\n", i0->unknown14);
176 printf("\tunknown15:[0x%x]\n", i0->unknown15);
177 printf("\tunknown16:[0x%x]\n", i0->unknown16);
178 printf("\tchange_id:[0x%x]\n", i0->change_id);
179 printf("\tunknown18:[0x%x]\n", i0->unknown18);
180 printf("\tstatus:[0x%x]\n", i0->status);
181 printf("\tunknown20:[0x%x]\n", i0->unknown20);
182 printf("\tc_setprinter:[0x%x]\n", i0->c_setprinter);
183 printf("\tunknown22:[0x%x]\n", i0->unknown22);
184 printf("\tunknown23:[0x%x]\n", i0->unknown23);
185 printf("\tunknown24:[0x%x]\n", i0->unknown24);
186 printf("\tunknown25:[0x%x]\n", i0->unknown25);
187 printf("\tunknown26:[0x%x]\n", i0->unknown26);
188 printf("\tunknown27:[0x%x]\n", i0->unknown27);
189 printf("\tunknown28:[0x%x]\n", i0->unknown28);
190 printf("\tunknown29:[0x%x]\n", i0->unknown29);
192 printf("\n");
195 /****************************************************************************
196 ****************************************************************************/
198 static void display_print_info_1(PRINTER_INFO_1 *i1)
200 fstring desc = "";
201 fstring name = "";
202 fstring comm = "";
204 rpcstr_pull(desc, i1->description.buffer, sizeof(desc), -1,
205 STR_TERMINATE);
207 rpcstr_pull(name, i1->name.buffer, sizeof(name), -1, STR_TERMINATE);
208 rpcstr_pull(comm, i1->comment.buffer, sizeof(comm), -1, STR_TERMINATE);
210 printf("\tflags:[0x%x]\n", i1->flags);
211 printf("\tname:[%s]\n", name);
212 printf("\tdescription:[%s]\n", desc);
213 printf("\tcomment:[%s]\n", comm);
215 printf("\n");
218 /****************************************************************************
219 ****************************************************************************/
221 static void display_print_info_2(PRINTER_INFO_2 *i2)
223 fstring servername = "";
224 fstring printername = "";
225 fstring sharename = "";
226 fstring portname = "";
227 fstring drivername = "";
228 fstring comment = "";
229 fstring location = "";
230 fstring sepfile = "";
231 fstring printprocessor = "";
232 fstring datatype = "";
233 fstring parameters = "";
235 rpcstr_pull(servername, i2->servername.buffer,sizeof(servername), -1, STR_TERMINATE);
236 rpcstr_pull(printername, i2->printername.buffer,sizeof(printername), -1, STR_TERMINATE);
237 rpcstr_pull(sharename, i2->sharename.buffer,sizeof(sharename), -1, STR_TERMINATE);
238 rpcstr_pull(portname, i2->portname.buffer,sizeof(portname), -1, STR_TERMINATE);
239 rpcstr_pull(drivername, i2->drivername.buffer,sizeof(drivername), -1, STR_TERMINATE);
240 rpcstr_pull(comment, i2->comment.buffer,sizeof(comment), -1, STR_TERMINATE);
241 rpcstr_pull(location, i2->location.buffer,sizeof(location), -1, STR_TERMINATE);
242 rpcstr_pull(sepfile, i2->sepfile.buffer,sizeof(sepfile), -1, STR_TERMINATE);
243 rpcstr_pull(printprocessor, i2->printprocessor.buffer,sizeof(printprocessor), -1, STR_TERMINATE);
244 rpcstr_pull(datatype, i2->datatype.buffer,sizeof(datatype), -1, STR_TERMINATE);
245 rpcstr_pull(parameters, i2->parameters.buffer,sizeof(parameters), -1, STR_TERMINATE);
247 printf("\tservername:[%s]\n", servername);
248 printf("\tprintername:[%s]\n", printername);
249 printf("\tsharename:[%s]\n", sharename);
250 printf("\tportname:[%s]\n", portname);
251 printf("\tdrivername:[%s]\n", drivername);
252 printf("\tcomment:[%s]\n", comment);
253 printf("\tlocation:[%s]\n", location);
254 printf("\tsepfile:[%s]\n", sepfile);
255 printf("\tprintprocessor:[%s]\n", printprocessor);
256 printf("\tdatatype:[%s]\n", datatype);
257 printf("\tparameters:[%s]\n", parameters);
258 printf("\tattributes:[0x%x]\n", i2->attributes);
259 printf("\tpriority:[0x%x]\n", i2->priority);
260 printf("\tdefaultpriority:[0x%x]\n", i2->defaultpriority);
261 printf("\tstarttime:[0x%x]\n", i2->starttime);
262 printf("\tuntiltime:[0x%x]\n", i2->untiltime);
263 printf("\tstatus:[0x%x]\n", i2->status);
264 printf("\tcjobs:[0x%x]\n", i2->cjobs);
265 printf("\taverageppm:[0x%x]\n", i2->averageppm);
267 if (i2->secdesc)
268 display_sec_desc(i2->secdesc);
270 printf("\n");
273 /****************************************************************************
274 ****************************************************************************/
276 static void display_print_info_3(PRINTER_INFO_3 *i3)
278 display_sec_desc(i3->secdesc);
280 printf("\n");
283 /****************************************************************************
284 ****************************************************************************/
286 static void display_print_info7(struct spoolss_PrinterInfo7 *r)
288 printf("\tguid:[%s]\n", r->guid);
289 printf("\taction:[0x%x]\n", r->action);
293 /****************************************************************************
294 ****************************************************************************/
296 static WERROR cmd_spoolss_enum_printers(struct rpc_pipe_client *cli,
297 TALLOC_CTX *mem_ctx,
298 int argc, const char **argv)
300 WERROR result;
301 uint32 info_level = 1;
302 PRINTER_INFO_CTR ctr;
303 uint32 i = 0, num_printers;
304 fstring name;
306 if (argc > 3)
308 printf("Usage: %s [level] [name]\n", argv[0]);
309 return WERR_OK;
312 if (argc >= 2)
313 info_level = atoi(argv[1]);
315 if (argc == 3)
316 fstrcpy(name, argv[2]);
317 else {
318 slprintf(name, sizeof(name)-1, "\\\\%s", cli->desthost);
319 strupper_m(name);
322 ZERO_STRUCT(ctr);
324 result = rpccli_spoolss_enum_printers(cli, mem_ctx, name, PRINTER_ENUM_LOCAL,
325 info_level, &num_printers, &ctr);
327 if (W_ERROR_IS_OK(result)) {
329 if (!num_printers) {
330 printf ("No printers returned.\n");
331 goto done;
334 for (i = 0; i < num_printers; i++) {
335 switch(info_level) {
336 case 0:
337 display_print_info_0(&ctr.printers_0[i]);
338 break;
339 case 1:
340 display_print_info_1(&ctr.printers_1[i]);
341 break;
342 case 2:
343 display_print_info_2(&ctr.printers_2[i]);
344 break;
345 case 3:
346 display_print_info_3(&ctr.printers_3[i]);
347 break;
348 default:
349 printf("unknown info level %d\n", info_level);
350 goto done;
354 done:
356 return result;
359 /****************************************************************************
360 ****************************************************************************/
362 static void display_port_info_1(PORT_INFO_1 *i1)
364 fstring buffer;
366 rpcstr_pull(buffer, i1->port_name.buffer, sizeof(buffer), -1, STR_TERMINATE);
367 printf("\tPort Name:\t[%s]\n", buffer);
370 /****************************************************************************
371 ****************************************************************************/
373 static void display_port_info_2(PORT_INFO_2 *i2)
375 fstring buffer;
377 rpcstr_pull(buffer, i2->port_name.buffer, sizeof(buffer), -1, STR_TERMINATE);
378 printf("\tPort Name:\t[%s]\n", buffer);
379 rpcstr_pull(buffer, i2->monitor_name.buffer, sizeof(buffer), -1, STR_TERMINATE);
381 printf("\tMonitor Name:\t[%s]\n", buffer);
382 rpcstr_pull(buffer, i2->description.buffer, sizeof(buffer), -1, STR_TERMINATE);
384 printf("\tDescription:\t[%s]\n", buffer);
385 printf("\tPort Type:\t" );
386 if ( i2->port_type ) {
387 int comma = 0; /* hack */
388 printf( "[" );
389 if ( i2->port_type & PORT_TYPE_READ ) {
390 printf( "Read" );
391 comma = 1;
393 if ( i2->port_type & PORT_TYPE_WRITE ) {
394 printf( "%sWrite", comma ? ", " : "" );
395 comma = 1;
397 /* These two have slightly different interpretations
398 on 95/98/ME but I'm disregarding that for now */
399 if ( i2->port_type & PORT_TYPE_REDIRECTED ) {
400 printf( "%sRedirected", comma ? ", " : "" );
401 comma = 1;
403 if ( i2->port_type & PORT_TYPE_NET_ATTACHED ) {
404 printf( "%sNet-Attached", comma ? ", " : "" );
406 printf( "]\n" );
407 } else {
408 printf( "[Unset]\n" );
410 printf("\tReserved:\t[%d]\n", i2->reserved);
411 printf("\n");
414 /****************************************************************************
415 ****************************************************************************/
417 static WERROR cmd_spoolss_enum_ports(struct rpc_pipe_client *cli,
418 TALLOC_CTX *mem_ctx, int argc,
419 const char **argv)
421 WERROR result;
422 uint32 info_level = 1;
423 PORT_INFO_CTR ctr;
424 uint32 returned;
426 if (argc > 2) {
427 printf("Usage: %s [level]\n", argv[0]);
428 return WERR_OK;
431 if (argc == 2)
432 info_level = atoi(argv[1]);
434 /* Enumerate ports */
436 ZERO_STRUCT(ctr);
438 result = rpccli_spoolss_enum_ports(cli, mem_ctx, info_level, &returned, &ctr);
440 if (W_ERROR_IS_OK(result)) {
441 int i;
443 for (i = 0; i < returned; i++) {
444 switch (info_level) {
445 case 1:
446 display_port_info_1(&ctr.port.info_1[i]);
447 break;
448 case 2:
449 display_port_info_2(&ctr.port.info_2[i]);
450 break;
451 default:
452 printf("unknown info level %d\n", info_level);
453 break;
458 return result;
461 /****************************************************************************
462 ****************************************************************************/
464 static WERROR cmd_spoolss_setprinter(struct rpc_pipe_client *cli,
465 TALLOC_CTX *mem_ctx,
466 int argc, const char **argv)
468 POLICY_HND pol;
469 WERROR result;
470 NTSTATUS status;
471 uint32 info_level = 2;
472 union spoolss_PrinterInfo info;
473 struct spoolss_SetPrinterInfoCtr info_ctr;
474 const char *printername, *comment = NULL;
475 struct spoolss_DevmodeContainer devmode_ctr;
476 struct sec_desc_buf secdesc_ctr;
478 if (argc == 1 || argc > 3) {
479 printf("Usage: %s printername comment\n", argv[0]);
481 return WERR_OK;
484 /* Open a printer handle */
485 if (argc == 3) {
486 comment = argv[2];
489 ZERO_STRUCT(devmode_ctr);
490 ZERO_STRUCT(secdesc_ctr);
492 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
494 /* get a printer handle */
495 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
496 printername,
497 PRINTER_ALL_ACCESS,
498 &pol);
499 if (!W_ERROR_IS_OK(result))
500 goto done;
502 /* Get printer info */
503 result = rpccli_spoolss_getprinter(cli, mem_ctx,
504 &pol,
505 info_level,
507 &info);
508 if (!W_ERROR_IS_OK(result))
509 goto done;
512 /* Modify the comment. */
513 info.info2.comment = comment;
514 info.info2.secdesc = NULL;
515 info.info2.devmode = NULL;
517 info_ctr.level = 2;
518 info_ctr.info.info2 = (struct spoolss_SetPrinterInfo2 *)&info.info2;
520 status = rpccli_spoolss_SetPrinter(cli, mem_ctx,
521 &pol,
522 &info_ctr,
523 &devmode_ctr,
524 &secdesc_ctr,
525 0, /* command */
526 &result);
527 if (W_ERROR_IS_OK(result))
528 printf("Success in setting comment.\n");
530 done:
531 if (is_valid_policy_hnd(&pol))
532 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &pol, NULL);
534 return result;
537 /****************************************************************************
538 ****************************************************************************/
540 static WERROR cmd_spoolss_setprintername(struct rpc_pipe_client *cli,
541 TALLOC_CTX *mem_ctx,
542 int argc, const char **argv)
544 POLICY_HND pol;
545 WERROR result;
546 NTSTATUS status;
547 uint32 info_level = 2;
548 union spoolss_PrinterInfo info;
549 const char *printername,
550 *new_printername = NULL;
551 struct spoolss_SetPrinterInfoCtr info_ctr;
552 struct spoolss_DevmodeContainer devmode_ctr;
553 struct sec_desc_buf secdesc_ctr;
555 ZERO_STRUCT(devmode_ctr);
556 ZERO_STRUCT(secdesc_ctr);
558 if (argc == 1 || argc > 3) {
559 printf("Usage: %s printername new_printername\n", argv[0]);
561 return WERR_OK;
564 /* Open a printer handle */
565 if (argc == 3) {
566 new_printername = argv[2];
569 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
571 /* get a printer handle */
572 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
573 printername,
574 PRINTER_ALL_ACCESS,
575 &pol);
576 if (!W_ERROR_IS_OK(result))
577 goto done;
579 /* Get printer info */
580 result = rpccli_spoolss_getprinter(cli, mem_ctx,
581 &pol,
582 info_level,
584 &info);
585 if (!W_ERROR_IS_OK(result))
586 goto done;
588 /* Modify the printername. */
589 info.info2.printername = new_printername;
590 info.info2.devmode = NULL;
591 info.info2.secdesc = NULL;
593 info_ctr.level = info_level;
594 info_ctr.info.info2 = (struct spoolss_SetPrinterInfo2 *)&info.info2;
596 status = rpccli_spoolss_SetPrinter(cli, mem_ctx,
597 &pol,
598 &info_ctr,
599 &devmode_ctr,
600 &secdesc_ctr,
601 0, /* command */
602 &result);
603 if (W_ERROR_IS_OK(result))
604 printf("Success in setting printername.\n");
606 done:
607 if (is_valid_policy_hnd(&pol))
608 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &pol, NULL);
610 return result;
613 /****************************************************************************
614 ****************************************************************************/
616 static WERROR cmd_spoolss_getprinter(struct rpc_pipe_client *cli,
617 TALLOC_CTX *mem_ctx,
618 int argc, const char **argv)
620 POLICY_HND pol;
621 WERROR result;
622 uint32 info_level = 1;
623 const char *printername;
624 union spoolss_PrinterInfo info;
626 if (argc == 1 || argc > 3) {
627 printf("Usage: %s <printername> [level]\n", argv[0]);
628 return WERR_OK;
631 /* Open a printer handle */
632 if (argc == 3) {
633 info_level = atoi(argv[2]);
636 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
638 /* get a printer handle */
640 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
641 printername,
642 SEC_FLAG_MAXIMUM_ALLOWED,
643 &pol);
644 if (!W_ERROR_IS_OK(result))
645 goto done;
647 /* Get printer info */
649 result = rpccli_spoolss_getprinter(cli, mem_ctx,
650 &pol,
651 info_level,
653 &info);
654 if (!W_ERROR_IS_OK(result))
655 goto done;
657 /* Display printer info */
658 switch (info_level) {
659 #if 0 /* FIXME GD */
660 case 0:
661 display_print_info_0(ctr.printers_0);
662 break;
663 case 1:
664 display_print_info_1(ctr.printers_1);
665 break;
666 case 2:
667 display_print_info_2(ctr.printers_2);
668 break;
669 case 3:
670 display_print_info_3(ctr.printers_3);
671 break;
672 #endif
673 case 7:
674 display_print_info7(&info.info7);
675 break;
676 default:
677 printf("unknown info level %d\n", info_level);
678 break;
680 done:
681 if (is_valid_policy_hnd(&pol))
682 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &pol, NULL);
684 return result;
687 /****************************************************************************
688 ****************************************************************************/
690 static void display_reg_value(REGISTRY_VALUE value)
692 char *text = NULL;
694 switch(value.type) {
695 case REG_DWORD:
696 printf("%s: REG_DWORD: 0x%08x\n", value.valuename,
697 *((uint32 *) value.data_p));
698 break;
699 case REG_SZ:
700 rpcstr_pull_talloc(talloc_tos(),
701 &text,
702 value.data_p,
703 value.size,
704 STR_TERMINATE);
705 printf("%s: REG_SZ: %s\n", value.valuename, text ? text : "");
706 break;
707 case REG_BINARY: {
708 char *hex = hex_encode_talloc(NULL, value.data_p, value.size);
709 size_t i, len;
710 printf("%s: REG_BINARY:", value.valuename);
711 len = strlen(hex);
712 for (i=0; i<len; i++) {
713 if (hex[i] == '\0') {
714 break;
716 if (i%40 == 0) {
717 putchar('\n');
719 putchar(hex[i]);
721 TALLOC_FREE(hex);
722 putchar('\n');
723 break;
725 case REG_MULTI_SZ: {
726 uint32 i, num_values;
727 char **values;
729 if (!W_ERROR_IS_OK(reg_pull_multi_sz(NULL, value.data_p,
730 value.size, &num_values,
731 &values))) {
732 d_printf("reg_pull_multi_sz failed\n");
733 break;
736 for (i=0; i<num_values; i++) {
737 d_printf("%s\n", values[i]);
739 TALLOC_FREE(values);
740 break;
742 default:
743 printf("%s: unknown type %d\n", value.valuename, value.type);
748 /****************************************************************************
749 ****************************************************************************/
751 static WERROR cmd_spoolss_getprinterdata(struct rpc_pipe_client *cli,
752 TALLOC_CTX *mem_ctx,
753 int argc, const char **argv)
755 POLICY_HND pol;
756 WERROR result;
757 fstring printername;
758 const char *valuename;
759 REGISTRY_VALUE value;
761 if (argc != 3) {
762 printf("Usage: %s <printername> <valuename>\n", argv[0]);
763 printf("<printername> of . queries print server\n");
764 return WERR_OK;
766 valuename = argv[2];
768 /* Open a printer handle */
770 if (strncmp(argv[1], ".", sizeof(".")) == 0)
771 fstrcpy(printername, cli->srv_name_slash);
772 else
773 slprintf(printername, sizeof(printername)-1, "%s\\%s",
774 cli->srv_name_slash, argv[1]);
776 /* get a printer handle */
778 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
779 printername,
780 SEC_FLAG_MAXIMUM_ALLOWED,
781 &pol);
782 if (!W_ERROR_IS_OK(result))
783 goto done;
785 /* Get printer info */
787 result = rpccli_spoolss_getprinterdata(cli, mem_ctx, &pol, valuename, &value);
789 if (!W_ERROR_IS_OK(result))
790 goto done;
792 /* Display printer data */
794 fstrcpy(value.valuename, valuename);
795 display_reg_value(value);
798 done:
799 if (is_valid_policy_hnd(&pol))
800 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &pol, NULL);
802 return result;
805 /****************************************************************************
806 ****************************************************************************/
808 static WERROR cmd_spoolss_getprinterdataex(struct rpc_pipe_client *cli,
809 TALLOC_CTX *mem_ctx,
810 int argc, const char **argv)
812 POLICY_HND pol;
813 WERROR result;
814 NTSTATUS status;
815 fstring printername;
816 const char *valuename, *keyname;
817 REGISTRY_VALUE value;
819 uint32_t type;
820 uint8_t *buffer = NULL;
821 uint32_t offered = 0;
822 uint32_t needed;
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;
830 valuename = argv[3];
831 keyname = argv[2];
833 /* Open a printer handle */
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]);
841 /* get a printer handle */
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;
850 /* Get printer info */
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);
875 if (!NT_STATUS_IS_OK(status)) {
876 goto done;
879 if (!W_ERROR_IS_OK(result)) {
880 goto done;
884 if (!W_ERROR_IS_OK(result))
885 goto done;
887 /* Display printer data */
889 fstrcpy(value.valuename, valuename);
890 value.type = type;
891 value.size = needed;
892 value.data_p = buffer;
894 display_reg_value(value);
896 done:
897 if (is_valid_policy_hnd(&pol))
898 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &pol, NULL);
900 return result;
903 /****************************************************************************
904 ****************************************************************************/
906 static void display_print_driver_1(DRIVER_INFO_1 *i1)
908 fstring name;
909 if (i1 == NULL)
910 return;
912 rpcstr_pull(name, i1->name.buffer, sizeof(name), -1, STR_TERMINATE);
914 printf ("Printer Driver Info 1:\n");
915 printf ("\tDriver Name: [%s]\n\n", name);
917 return;
920 /****************************************************************************
921 ****************************************************************************/
923 static void display_print_driver_2(DRIVER_INFO_2 *i1)
925 fstring name;
926 fstring architecture;
927 fstring driverpath;
928 fstring datafile;
929 fstring configfile;
930 if (i1 == NULL)
931 return;
933 rpcstr_pull(name, i1->name.buffer, sizeof(name), -1, STR_TERMINATE);
934 rpcstr_pull(architecture, i1->architecture.buffer, sizeof(architecture), -1, STR_TERMINATE);
935 rpcstr_pull(driverpath, i1->driverpath.buffer, sizeof(driverpath), -1, STR_TERMINATE);
936 rpcstr_pull(datafile, i1->datafile.buffer, sizeof(datafile), -1, STR_TERMINATE);
937 rpcstr_pull(configfile, i1->configfile.buffer, sizeof(configfile), -1, STR_TERMINATE);
939 printf ("Printer Driver Info 2:\n");
940 printf ("\tVersion: [%x]\n", i1->version);
941 printf ("\tDriver Name: [%s]\n", name);
942 printf ("\tArchitecture: [%s]\n", architecture);
943 printf ("\tDriver Path: [%s]\n", driverpath);
944 printf ("\tDatafile: [%s]\n", datafile);
945 printf ("\tConfigfile: [%s]\n\n", configfile);
947 return;
950 /****************************************************************************
951 ****************************************************************************/
953 static void display_print_driver_3(DRIVER_INFO_3 *i1)
955 fstring name = "";
956 fstring architecture = "";
957 fstring driverpath = "";
958 fstring datafile = "";
959 fstring configfile = "";
960 fstring helpfile = "";
961 fstring dependentfiles = "";
962 fstring monitorname = "";
963 fstring defaultdatatype = "";
965 int length=0;
966 bool valid = True;
968 if (i1 == NULL)
969 return;
971 rpcstr_pull(name, i1->name.buffer, sizeof(name), -1, STR_TERMINATE);
972 rpcstr_pull(architecture, i1->architecture.buffer, sizeof(architecture), -1, STR_TERMINATE);
973 rpcstr_pull(driverpath, i1->driverpath.buffer, sizeof(driverpath), -1, STR_TERMINATE);
974 rpcstr_pull(datafile, i1->datafile.buffer, sizeof(datafile), -1, STR_TERMINATE);
975 rpcstr_pull(configfile, i1->configfile.buffer, sizeof(configfile), -1, STR_TERMINATE);
976 rpcstr_pull(helpfile, i1->helpfile.buffer, sizeof(helpfile), -1, STR_TERMINATE);
977 rpcstr_pull(monitorname, i1->monitorname.buffer, sizeof(monitorname), -1, STR_TERMINATE);
978 rpcstr_pull(defaultdatatype, i1->defaultdatatype.buffer, sizeof(defaultdatatype), -1, STR_TERMINATE);
980 printf ("Printer Driver Info 3:\n");
981 printf ("\tVersion: [%x]\n", i1->version);
982 printf ("\tDriver Name: [%s]\n",name);
983 printf ("\tArchitecture: [%s]\n", architecture);
984 printf ("\tDriver Path: [%s]\n", driverpath);
985 printf ("\tDatafile: [%s]\n", datafile);
986 printf ("\tConfigfile: [%s]\n", configfile);
987 printf ("\tHelpfile: [%s]\n\n", helpfile);
989 while (valid)
991 rpcstr_pull(dependentfiles, i1->dependentfiles+length, sizeof(dependentfiles), -1, STR_TERMINATE);
993 length+=strlen(dependentfiles)+1;
995 if (strlen(dependentfiles) > 0)
997 printf ("\tDependentfiles: [%s]\n", dependentfiles);
999 else
1001 valid = False;
1005 printf ("\n");
1007 printf ("\tMonitorname: [%s]\n", monitorname);
1008 printf ("\tDefaultdatatype: [%s]\n\n", defaultdatatype);
1010 return;
1013 /****************************************************************************
1014 ****************************************************************************/
1016 static void display_print_driver1(struct spoolss_DriverInfo1 *r)
1018 if (!r) {
1019 return;
1022 printf("Printer Driver Info 1:\n");
1023 printf("\tDriver Name: [%s]\n\n", r->driver_name);
1026 /****************************************************************************
1027 ****************************************************************************/
1029 static void display_print_driver2(struct spoolss_DriverInfo2 *r)
1031 if (!r) {
1032 return;
1035 printf("Printer Driver Info 2:\n");
1036 printf("\tVersion: [%x]\n", r->version);
1037 printf("\tDriver Name: [%s]\n", r->driver_name);
1038 printf("\tArchitecture: [%s]\n", r->architecture);
1039 printf("\tDriver Path: [%s]\n", r->driver_path);
1040 printf("\tDatafile: [%s]\n", r->data_file);
1041 printf("\tConfigfile: [%s]\n\n", r->config_file);
1044 /****************************************************************************
1045 ****************************************************************************/
1047 static void display_print_driver3(struct spoolss_DriverInfo3 *r)
1049 int i;
1051 if (!r) {
1052 return;
1055 printf("Printer Driver Info 3:\n");
1056 printf("\tVersion: [%x]\n", r->version);
1057 printf("\tDriver Name: [%s]\n", r->driver_name);
1058 printf("\tArchitecture: [%s]\n", r->architecture);
1059 printf("\tDriver Path: [%s]\n", r->driver_path);
1060 printf("\tDatafile: [%s]\n", r->data_file);
1061 printf("\tConfigfile: [%s]\n\n", r->config_file);
1062 printf("\tHelpfile: [%s]\n\n", r->help_file);
1064 for (i=0; r->dependent_files[i] != NULL; i++) {
1065 printf("\tDependentfiles: [%s]\n", r->dependent_files[i]);
1068 printf("\n");
1070 printf("\tMonitorname: [%s]\n", r->monitor_name);
1071 printf("\tDefaultdatatype: [%s]\n\n", r->default_datatype);
1075 /****************************************************************************
1076 ****************************************************************************/
1078 static WERROR cmd_spoolss_getdriver(struct rpc_pipe_client *cli,
1079 TALLOC_CTX *mem_ctx,
1080 int argc, const char **argv)
1082 POLICY_HND pol;
1083 WERROR werror;
1084 uint32 info_level = 3;
1085 const char *printername;
1086 uint32 i;
1087 bool success = False;
1088 union spoolss_DriverInfo info;
1089 uint32_t server_major_version;
1090 uint32_t server_minor_version;
1092 if ((argc == 1) || (argc > 3))
1094 printf("Usage: %s <printername> [level]\n", argv[0]);
1095 return WERR_OK;
1098 /* get the arguments need to open the printer handle */
1100 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
1102 if (argc == 3)
1103 info_level = atoi(argv[2]);
1105 /* Open a printer handle */
1107 werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
1108 printername,
1109 PRINTER_ACCESS_USE,
1110 &pol);
1111 if (!W_ERROR_IS_OK(werror)) {
1112 printf("Error opening printer handle for %s!\n", printername);
1113 return werror;
1116 /* loop through and print driver info level for each architecture */
1118 for (i=0; archi_table[i].long_archi!=NULL; i++) {
1120 werror = rpccli_spoolss_getprinterdriver2(cli, mem_ctx,
1121 &pol,
1122 archi_table[i].long_archi,
1123 info_level,
1124 0, /* offered */
1125 archi_table[i].version,
1127 &info,
1128 &server_major_version,
1129 &server_minor_version);
1130 if (!W_ERROR_IS_OK(werror))
1131 continue;
1133 /* need at least one success */
1135 success = True;
1137 printf ("\n[%s]\n", archi_table[i].long_archi);
1139 switch (info_level) {
1140 case 1:
1141 display_print_driver1(&info.info1);
1142 break;
1143 case 2:
1144 display_print_driver2(&info.info2);
1145 break;
1146 case 3:
1147 display_print_driver3(&info.info3);
1148 break;
1149 default:
1150 printf("unknown info level %d\n", info_level);
1151 break;
1155 /* Cleanup */
1157 if (is_valid_policy_hnd(&pol))
1158 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &pol, NULL);
1160 if ( success )
1161 werror = WERR_OK;
1163 return werror;
1166 /****************************************************************************
1167 ****************************************************************************/
1169 static WERROR cmd_spoolss_enum_drivers(struct rpc_pipe_client *cli,
1170 TALLOC_CTX *mem_ctx,
1171 int argc, const char **argv)
1173 WERROR werror = WERR_OK;
1174 uint32 info_level = 1;
1175 PRINTER_DRIVER_CTR ctr;
1176 uint32 i, j,
1177 returned;
1179 if (argc > 2) {
1180 printf("Usage: enumdrivers [level]\n");
1181 return WERR_OK;
1184 if (argc == 2)
1185 info_level = atoi(argv[1]);
1188 /* loop through and print driver info level for each architecture */
1189 for (i=0; archi_table[i].long_archi!=NULL; i++) {
1190 /* check to see if we already asked for this architecture string */
1192 if ( i>0 && strequal(archi_table[i].long_archi, archi_table[i-1].long_archi) )
1193 continue;
1195 werror = rpccli_spoolss_enumprinterdrivers(
1196 cli, mem_ctx, info_level,
1197 archi_table[i].long_archi, &returned, &ctr);
1199 if (W_ERROR_V(werror) == W_ERROR_V(WERR_INVALID_ENVIRONMENT)) {
1200 printf ("Server does not support environment [%s]\n",
1201 archi_table[i].long_archi);
1202 werror = WERR_OK;
1203 continue;
1206 if (returned == 0)
1207 continue;
1209 if (!W_ERROR_IS_OK(werror)) {
1210 printf ("Error getting driver for environment [%s] - %d\n",
1211 archi_table[i].long_archi, W_ERROR_V(werror));
1212 continue;
1215 printf ("\n[%s]\n", archi_table[i].long_archi);
1216 switch (info_level)
1219 case 1:
1220 for (j=0; j < returned; j++) {
1221 display_print_driver_1 (&ctr.info1[j]);
1223 break;
1224 case 2:
1225 for (j=0; j < returned; j++) {
1226 display_print_driver_2 (&ctr.info2[j]);
1228 break;
1229 case 3:
1230 for (j=0; j < returned; j++) {
1231 display_print_driver_3 (&ctr.info3[j]);
1233 break;
1234 default:
1235 printf("unknown info level %d\n", info_level);
1236 return WERR_UNKNOWN_LEVEL;
1240 return werror;
1243 /****************************************************************************
1244 ****************************************************************************/
1246 static void display_printdriverdir_1(struct spoolss_DriverDirectoryInfo1 *r)
1248 printf("\tDirectory Name:[%s]\n", r->directory_name);
1251 /****************************************************************************
1252 ****************************************************************************/
1254 static WERROR cmd_spoolss_getdriverdir(struct rpc_pipe_client *cli,
1255 TALLOC_CTX *mem_ctx,
1256 int argc, const char **argv)
1258 WERROR result;
1259 NTSTATUS status;
1260 const char *env = SPOOLSS_ARCHITECTURE_NT_X86;
1261 DATA_BLOB buffer;
1262 uint32_t offered;
1263 union spoolss_DriverDirectoryInfo info;
1264 uint32_t needed;
1266 if (argc > 2) {
1267 printf("Usage: %s [environment]\n", argv[0]);
1268 return WERR_OK;
1271 /* Get the arguments need to open the printer handle */
1273 if (argc == 2) {
1274 env = argv[1];
1277 /* Get the directory. Only use Info level 1 */
1279 status = rpccli_spoolss_GetPrinterDriverDirectory(cli, mem_ctx,
1280 cli->srv_name_slash,
1281 env,
1283 NULL, /* buffer */
1284 0, /* offered */
1285 NULL, /* info */
1286 &needed,
1287 &result);
1288 if (W_ERROR_EQUAL(result, WERR_INSUFFICIENT_BUFFER)) {
1289 offered = needed;
1290 buffer = data_blob_talloc_zero(mem_ctx, needed);
1292 status = rpccli_spoolss_GetPrinterDriverDirectory(cli, mem_ctx,
1293 cli->srv_name_slash,
1294 env,
1296 &buffer,
1297 offered,
1298 &info,
1299 &needed,
1300 &result);
1303 if (W_ERROR_IS_OK(result)) {
1304 display_printdriverdir_1(&info.info1);
1307 return result;
1310 /****************************************************************************
1311 ****************************************************************************/
1313 static void set_drv_info_3_env(TALLOC_CTX *mem_ctx,
1314 struct spoolss_AddDriverInfo3 *info,
1315 const char *arch)
1318 int i;
1320 for (i=0; archi_table[i].long_archi != NULL; i++)
1322 if (strcmp(arch, archi_table[i].short_archi) == 0)
1324 info->version = archi_table[i].version;
1325 info->architecture = talloc_strdup(mem_ctx, archi_table[i].long_archi);
1326 break;
1330 if (archi_table[i].long_archi == NULL)
1332 DEBUG(0, ("set_drv_info_3_env: Unknown arch [%s]\n", arch));
1335 return;
1339 /**************************************************************************
1340 wrapper for strtok to get the next parameter from a delimited list.
1341 Needed to handle the empty parameter string denoted by "NULL"
1342 *************************************************************************/
1344 static char *get_driver_3_param(TALLOC_CTX *mem_ctx, char *str,
1345 const char *delim, const char **dest,
1346 char **saveptr)
1348 char *ptr;
1350 /* get the next token */
1351 ptr = strtok_r(str, delim, saveptr);
1353 /* a string of 'NULL' is used to represent an empty
1354 parameter because two consecutive delimiters
1355 will not return an empty string. See man strtok(3)
1356 for details */
1357 if (ptr && (StrCaseCmp(ptr, "NULL") == 0)) {
1358 ptr = NULL;
1361 if (dest != NULL) {
1362 *dest = talloc_strdup(mem_ctx, ptr);
1365 return ptr;
1368 /********************************************************************************
1369 fill in the members of a spoolss_AddDriverInfo3 struct using a character
1370 string in the form of
1371 <Long Printer Name>:<Driver File Name>:<Data File Name>:\
1372 <Config File Name>:<Help File Name>:<Language Monitor Name>:\
1373 <Default Data Type>:<Comma Separated list of Files>
1374 *******************************************************************************/
1376 static bool init_drv_info_3_members(TALLOC_CTX *mem_ctx, struct spoolss_AddDriverInfo3 *r,
1377 char *args)
1379 char *str, *str2;
1380 int count = 0;
1381 char *saveptr = NULL;
1382 struct spoolss_StringArray *deps;
1383 const char **file_array = NULL;
1384 int i;
1386 /* fill in the UNISTR fields */
1387 str = get_driver_3_param(mem_ctx, args, ":", &r->driver_name, &saveptr);
1388 str = get_driver_3_param(mem_ctx, NULL, ":", &r->driver_path, &saveptr);
1389 str = get_driver_3_param(mem_ctx, NULL, ":", &r->data_file, &saveptr);
1390 str = get_driver_3_param(mem_ctx, NULL, ":", &r->config_file, &saveptr);
1391 str = get_driver_3_param(mem_ctx, NULL, ":", &r->help_file, &saveptr);
1392 str = get_driver_3_param(mem_ctx, NULL, ":", &r->monitor_name, &saveptr);
1393 str = get_driver_3_param(mem_ctx, NULL, ":", &r->default_datatype, &saveptr);
1395 /* <Comma Separated List of Dependent Files> */
1396 /* save the beginning of the string */
1397 str2 = get_driver_3_param(mem_ctx, NULL, ":", NULL, &saveptr);
1398 str = str2;
1400 /* begin to strip out each filename */
1401 str = strtok_r(str, ",", &saveptr);
1403 /* no dependent files, we are done */
1404 if (!str) {
1405 return true;
1408 deps = talloc_zero(mem_ctx, struct spoolss_StringArray);
1409 if (!deps) {
1410 return false;
1413 while (str != NULL) {
1414 add_string_to_array(deps, str, &file_array, &count);
1415 str = strtok_r(NULL, ",", &saveptr);
1418 deps->string = talloc_zero_array(deps, const char *, count + 1);
1419 if (!deps->string) {
1420 return false;
1423 for (i=0; i < count; i++) {
1424 deps->string[i] = file_array[i];
1427 r->dependent_files = deps;
1429 return true;
1432 /****************************************************************************
1433 ****************************************************************************/
1435 static WERROR cmd_spoolss_addprinterdriver(struct rpc_pipe_client *cli,
1436 TALLOC_CTX *mem_ctx,
1437 int argc, const char **argv)
1439 WERROR result;
1440 NTSTATUS status;
1441 uint32 level = 3;
1442 struct spoolss_AddDriverInfoCtr info_ctr;
1443 struct spoolss_AddDriverInfo3 info3;
1444 const char *arch;
1445 char *driver_args;
1447 /* parse the command arguments */
1448 if (argc != 3 && argc != 4)
1450 printf ("Usage: %s <Environment> \\\n", argv[0]);
1451 printf ("\t<Long Printer Name>:<Driver File Name>:<Data File Name>:\\\n");
1452 printf ("\t<Config File Name>:<Help File Name>:<Language Monitor Name>:\\\n");
1453 printf ("\t<Default Data Type>:<Comma Separated list of Files> \\\n");
1454 printf ("\t[version]\n");
1456 return WERR_OK;
1459 /* Fill in the spoolss_AddDriverInfo3 struct */
1460 ZERO_STRUCT(info3);
1462 arch = cmd_spoolss_get_short_archi(argv[1]);
1463 if (!arch) {
1464 printf ("Error Unknown architechture [%s]\n", argv[1]);
1465 return WERR_INVALID_PARAM;
1468 set_drv_info_3_env(mem_ctx, &info3, arch);
1470 driver_args = talloc_strdup( mem_ctx, argv[2] );
1471 if (!init_drv_info_3_members(mem_ctx, &info3, driver_args ))
1473 printf ("Error Invalid parameter list - %s.\n", argv[2]);
1474 return WERR_INVALID_PARAM;
1477 /* if printer driver version specified, override the default version
1478 * used by the architecture. This allows installation of Windows
1479 * 2000 (version 3) printer drivers. */
1480 if (argc == 4)
1482 info3.version = atoi(argv[3]);
1486 info_ctr.level = level;
1487 info_ctr.info.info3 = &info3;
1489 status = rpccli_spoolss_AddPrinterDriver(cli, mem_ctx,
1490 cli->srv_name_slash,
1491 &info_ctr,
1492 &result);
1493 if (!NT_STATUS_IS_OK(status)) {
1494 return ntstatus_to_werror(status);
1496 if (W_ERROR_IS_OK(result)) {
1497 printf ("Printer Driver %s successfully installed.\n",
1498 info3.driver_name);
1501 return result;
1505 /****************************************************************************
1506 ****************************************************************************/
1508 static WERROR cmd_spoolss_addprinterex(struct rpc_pipe_client *cli,
1509 TALLOC_CTX *mem_ctx,
1510 int argc, const char **argv)
1512 WERROR result;
1513 struct spoolss_SetPrinterInfoCtr info_ctr;
1514 struct spoolss_SetPrinterInfo2 info2;
1516 /* parse the command arguments */
1517 if (argc != 5)
1519 printf ("Usage: %s <name> <shared name> <driver> <port>\n", argv[0]);
1520 return WERR_OK;
1523 /* Fill in the DRIVER_INFO_2 struct */
1524 ZERO_STRUCT(info2);
1526 info2.printername = argv[1];
1527 info2.drivername = argv[3];
1528 info2.sharename = argv[2];
1529 info2.portname = argv[4];
1530 info2.comment = "Created by rpcclient";
1531 info2.printprocessor = "winprint";
1532 info2.datatype = "RAW";
1533 info2.devmode = NULL;
1534 info2.secdesc = NULL;
1535 info2.attributes = PRINTER_ATTRIBUTE_SHARED;
1536 info2.priority = 0;
1537 info2.defaultpriority = 0;
1538 info2.starttime = 0;
1539 info2.untiltime = 0;
1541 /* These three fields must not be used by AddPrinter()
1542 as defined in the MS Platform SDK documentation..
1543 --jerry
1544 info2.status = 0;
1545 info2.cjobs = 0;
1546 info2.averageppm = 0;
1549 info_ctr.level = 2;
1550 info_ctr.info.info2 = &info2;
1552 result = rpccli_spoolss_addprinterex(cli, mem_ctx,
1553 &info_ctr);
1554 if (W_ERROR_IS_OK(result))
1555 printf ("Printer %s successfully installed.\n", argv[1]);
1557 return result;
1560 /****************************************************************************
1561 ****************************************************************************/
1563 static WERROR cmd_spoolss_setdriver(struct rpc_pipe_client *cli,
1564 TALLOC_CTX *mem_ctx,
1565 int argc, const char **argv)
1567 POLICY_HND pol;
1568 WERROR result;
1569 NTSTATUS status;
1570 uint32 level = 2;
1571 const char *printername;
1572 union spoolss_PrinterInfo info;
1573 struct spoolss_SetPrinterInfoCtr info_ctr;
1574 struct spoolss_DevmodeContainer devmode_ctr;
1575 struct sec_desc_buf secdesc_ctr;
1577 ZERO_STRUCT(devmode_ctr);
1578 ZERO_STRUCT(secdesc_ctr);
1580 /* parse the command arguments */
1581 if (argc != 3)
1583 printf ("Usage: %s <printer> <driver>\n", argv[0]);
1584 return WERR_OK;
1587 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
1589 /* Get a printer handle */
1591 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
1592 printername,
1593 PRINTER_ALL_ACCESS,
1594 &pol);
1595 if (!W_ERROR_IS_OK(result))
1596 goto done;
1598 /* Get printer info */
1600 result = rpccli_spoolss_getprinter(cli, mem_ctx,
1601 &pol,
1602 level,
1604 &info);
1605 if (!W_ERROR_IS_OK(result)) {
1606 printf ("Unable to retrieve printer information!\n");
1607 goto done;
1610 /* Set the printer driver */
1612 info.info2.drivername = argv[2];
1613 info.info2.devmode = NULL;
1614 info.info2.secdesc = NULL;
1616 info_ctr.level = 2;
1617 info_ctr.info.info2 = (struct spoolss_SetPrinterInfo2 *)&info.info2;
1619 status = rpccli_spoolss_SetPrinter(cli, mem_ctx,
1620 &pol,
1621 &info_ctr,
1622 &devmode_ctr,
1623 &secdesc_ctr,
1624 0, /* command */
1625 &result);
1626 if (!W_ERROR_IS_OK(result)) {
1627 printf("SetPrinter call failed!\n");
1628 goto done;;
1631 printf("Successfully set %s to driver %s.\n", argv[1], argv[2]);
1633 done:
1634 /* Cleanup */
1636 if (is_valid_policy_hnd(&pol))
1637 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &pol, NULL);
1639 return result;
1643 /****************************************************************************
1644 ****************************************************************************/
1646 static WERROR cmd_spoolss_deletedriverex(struct rpc_pipe_client *cli,
1647 TALLOC_CTX *mem_ctx,
1648 int argc, const char **argv)
1650 WERROR result, ret = WERR_UNKNOWN_PRINTER_DRIVER;
1651 NTSTATUS status;
1653 int i;
1654 int vers = -1;
1656 const char *arch = NULL;
1657 uint32_t delete_flags = 0;
1659 /* parse the command arguments */
1660 if (argc < 2 || argc > 4) {
1661 printf ("Usage: %s <driver> [arch] [version]\n", argv[0]);
1662 return WERR_OK;
1665 if (argc >= 3)
1666 arch = argv[2];
1667 if (argc == 4)
1668 vers = atoi (argv[3]);
1670 if (vers >= 0) {
1671 delete_flags |= DPD_DELETE_SPECIFIC_VERSION;
1674 /* delete the driver for all architectures */
1675 for (i=0; archi_table[i].long_archi; i++) {
1677 if (arch && !strequal( archi_table[i].long_archi, arch))
1678 continue;
1680 if (vers >= 0 && archi_table[i].version != vers)
1681 continue;
1683 /* make the call to remove the driver */
1684 status = rpccli_spoolss_DeletePrinterDriverEx(cli, mem_ctx,
1685 cli->srv_name_slash,
1686 archi_table[i].long_archi,
1687 argv[1],
1688 delete_flags,
1689 archi_table[i].version,
1690 &result);
1692 if ( !W_ERROR_IS_OK(result) )
1694 if ( !W_ERROR_EQUAL(result, WERR_UNKNOWN_PRINTER_DRIVER) ) {
1695 printf ("Failed to remove driver %s for arch [%s] (version: %d): %s\n",
1696 argv[1], archi_table[i].long_archi, archi_table[i].version, win_errstr(result));
1699 else
1701 printf ("Driver %s and files removed for arch [%s] (version: %d).\n", argv[1],
1702 archi_table[i].long_archi, archi_table[i].version);
1703 ret = WERR_OK;
1707 return ret;
1711 /****************************************************************************
1712 ****************************************************************************/
1714 static WERROR cmd_spoolss_deletedriver(struct rpc_pipe_client *cli,
1715 TALLOC_CTX *mem_ctx,
1716 int argc, const char **argv)
1718 WERROR result = WERR_OK;
1719 NTSTATUS status;
1720 int i;
1722 /* parse the command arguments */
1723 if (argc != 2) {
1724 printf ("Usage: %s <driver>\n", argv[0]);
1725 return WERR_OK;
1728 /* delete the driver for all architectures */
1729 for (i=0; archi_table[i].long_archi; i++) {
1730 /* make the call to remove the driver */
1731 status = rpccli_spoolss_DeletePrinterDriver(cli, mem_ctx,
1732 cli->srv_name_slash,
1733 archi_table[i].long_archi,
1734 argv[1],
1735 &result);
1736 if (!NT_STATUS_IS_OK(status)) {
1737 return result;
1739 if ( !W_ERROR_IS_OK(result) ) {
1740 if ( !W_ERROR_EQUAL(result, WERR_UNKNOWN_PRINTER_DRIVER) ) {
1741 printf ("Failed to remove driver %s for arch [%s] - error 0x%x!\n",
1742 argv[1], archi_table[i].long_archi,
1743 W_ERROR_V(result));
1745 } else {
1746 printf ("Driver %s removed for arch [%s].\n", argv[1],
1747 archi_table[i].long_archi);
1751 return result;
1754 /****************************************************************************
1755 ****************************************************************************/
1757 static WERROR cmd_spoolss_getprintprocdir(struct rpc_pipe_client *cli,
1758 TALLOC_CTX *mem_ctx,
1759 int argc, const char **argv)
1761 WERROR result;
1762 NTSTATUS status;
1763 const char *environment = SPOOLSS_ARCHITECTURE_NT_X86;
1764 DATA_BLOB buffer;
1765 uint32_t offered;
1766 union spoolss_PrintProcessorDirectoryInfo info;
1767 uint32_t needed;
1769 /* parse the command arguments */
1770 if (argc > 2) {
1771 printf ("Usage: %s [environment]\n", argv[0]);
1772 return WERR_OK;
1775 if (argc == 2) {
1776 environment = argv[1];
1779 status = rpccli_spoolss_GetPrintProcessorDirectory(cli, mem_ctx,
1780 cli->srv_name_slash,
1781 environment,
1783 NULL, /* buffer */
1784 0, /* offered */
1785 NULL, /* info */
1786 &needed,
1787 &result);
1788 if (W_ERROR_EQUAL(result, WERR_INSUFFICIENT_BUFFER)) {
1789 offered = needed;
1790 buffer = data_blob_talloc_zero(mem_ctx, needed);
1792 status = rpccli_spoolss_GetPrintProcessorDirectory(cli, mem_ctx,
1793 cli->srv_name_slash,
1794 environment,
1796 &buffer,
1797 offered,
1798 &info,
1799 &needed,
1800 &result);
1803 if (W_ERROR_IS_OK(result)) {
1804 printf("%s\n", info.info1.directory_name);
1807 return result;
1810 /****************************************************************************
1811 ****************************************************************************/
1813 static WERROR cmd_spoolss_addform(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
1814 int argc, const char **argv)
1816 POLICY_HND handle;
1817 WERROR werror;
1818 NTSTATUS status;
1819 const char *printername;
1820 union spoolss_AddFormInfo info;
1821 struct spoolss_AddFormInfo1 info1;
1822 struct spoolss_AddFormInfo2 info2;
1823 uint32_t level = 1;
1825 /* Parse the command arguments */
1827 if (argc < 3 || argc > 5) {
1828 printf ("Usage: %s <printer> <formname> [level]\n", argv[0]);
1829 return WERR_OK;
1832 /* Get a printer handle */
1834 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
1836 werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
1837 printername,
1838 PRINTER_ALL_ACCESS,
1839 &handle);
1840 if (!W_ERROR_IS_OK(werror))
1841 goto done;
1843 /* Dummy up some values for the form data */
1845 if (argc == 4) {
1846 level = atoi(argv[3]);
1849 switch (level) {
1850 case 1:
1851 info1.flags = FORM_USER;
1852 info1.form_name = argv[2];
1853 info1.size.width = 100;
1854 info1.size.height = 100;
1855 info1.area.left = 0;
1856 info1.area.top = 10;
1857 info1.area.right = 20;
1858 info1.area.bottom = 30;
1860 info.info1 = &info1;
1862 break;
1863 case 2:
1864 info2.flags = FORM_USER;
1865 info2.form_name = argv[2];
1866 info2.size.width = 100;
1867 info2.size.height = 100;
1868 info2.area.left = 0;
1869 info2.area.top = 10;
1870 info2.area.right = 20;
1871 info2.area.bottom = 30;
1872 info2.keyword = argv[2];
1873 info2.string_type = SPOOLSS_FORM_STRING_TYPE_NONE;
1874 info2.mui_dll = NULL;
1875 info2.ressource_id = 0;
1876 info2.display_name = argv[2];
1877 info2.lang_id = 0;
1879 info.info2 = &info2;
1881 break;
1884 /* Add the form */
1887 status = rpccli_spoolss_AddForm(cli, mem_ctx,
1888 &handle,
1889 level,
1890 info,
1891 &werror);
1893 done:
1894 if (is_valid_policy_hnd(&handle))
1895 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
1897 return werror;
1900 /****************************************************************************
1901 ****************************************************************************/
1903 static WERROR cmd_spoolss_setform(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
1904 int argc, const char **argv)
1906 POLICY_HND handle;
1907 WERROR werror;
1908 NTSTATUS status;
1909 const char *printername;
1910 union spoolss_AddFormInfo info;
1911 struct spoolss_AddFormInfo1 info1;
1913 /* Parse the command arguments */
1915 if (argc != 3) {
1916 printf ("Usage: %s <printer> <formname>\n", argv[0]);
1917 return WERR_OK;
1920 /* Get a printer handle */
1922 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
1924 werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
1925 printername,
1926 SEC_FLAG_MAXIMUM_ALLOWED,
1927 &handle);
1928 if (!W_ERROR_IS_OK(werror))
1929 goto done;
1931 /* Dummy up some values for the form data */
1933 info1.flags = FORM_PRINTER;
1934 info1.size.width = 100;
1935 info1.size.height = 100;
1936 info1.area.left = 0;
1937 info1.area.top = 1000;
1938 info1.area.right = 2000;
1939 info1.area.bottom = 3000;
1940 info1.form_name = argv[2];
1942 info.info1 = &info1;
1944 /* Set the form */
1946 status = rpccli_spoolss_SetForm(cli, mem_ctx,
1947 &handle,
1948 argv[2],
1950 info,
1951 &werror);
1953 done:
1954 if (is_valid_policy_hnd(&handle))
1955 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
1957 return werror;
1960 /****************************************************************************
1961 ****************************************************************************/
1963 static const char *get_form_flag(int form_flag)
1965 switch (form_flag) {
1966 case FORM_USER:
1967 return "FORM_USER";
1968 case FORM_BUILTIN:
1969 return "FORM_BUILTIN";
1970 case FORM_PRINTER:
1971 return "FORM_PRINTER";
1972 default:
1973 return "unknown";
1977 /****************************************************************************
1978 ****************************************************************************/
1980 static void display_form_info1(struct spoolss_FormInfo1 *r)
1982 printf("%s\n" \
1983 "\tflag: %s (%d)\n" \
1984 "\twidth: %d, length: %d\n" \
1985 "\tleft: %d, right: %d, top: %d, bottom: %d\n\n",
1986 r->form_name, get_form_flag(r->flags), r->flags,
1987 r->size.width, r->size.height,
1988 r->area.left, r->area.right,
1989 r->area.top, r->area.bottom);
1992 /****************************************************************************
1993 ****************************************************************************/
1995 static void display_form_info2(struct spoolss_FormInfo2 *r)
1997 printf("%s\n" \
1998 "\tflag: %s (%d)\n" \
1999 "\twidth: %d, length: %d\n" \
2000 "\tleft: %d, right: %d, top: %d, bottom: %d\n",
2001 r->form_name, get_form_flag(r->flags), r->flags,
2002 r->size.width, r->size.height,
2003 r->area.left, r->area.right,
2004 r->area.top, r->area.bottom);
2005 printf("\tkeyword: %s\n", r->keyword);
2006 printf("\tstring_type: 0x%08x\n", r->string_type);
2007 printf("\tmui_dll: %s\n", r->mui_dll);
2008 printf("\tressource_id: 0x%08x\n", r->ressource_id);
2009 printf("\tdisplay_name: %s\n", r->display_name);
2010 printf("\tlang_id: %d\n", r->lang_id);
2011 printf("\n");
2014 /****************************************************************************
2015 ****************************************************************************/
2017 static WERROR cmd_spoolss_getform(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
2018 int argc, const char **argv)
2020 POLICY_HND handle;
2021 WERROR werror;
2022 NTSTATUS status;
2023 const char *printername;
2024 DATA_BLOB buffer;
2025 uint32_t offered = 0;
2026 union spoolss_FormInfo info;
2027 uint32_t needed;
2028 uint32_t level = 1;
2030 /* Parse the command arguments */
2032 if (argc < 3 || argc > 5) {
2033 printf ("Usage: %s <printer> <formname> [level]\n", argv[0]);
2034 return WERR_OK;
2037 /* Get a printer handle */
2039 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2041 werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2042 printername,
2043 SEC_FLAG_MAXIMUM_ALLOWED,
2044 &handle);
2045 if (!W_ERROR_IS_OK(werror))
2046 goto done;
2048 if (argc == 4) {
2049 level = atoi(argv[3]);
2052 /* Get the form */
2054 status = rpccli_spoolss_GetForm(cli, mem_ctx,
2055 &handle,
2056 argv[2],
2057 level,
2058 NULL,
2059 offered,
2060 &info,
2061 &needed,
2062 &werror);
2063 if (W_ERROR_EQUAL(werror, WERR_INSUFFICIENT_BUFFER)) {
2064 buffer = data_blob_talloc_zero(mem_ctx, needed);
2065 offered = needed;
2066 status = rpccli_spoolss_GetForm(cli, mem_ctx,
2067 &handle,
2068 argv[2],
2069 level,
2070 &buffer,
2071 offered,
2072 &info,
2073 &needed,
2074 &werror);
2077 if (!NT_STATUS_IS_OK(status)) {
2078 return werror;
2081 switch (level) {
2082 case 1:
2083 display_form_info1(&info.info1);
2084 break;
2085 case 2:
2086 display_form_info2(&info.info2);
2087 break;
2090 done:
2091 if (is_valid_policy_hnd(&handle))
2092 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
2094 return werror;
2097 /****************************************************************************
2098 ****************************************************************************/
2100 static WERROR cmd_spoolss_deleteform(struct rpc_pipe_client *cli,
2101 TALLOC_CTX *mem_ctx, int argc,
2102 const char **argv)
2104 POLICY_HND handle;
2105 WERROR werror;
2106 NTSTATUS status;
2107 const char *printername;
2109 /* Parse the command arguments */
2111 if (argc != 3) {
2112 printf ("Usage: %s <printer> <formname>\n", argv[0]);
2113 return WERR_OK;
2116 /* Get a printer handle */
2118 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2120 werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2121 printername,
2122 SEC_FLAG_MAXIMUM_ALLOWED,
2123 &handle);
2124 if (!W_ERROR_IS_OK(werror))
2125 goto done;
2127 /* Delete the form */
2129 status = rpccli_spoolss_DeleteForm(cli, mem_ctx,
2130 &handle,
2131 argv[2],
2132 &werror);
2133 if (!NT_STATUS_IS_OK(status)) {
2134 return ntstatus_to_werror(status);
2137 done:
2138 if (is_valid_policy_hnd(&handle))
2139 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
2141 return werror;
2144 /****************************************************************************
2145 ****************************************************************************/
2147 static WERROR cmd_spoolss_enum_forms(struct rpc_pipe_client *cli,
2148 TALLOC_CTX *mem_ctx, int argc,
2149 const char **argv)
2151 POLICY_HND handle;
2152 WERROR werror;
2153 const char *printername;
2154 uint32 num_forms, level = 1, i;
2155 union spoolss_FormInfo *forms;
2157 /* Parse the command arguments */
2159 if (argc < 2 || argc > 4) {
2160 printf ("Usage: %s <printer> [level]\n", argv[0]);
2161 return WERR_OK;
2164 /* Get a printer handle */
2166 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2168 werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2169 printername,
2170 SEC_FLAG_MAXIMUM_ALLOWED,
2171 &handle);
2172 if (!W_ERROR_IS_OK(werror))
2173 goto done;
2175 if (argc == 3) {
2176 level = atoi(argv[2]);
2179 /* Enumerate forms */
2181 werror = rpccli_spoolss_enumforms(cli, mem_ctx,
2182 &handle,
2183 level,
2185 &num_forms,
2186 &forms);
2188 if (!W_ERROR_IS_OK(werror))
2189 goto done;
2191 /* Display output */
2193 for (i = 0; i < num_forms; i++) {
2194 switch (level) {
2195 case 1:
2196 display_form_info1(&forms[i].info1);
2197 break;
2198 case 2:
2199 display_form_info2(&forms[i].info2);
2200 break;
2204 done:
2205 if (is_valid_policy_hnd(&handle))
2206 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
2208 return werror;
2211 /****************************************************************************
2212 ****************************************************************************/
2214 static WERROR cmd_spoolss_setprinterdata(struct rpc_pipe_client *cli,
2215 TALLOC_CTX *mem_ctx,
2216 int argc, const char **argv)
2218 WERROR result;
2219 const char *printername;
2220 POLICY_HND pol;
2221 union spoolss_PrinterInfo info;
2222 REGISTRY_VALUE value;
2223 TALLOC_CTX *tmp_ctx = talloc_stackframe();
2225 /* parse the command arguments */
2226 if (argc < 5) {
2227 printf ("Usage: %s <printer> <string|binary|dword|multistring>"
2228 " <value> <data>\n",
2229 argv[0]);
2230 result = WERR_INVALID_PARAM;
2231 goto done;
2234 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2236 value.type = REG_NONE;
2238 if (strequal(argv[2], "string")) {
2239 value.type = REG_SZ;
2242 if (strequal(argv[2], "binary")) {
2243 value.type = REG_BINARY;
2246 if (strequal(argv[2], "dword")) {
2247 value.type = REG_DWORD;
2250 if (strequal(argv[2], "multistring")) {
2251 value.type = REG_MULTI_SZ;
2254 if (value.type == REG_NONE) {
2255 printf("Unknown data type: %s\n", argv[2]);
2256 result = WERR_INVALID_PARAM;
2257 goto done;
2260 /* get a printer handle */
2262 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2263 printername,
2264 SEC_FLAG_MAXIMUM_ALLOWED,
2265 &pol);
2266 if (!W_ERROR_IS_OK(result))
2267 goto done;
2269 result = rpccli_spoolss_getprinter(cli, mem_ctx,
2270 &pol,
2273 &info);
2274 if (!W_ERROR_IS_OK(result))
2275 goto done;
2277 printf("%s\n", current_timestring(tmp_ctx, True));
2278 printf("\tchange_id (before set)\t:[0x%x]\n", info.info0.change_id);
2280 /* Set the printer data */
2282 fstrcpy(value.valuename, argv[3]);
2284 switch (value.type) {
2285 case REG_SZ: {
2286 UNISTR2 data;
2287 init_unistr2(&data, argv[4], UNI_STR_TERMINATE);
2288 value.size = data.uni_str_len * 2;
2289 if (value.size) {
2290 value.data_p = (uint8 *)TALLOC_MEMDUP(mem_ctx, data.buffer,
2291 value.size);
2292 } else {
2293 value.data_p = NULL;
2295 break;
2297 case REG_DWORD: {
2298 uint32 data = strtoul(argv[4], NULL, 10);
2299 value.size = sizeof(data);
2300 if (sizeof(data)) {
2301 value.data_p = (uint8 *)TALLOC_MEMDUP(mem_ctx, &data,
2302 sizeof(data));
2303 } else {
2304 value.data_p = NULL;
2306 break;
2308 case REG_BINARY: {
2309 DATA_BLOB data = strhex_to_data_blob(mem_ctx, argv[4]);
2310 value.data_p = data.data;
2311 value.size = data.length;
2312 break;
2314 case REG_MULTI_SZ: {
2315 int i;
2316 size_t len = 0;
2317 char *p;
2319 for (i=4; i<argc; i++) {
2320 if (strcmp(argv[i], "NULL") == 0) {
2321 argv[i] = "";
2323 len += strlen(argv[i])+1;
2326 value.size = len*2;
2327 value.data_p = TALLOC_ARRAY(mem_ctx, unsigned char, value.size);
2328 if (value.data_p == NULL) {
2329 result = WERR_NOMEM;
2330 goto done;
2333 p = (char *)value.data_p;
2334 len = value.size;
2335 for (i=4; i<argc; i++) {
2336 size_t l = (strlen(argv[i])+1)*2;
2337 rpcstr_push(p, argv[i], len, STR_TERMINATE);
2338 p += l;
2339 len -= l;
2341 SMB_ASSERT(len == 0);
2342 break;
2344 default:
2345 printf("Unknown data type: %s\n", argv[2]);
2346 result = WERR_INVALID_PARAM;
2347 goto done;
2350 result = rpccli_spoolss_setprinterdata(cli, mem_ctx, &pol, &value);
2352 if (!W_ERROR_IS_OK(result)) {
2353 printf ("Unable to set [%s=%s]!\n", argv[3], argv[4]);
2354 goto done;
2356 printf("\tSetPrinterData succeeded [%s: %s]\n", argv[3], argv[4]);
2358 result = rpccli_spoolss_getprinter(cli, mem_ctx,
2359 &pol,
2362 &info);
2363 if (!W_ERROR_IS_OK(result))
2364 goto done;
2366 printf("%s\n", current_timestring(tmp_ctx, True));
2367 printf("\tchange_id (after set)\t:[0x%x]\n", info.info0.change_id);
2369 done:
2370 /* cleanup */
2371 TALLOC_FREE(tmp_ctx);
2372 if (is_valid_policy_hnd(&pol))
2373 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &pol, NULL);
2375 return result;
2378 /****************************************************************************
2379 ****************************************************************************/
2381 static void display_job_info_1(JOB_INFO_1 *job)
2383 fstring username = "", document = "", text_status = "";
2385 rpcstr_pull(username, job->username.buffer,
2386 sizeof(username), -1, STR_TERMINATE);
2388 rpcstr_pull(document, job->document.buffer,
2389 sizeof(document), -1, STR_TERMINATE);
2391 rpcstr_pull(text_status, job->text_status.buffer,
2392 sizeof(text_status), -1, STR_TERMINATE);
2394 printf("%d: jobid[%d]: %s %s %s %d/%d pages\n", job->position, job->jobid,
2395 username, document, text_status, job->pagesprinted,
2396 job->totalpages);
2399 /****************************************************************************
2400 ****************************************************************************/
2402 static void display_job_info_2(JOB_INFO_2 *job)
2404 fstring username = "", document = "", text_status = "";
2406 rpcstr_pull(username, job->username.buffer,
2407 sizeof(username), -1, STR_TERMINATE);
2409 rpcstr_pull(document, job->document.buffer,
2410 sizeof(document), -1, STR_TERMINATE);
2412 rpcstr_pull(text_status, job->text_status.buffer,
2413 sizeof(text_status), -1, STR_TERMINATE);
2415 printf("%d: jobid[%d]: %s %s %s %d/%d pages, %d bytes\n", job->position, job->jobid,
2416 username, document, text_status, job->pagesprinted,
2417 job->totalpages, job->size);
2420 /****************************************************************************
2421 ****************************************************************************/
2423 static void display_job_info1(struct spoolss_JobInfo1 *r)
2425 printf("%d: jobid[%d]: %s %s %s %d/%d pages\n", r->position, r->job_id,
2426 r->user_name, r->document_name, r->text_status, r->pages_printed,
2427 r->total_pages);
2430 /****************************************************************************
2431 ****************************************************************************/
2433 static void display_job_info2(struct spoolss_JobInfo2 *r)
2435 printf("%d: jobid[%d]: %s %s %s %d/%d pages, %d bytes\n",
2436 r->position, r->job_id,
2437 r->user_name, r->document_name, r->text_status, r->pages_printed,
2438 r->total_pages, r->size);
2441 /****************************************************************************
2442 ****************************************************************************/
2444 static void display_job_info3(struct spoolss_JobInfo3 *r)
2446 printf("jobid[%d], next_jobid[%d]\n",
2447 r->job_id, r->next_job_id);
2450 /****************************************************************************
2451 ****************************************************************************/
2453 static void display_job_info4(struct spoolss_JobInfo4 *r)
2455 printf("%d: jobid[%d]: %s %s %s %d/%d pages, %d/%d bytes\n",
2456 r->position, r->job_id,
2457 r->user_name, r->document_name, r->text_status, r->pages_printed,
2458 r->total_pages, r->size, r->size_high);
2461 /****************************************************************************
2462 ****************************************************************************/
2464 static WERROR cmd_spoolss_enum_jobs(struct rpc_pipe_client *cli,
2465 TALLOC_CTX *mem_ctx, int argc,
2466 const char **argv)
2468 WERROR result;
2469 uint32 level = 1, num_jobs, i;
2470 const char *printername;
2471 POLICY_HND hnd;
2472 JOB_INFO_CTR ctr;
2474 if (argc < 2 || argc > 3) {
2475 printf("Usage: %s printername [level]\n", argv[0]);
2476 return WERR_OK;
2479 if (argc == 3)
2480 level = atoi(argv[2]);
2482 /* Open printer handle */
2484 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2486 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2487 printername,
2488 SEC_FLAG_MAXIMUM_ALLOWED,
2489 &hnd);
2490 if (!W_ERROR_IS_OK(result))
2491 goto done;
2493 /* Enumerate ports */
2495 result = rpccli_spoolss_enumjobs(cli, mem_ctx, &hnd, level, 0, 1000,
2496 &num_jobs, &ctr);
2498 if (!W_ERROR_IS_OK(result))
2499 goto done;
2501 for (i = 0; i < num_jobs; i++) {
2502 switch(level) {
2503 case 1:
2504 display_job_info_1(&ctr.job.job_info_1[i]);
2505 break;
2506 case 2:
2507 display_job_info_2(&ctr.job.job_info_2[i]);
2508 break;
2509 default:
2510 d_printf("unknown info level %d\n", level);
2511 break;
2515 done:
2516 if (is_valid_policy_hnd(&hnd))
2517 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &hnd, NULL);
2519 return result;
2522 /****************************************************************************
2523 ****************************************************************************/
2525 static WERROR cmd_spoolss_get_job(struct rpc_pipe_client *cli,
2526 TALLOC_CTX *mem_ctx, int argc,
2527 const char **argv)
2529 WERROR result;
2530 const char *printername;
2531 struct policy_handle hnd;
2532 uint32_t job_id;
2533 uint32_t level = 1;
2534 union spoolss_JobInfo info;
2536 if (argc < 3 || argc > 4) {
2537 printf("Usage: %s printername job_id [level]\n", argv[0]);
2538 return WERR_OK;
2541 job_id = atoi(argv[2]);
2543 if (argc == 4) {
2544 level = atoi(argv[3]);
2547 /* Open printer handle */
2549 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2551 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2552 printername,
2553 SEC_FLAG_MAXIMUM_ALLOWED,
2554 &hnd);
2555 if (!W_ERROR_IS_OK(result)) {
2556 goto done;
2559 /* Enumerate ports */
2561 result = rpccli_spoolss_getjob(cli, mem_ctx,
2562 &hnd,
2563 job_id,
2564 level,
2566 &info);
2568 if (!W_ERROR_IS_OK(result)) {
2569 goto done;
2572 switch (level) {
2573 case 1:
2574 display_job_info1(&info.info1);
2575 break;
2576 case 2:
2577 display_job_info2(&info.info2);
2578 break;
2579 case 3:
2580 display_job_info3(&info.info3);
2581 break;
2582 case 4:
2583 display_job_info4(&info.info4);
2584 break;
2585 default:
2586 d_printf("unknown info level %d\n", level);
2587 break;
2590 done:
2591 if (is_valid_policy_hnd(&hnd)) {
2592 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &hnd, NULL);
2595 return result;
2599 /****************************************************************************
2600 ****************************************************************************/
2602 static WERROR cmd_spoolss_enum_data( struct rpc_pipe_client *cli,
2603 TALLOC_CTX *mem_ctx, int argc,
2604 const char **argv)
2606 WERROR result;
2607 uint32 i=0, val_needed, data_needed;
2608 const char *printername;
2609 POLICY_HND hnd;
2611 if (argc != 2) {
2612 printf("Usage: %s printername\n", argv[0]);
2613 return WERR_OK;
2616 /* Open printer handle */
2618 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2620 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2621 printername,
2622 SEC_FLAG_MAXIMUM_ALLOWED,
2623 &hnd);
2624 if (!W_ERROR_IS_OK(result))
2625 goto done;
2627 /* Enumerate data */
2629 result = rpccli_spoolss_enumprinterdata(cli, mem_ctx, &hnd, i, 0, 0,
2630 &val_needed, &data_needed,
2631 NULL);
2632 while (W_ERROR_IS_OK(result)) {
2633 REGISTRY_VALUE value;
2634 result = rpccli_spoolss_enumprinterdata(
2635 cli, mem_ctx, &hnd, i++, val_needed,
2636 data_needed, 0, 0, &value);
2637 if (W_ERROR_IS_OK(result))
2638 display_reg_value(value);
2640 if (W_ERROR_V(result) == ERRnomoreitems)
2641 result = W_ERROR(ERRsuccess);
2643 done:
2644 if (is_valid_policy_hnd(&hnd))
2645 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &hnd, NULL);
2647 return result;
2650 /****************************************************************************
2651 ****************************************************************************/
2653 static WERROR cmd_spoolss_enum_data_ex( struct rpc_pipe_client *cli,
2654 TALLOC_CTX *mem_ctx, int argc,
2655 const char **argv)
2657 WERROR result;
2658 uint32 i;
2659 const char *printername;
2660 const char *keyname = NULL;
2661 POLICY_HND hnd;
2662 REGVAL_CTR *ctr = NULL;
2664 if (argc != 3) {
2665 printf("Usage: %s printername <keyname>\n", argv[0]);
2666 return WERR_OK;
2669 keyname = argv[2];
2671 /* Open printer handle */
2673 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2675 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2676 printername,
2677 SEC_FLAG_MAXIMUM_ALLOWED,
2678 &hnd);
2679 if (!W_ERROR_IS_OK(result))
2680 goto done;
2682 /* Enumerate subkeys */
2684 if ( !(ctr = TALLOC_ZERO_P( mem_ctx, REGVAL_CTR )) )
2685 return WERR_NOMEM;
2687 result = rpccli_spoolss_enumprinterdataex(cli, mem_ctx, &hnd, keyname, ctr);
2689 if (!W_ERROR_IS_OK(result))
2690 goto done;
2692 for (i=0; i < ctr->num_values; i++) {
2693 display_reg_value(*(ctr->values[i]));
2696 TALLOC_FREE( ctr );
2698 done:
2699 if (is_valid_policy_hnd(&hnd))
2700 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &hnd, NULL);
2702 return result;
2705 /****************************************************************************
2706 ****************************************************************************/
2708 static WERROR cmd_spoolss_enum_printerkey( struct rpc_pipe_client *cli,
2709 TALLOC_CTX *mem_ctx, int argc,
2710 const char **argv)
2712 WERROR result;
2713 const char *printername;
2714 const char *keyname = NULL;
2715 POLICY_HND hnd;
2716 uint16 *keylist = NULL, *curkey;
2718 if (argc < 2 || argc > 3) {
2719 printf("Usage: %s printername [keyname]\n", argv[0]);
2720 return WERR_OK;
2723 if (argc == 3)
2724 keyname = argv[2];
2725 else
2726 keyname = "";
2728 /* Open printer handle */
2730 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2732 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2733 printername,
2734 SEC_FLAG_MAXIMUM_ALLOWED,
2735 &hnd);
2736 if (!W_ERROR_IS_OK(result))
2737 goto done;
2739 /* Enumerate subkeys */
2741 result = rpccli_spoolss_enumprinterkey(cli, mem_ctx, &hnd, keyname, &keylist, NULL);
2743 if (!W_ERROR_IS_OK(result))
2744 goto done;
2746 curkey = keylist;
2747 while (*curkey != 0) {
2748 char *subkey = NULL;
2749 rpcstr_pull_talloc(mem_ctx, &subkey, curkey, -1,
2750 STR_TERMINATE);
2751 if (!subkey) {
2752 break;
2754 printf("%s\n", subkey);
2755 curkey += strlen(subkey) + 1;
2758 done:
2760 SAFE_FREE(keylist);
2762 if (is_valid_policy_hnd(&hnd))
2763 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &hnd, NULL);
2765 return result;
2768 /****************************************************************************
2769 ****************************************************************************/
2771 static WERROR cmd_spoolss_rffpcnex(struct rpc_pipe_client *cli,
2772 TALLOC_CTX *mem_ctx, int argc,
2773 const char **argv)
2775 const char *printername;
2776 const char *clientname;
2777 POLICY_HND hnd;
2778 WERROR result;
2779 NTSTATUS status;
2780 struct spoolss_NotifyOption option;
2782 if (argc != 2) {
2783 printf("Usage: %s printername\n", argv[0]);
2784 result = WERR_OK;
2785 goto done;
2788 /* Open printer */
2790 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2792 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2793 printername,
2794 SEC_FLAG_MAXIMUM_ALLOWED,
2795 &hnd);
2796 if (!W_ERROR_IS_OK(result)) {
2797 printf("Error opening %s\n", argv[1]);
2798 goto done;
2801 /* Create spool options */
2803 option.version = 2;
2804 option.count = 2;
2806 option.types = talloc_array(mem_ctx, struct spoolss_NotifyOptionType, 2);
2807 if (option.types == NULL) {
2808 result = WERR_NOMEM;
2809 goto done;
2812 option.types[0].type = PRINTER_NOTIFY_TYPE;
2813 option.types[0].count = 1;
2814 option.types[0].fields = talloc_array(mem_ctx, enum spoolss_Field, 1);
2815 if (option.types[0].fields == NULL) {
2816 result = WERR_NOMEM;
2817 goto done;
2819 option.types[0].fields[0] = PRINTER_NOTIFY_SERVER_NAME;
2821 option.types[1].type = JOB_NOTIFY_TYPE;
2822 option.types[1].count = 1;
2823 option.types[1].fields = talloc_array(mem_ctx, enum spoolss_Field, 1);
2824 if (option.types[1].fields == NULL) {
2825 result = WERR_NOMEM;
2826 goto done;
2828 option.types[1].fields[0] = JOB_NOTIFY_PRINTER_NAME;
2830 clientname = talloc_asprintf(mem_ctx, "\\\\%s", global_myname());
2831 if (!clientname) {
2832 result = WERR_NOMEM;
2833 goto done;
2836 /* Send rffpcnex */
2838 status = rpccli_spoolss_RemoteFindFirstPrinterChangeNotifyEx(cli, mem_ctx,
2839 &hnd,
2842 clientname,
2843 123,
2844 &option,
2845 &result);
2846 if (!W_ERROR_IS_OK(result)) {
2847 printf("Error rffpcnex %s\n", argv[1]);
2848 goto done;
2851 done:
2852 if (is_valid_policy_hnd(&hnd))
2853 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &hnd, NULL);
2855 return result;
2858 /****************************************************************************
2859 ****************************************************************************/
2861 static bool compare_printer( struct rpc_pipe_client *cli1, POLICY_HND *hnd1,
2862 struct rpc_pipe_client *cli2, POLICY_HND *hnd2 )
2864 union spoolss_PrinterInfo info1, info2;
2865 WERROR werror;
2866 TALLOC_CTX *mem_ctx = talloc_init("compare_printer");
2868 printf("Retrieving printer propertiesfor %s...", cli1->desthost);
2869 werror = rpccli_spoolss_getprinter(cli1, mem_ctx,
2870 hnd1,
2873 &info1);
2874 if ( !W_ERROR_IS_OK(werror) ) {
2875 printf("failed (%s)\n", win_errstr(werror));
2876 talloc_destroy(mem_ctx);
2877 return False;
2879 printf("ok\n");
2881 printf("Retrieving printer properties for %s...", cli2->desthost);
2882 werror = rpccli_spoolss_getprinter(cli2, mem_ctx,
2883 hnd2,
2886 &info2);
2887 if ( !W_ERROR_IS_OK(werror) ) {
2888 printf("failed (%s)\n", win_errstr(werror));
2889 talloc_destroy(mem_ctx);
2890 return False;
2892 printf("ok\n");
2894 talloc_destroy(mem_ctx);
2896 return True;
2899 /****************************************************************************
2900 ****************************************************************************/
2902 static bool compare_printer_secdesc( struct rpc_pipe_client *cli1, POLICY_HND *hnd1,
2903 struct rpc_pipe_client *cli2, POLICY_HND *hnd2 )
2905 union spoolss_PrinterInfo info1, info2;
2906 WERROR werror;
2907 TALLOC_CTX *mem_ctx = talloc_init("compare_printer_secdesc");
2908 SEC_DESC *sd1, *sd2;
2909 bool result = True;
2912 printf("Retrieving printer security for %s...", cli1->desthost);
2913 werror = rpccli_spoolss_getprinter(cli1, mem_ctx,
2914 hnd1,
2917 &info1);
2918 if ( !W_ERROR_IS_OK(werror) ) {
2919 printf("failed (%s)\n", win_errstr(werror));
2920 result = False;
2921 goto done;
2923 printf("ok\n");
2925 printf("Retrieving printer security for %s...", cli2->desthost);
2926 werror = rpccli_spoolss_getprinter(cli2, mem_ctx,
2927 hnd2,
2930 &info2);
2931 if ( !W_ERROR_IS_OK(werror) ) {
2932 printf("failed (%s)\n", win_errstr(werror));
2933 result = False;
2934 goto done;
2936 printf("ok\n");
2939 printf("++ ");
2941 sd1 = info1.info3.secdesc;
2942 sd2 = info2.info3.secdesc;
2944 if ( (sd1 != sd2) && ( !sd1 || !sd2 ) ) {
2945 printf("NULL secdesc!\n");
2946 result = False;
2947 goto done;
2950 if (!sec_desc_equal( sd1, sd2 ) ) {
2951 printf("Security Descriptors *not* equal!\n");
2952 result = False;
2953 goto done;
2956 printf("Security descriptors match\n");
2958 done:
2959 talloc_destroy(mem_ctx);
2960 return result;
2964 /****************************************************************************
2965 ****************************************************************************/
2967 extern struct user_auth_info *rpcclient_auth_info;
2969 static WERROR cmd_spoolss_printercmp(struct rpc_pipe_client *cli,
2970 TALLOC_CTX *mem_ctx, int argc,
2971 const char **argv)
2973 const char *printername;
2974 char *printername_path = NULL;
2975 struct cli_state *cli_server2 = NULL;
2976 struct rpc_pipe_client *cli2 = NULL;
2977 POLICY_HND hPrinter1, hPrinter2;
2978 NTSTATUS nt_status;
2979 WERROR werror;
2981 if ( argc != 3 ) {
2982 printf("Usage: %s <printer> <server>\n", argv[0]);
2983 return WERR_OK;
2986 printername = argv[1];
2988 /* first get the connection to the remote server */
2990 nt_status = cli_full_connection(&cli_server2, global_myname(), argv[2],
2991 NULL, 0,
2992 "IPC$", "IPC",
2993 get_cmdline_auth_info_username(rpcclient_auth_info),
2994 lp_workgroup(),
2995 get_cmdline_auth_info_password(rpcclient_auth_info),
2996 get_cmdline_auth_info_use_kerberos(rpcclient_auth_info) ? CLI_FULL_CONNECTION_USE_KERBEROS : 0,
2997 get_cmdline_auth_info_signing_state(rpcclient_auth_info), NULL);
2999 if ( !NT_STATUS_IS_OK(nt_status) )
3000 return WERR_GENERAL_FAILURE;
3002 nt_status = cli_rpc_pipe_open_noauth(cli_server2, &syntax_spoolss,
3003 &cli2);
3004 if (!NT_STATUS_IS_OK(nt_status)) {
3005 printf("failed to open spoolss pipe on server %s (%s)\n",
3006 argv[2], nt_errstr(nt_status));
3007 return WERR_GENERAL_FAILURE;
3010 /* now open up both printers */
3012 RPCCLIENT_PRINTERNAME(printername_path, cli, printername);
3014 printf("Opening %s...", printername_path);
3016 werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
3017 printername_path,
3018 PRINTER_ALL_ACCESS,
3019 &hPrinter1);
3020 if ( !W_ERROR_IS_OK(werror) ) {
3021 printf("failed (%s)\n", win_errstr(werror));
3022 goto done;
3024 printf("ok\n");
3026 RPCCLIENT_PRINTERNAME(printername_path, cli2, printername);
3028 printf("Opening %s...", printername_path);
3029 werror = rpccli_spoolss_openprinter_ex(cli2, mem_ctx,
3030 printername_path,
3031 PRINTER_ALL_ACCESS,
3032 &hPrinter2);
3033 if ( !W_ERROR_IS_OK(werror) ) {
3034 printf("failed (%s)\n", win_errstr(werror));
3035 goto done;
3037 printf("ok\n");
3039 compare_printer( cli, &hPrinter1, cli2, &hPrinter2 );
3040 compare_printer_secdesc( cli, &hPrinter1, cli2, &hPrinter2 );
3041 #if 0
3042 compare_printerdata( cli_server1, &hPrinter1, cli_server2, &hPrinter2 );
3043 #endif
3046 done:
3047 /* cleanup */
3049 printf("Closing printers...");
3050 rpccli_spoolss_ClosePrinter( cli, mem_ctx, &hPrinter1, NULL );
3051 rpccli_spoolss_ClosePrinter( cli2, mem_ctx, &hPrinter2, NULL );
3052 printf("ok\n");
3054 /* close the second remote connection */
3056 cli_shutdown( cli_server2 );
3057 return WERR_OK;
3060 /* List of commands exported by this module */
3061 struct cmd_set spoolss_commands[] = {
3063 { "SPOOLSS" },
3065 { "adddriver", RPC_RTYPE_WERROR, NULL, cmd_spoolss_addprinterdriver, &syntax_spoolss, NULL, "Add a print driver", "" },
3066 { "addprinter", RPC_RTYPE_WERROR, NULL, cmd_spoolss_addprinterex, &syntax_spoolss, NULL, "Add a printer", "" },
3067 { "deldriver", RPC_RTYPE_WERROR, NULL, cmd_spoolss_deletedriver, &syntax_spoolss, NULL, "Delete a printer driver", "" },
3068 { "deldriverex", RPC_RTYPE_WERROR, NULL, cmd_spoolss_deletedriverex, &syntax_spoolss, NULL, "Delete a printer driver with files", "" },
3069 { "enumdata", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_data, &syntax_spoolss, NULL, "Enumerate printer data", "" },
3070 { "enumdataex", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_data_ex, &syntax_spoolss, NULL, "Enumerate printer data for a key", "" },
3071 { "enumkey", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_printerkey, &syntax_spoolss, NULL, "Enumerate printer keys", "" },
3072 { "enumjobs", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_jobs, &syntax_spoolss, NULL, "Enumerate print jobs", "" },
3073 { "getjob", RPC_RTYPE_WERROR, NULL, cmd_spoolss_get_job, &syntax_spoolss, NULL, "Get print job", "" },
3074 { "enumports", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_ports, &syntax_spoolss, NULL, "Enumerate printer ports", "" },
3075 { "enumdrivers", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_drivers, &syntax_spoolss, NULL, "Enumerate installed printer drivers", "" },
3076 { "enumprinters", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_printers, &syntax_spoolss, NULL, "Enumerate printers", "" },
3077 { "getdata", RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprinterdata, &syntax_spoolss, NULL, "Get print driver data", "" },
3078 { "getdataex", RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprinterdataex, &syntax_spoolss, NULL, "Get printer driver data with keyname", ""},
3079 { "getdriver", RPC_RTYPE_WERROR, NULL, cmd_spoolss_getdriver, &syntax_spoolss, NULL, "Get print driver information", "" },
3080 { "getdriverdir", RPC_RTYPE_WERROR, NULL, cmd_spoolss_getdriverdir, &syntax_spoolss, NULL, "Get print driver upload directory", "" },
3081 { "getprinter", RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprinter, &syntax_spoolss, NULL, "Get printer info", "" },
3082 { "openprinter", RPC_RTYPE_WERROR, NULL, cmd_spoolss_open_printer_ex, &syntax_spoolss, NULL, "Open printer handle", "" },
3083 { "setdriver", RPC_RTYPE_WERROR, NULL, cmd_spoolss_setdriver, &syntax_spoolss, NULL, "Set printer driver", "" },
3084 { "getprintprocdir", RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprintprocdir, &syntax_spoolss, NULL, "Get print processor directory", "" },
3085 { "addform", RPC_RTYPE_WERROR, NULL, cmd_spoolss_addform, &syntax_spoolss, NULL, "Add form", "" },
3086 { "setform", RPC_RTYPE_WERROR, NULL, cmd_spoolss_setform, &syntax_spoolss, NULL, "Set form", "" },
3087 { "getform", RPC_RTYPE_WERROR, NULL, cmd_spoolss_getform, &syntax_spoolss, NULL, "Get form", "" },
3088 { "deleteform", RPC_RTYPE_WERROR, NULL, cmd_spoolss_deleteform, &syntax_spoolss, NULL, "Delete form", "" },
3089 { "enumforms", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_forms, &syntax_spoolss, NULL, "Enumerate forms", "" },
3090 { "setprinter", RPC_RTYPE_WERROR, NULL, cmd_spoolss_setprinter, &syntax_spoolss, NULL, "Set printer comment", "" },
3091 { "setprintername", RPC_RTYPE_WERROR, NULL, cmd_spoolss_setprintername, &syntax_spoolss, NULL, "Set printername", "" },
3092 { "setprinterdata", RPC_RTYPE_WERROR, NULL, cmd_spoolss_setprinterdata, &syntax_spoolss, NULL, "Set REG_SZ printer data", "" },
3093 { "rffpcnex", RPC_RTYPE_WERROR, NULL, cmd_spoolss_rffpcnex, &syntax_spoolss, NULL, "Rffpcnex test", "" },
3094 { "printercmp", RPC_RTYPE_WERROR, NULL, cmd_spoolss_printercmp, &syntax_spoolss, NULL, "Printer comparison test", "" },
3096 { NULL }