r23779: Change from v2 or later to v3 or later.
[kai/samba.git] / source3 / rpcclient / cmd_spoolss.c
1 /*
2    Unix SMB/CIFS implementation.
3    RPC pipe client
4
5    Copyright (C) Gerald Carter                2001-2005
6    Copyright (C) Tim Potter                        2000
7    Copyright (C) Andrew Tridgell              1992-1999
8    Copyright (C) Luke Kenneth Casson Leighton 1996-1999
9  
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, write to the Free Software
22    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25 #include "includes.h"
26 #include "rpcclient.h"
27
28 struct table_node {
29         const char      *long_archi;
30         const char      *short_archi;
31         int     version;
32 };
33  
34 /* The version int is used by getdrivers.  Note that
35    all architecture strings that support mutliple
36    versions must be grouped together since enumdrivers
37    uses this property to prevent issuing multiple 
38    enumdriver calls for the same arch */
39
40
41 static const struct table_node archi_table[]= {
42
43         {"Windows 4.0",          "WIN40",       0 },
44         {"Windows NT x86",       "W32X86",      2 },
45         {"Windows NT x86",       "W32X86",      3 },
46         {"Windows NT R4000",     "W32MIPS",     2 },
47         {"Windows NT Alpha_AXP", "W32ALPHA",    2 },
48         {"Windows NT PowerPC",   "W32PPC",      2 },
49         {"Windows IA64",         "IA64",        3 },
50         {"Windows x64",          "x64",         3 },
51         {NULL,                   "",            -1 }
52 };
53
54 /**
55  * @file
56  *
57  * rpcclient module for SPOOLSS rpc pipe.
58  *
59  * This generally just parses and checks command lines, and then calls
60  * a cli_spoolss function.
61  **/
62
63 /****************************************************************************
64  function to do the mapping between the long architecture name and
65  the short one.
66 ****************************************************************************/
67
68 static const char *cmd_spoolss_get_short_archi(const char *long_archi)
69 {
70         int i=-1;
71
72         DEBUG(107,("Getting architecture dependant directory\n"));
73         do {
74                 i++;
75         } while ( (archi_table[i].long_archi!=NULL ) &&
76                   StrCaseCmp(long_archi, archi_table[i].long_archi) );
77
78         if (archi_table[i].long_archi==NULL) {
79                 DEBUGADD(10,("Unknown architecture [%s] !\n", long_archi));
80                 return NULL;
81         }
82
83         /* this might be client code - but shouldn't this be an fstrcpy etc? */
84
85
86         DEBUGADD(108,("index: [%d]\n", i));
87         DEBUGADD(108,("long architecture: [%s]\n", archi_table[i].long_archi));
88         DEBUGADD(108,("short architecture: [%s]\n", archi_table[i].short_archi));
89
90         return archi_table[i].short_archi;
91 }
92
93 /****************************************************************************
94 ****************************************************************************/
95
96 static WERROR cmd_spoolss_open_printer_ex(struct rpc_pipe_client *cli, 
97                                             TALLOC_CTX *mem_ctx,
98                                             int argc, const char **argv)
99 {
100         WERROR          werror;
101         fstring         printername;
102         fstring         servername, user;
103         POLICY_HND      hnd;
104         
105         if (argc != 2) {
106                 printf("Usage: %s <printername>\n", argv[0]);
107                 return WERR_OK;
108         }
109         
110         if (!cli)
111             return WERR_GENERAL_FAILURE;
112
113         slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->cli->desthost);
114         strupper_m(servername);
115         fstrcpy(user, cli->user_name);
116         fstrcpy(printername, argv[1]);
117
118         /* Open the printer handle */
119
120         werror = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername, 
121                                              "", PRINTER_ALL_ACCESS, 
122                                              servername, user, &hnd);
123
124         if (W_ERROR_IS_OK(werror)) {
125                 printf("Printer %s opened successfully\n", printername);
126                 werror = rpccli_spoolss_close_printer(cli, mem_ctx, &hnd);
127
128                 if (!W_ERROR_IS_OK(werror)) {
129                         printf("Error closing printer handle! (%s)\n", 
130                                 get_dos_error_msg(werror));
131                 }
132         }
133
134         return werror;
135 }
136
137
138 /****************************************************************************
139 ****************************************************************************/
140
141 static void display_print_info_0(PRINTER_INFO_0 *i0)
142 {
143         fstring name = "";
144         fstring servername = "";
145
146         if (!i0)
147                 return;
148
149         rpcstr_pull(name, i0->printername.buffer, sizeof(name), -1, STR_TERMINATE);
150
151         rpcstr_pull(servername, i0->servername.buffer, sizeof(servername), -1,STR_TERMINATE);
152   
153         printf("\tprintername:[%s]\n", name);
154         printf("\tservername:[%s]\n", servername);
155         printf("\tcjobs:[0x%x]\n", i0->cjobs);
156         printf("\ttotal_jobs:[0x%x]\n", i0->total_jobs);
157         
158         printf("\t:date: [%d]-[%d]-[%d] (%d)\n", i0->year, i0->month, 
159                i0->day, i0->dayofweek);
160         printf("\t:time: [%d]-[%d]-[%d]-[%d]\n", i0->hour, i0->minute, 
161                i0->second, i0->milliseconds);
162         
163         printf("\tglobal_counter:[0x%x]\n", i0->global_counter);
164         printf("\ttotal_pages:[0x%x]\n", i0->total_pages);
165         
166         printf("\tmajorversion:[0x%x]\n", i0->major_version);
167         printf("\tbuildversion:[0x%x]\n", i0->build_version);
168         
169         printf("\tunknown7:[0x%x]\n", i0->unknown7);
170         printf("\tunknown8:[0x%x]\n", i0->unknown8);
171         printf("\tunknown9:[0x%x]\n", i0->unknown9);
172         printf("\tsession_counter:[0x%x]\n", i0->session_counter);
173         printf("\tunknown11:[0x%x]\n", i0->unknown11);
174         printf("\tprinter_errors:[0x%x]\n", i0->printer_errors);
175         printf("\tunknown13:[0x%x]\n", i0->unknown13);
176         printf("\tunknown14:[0x%x]\n", i0->unknown14);
177         printf("\tunknown15:[0x%x]\n", i0->unknown15);
178         printf("\tunknown16:[0x%x]\n", i0->unknown16);
179         printf("\tchange_id:[0x%x]\n", i0->change_id);
180         printf("\tunknown18:[0x%x]\n", i0->unknown18);
181         printf("\tstatus:[0x%x]\n", i0->status);
182         printf("\tunknown20:[0x%x]\n", i0->unknown20);
183         printf("\tc_setprinter:[0x%x]\n", i0->c_setprinter);
184         printf("\tunknown22:[0x%x]\n", i0->unknown22);
185         printf("\tunknown23:[0x%x]\n", i0->unknown23);
186         printf("\tunknown24:[0x%x]\n", i0->unknown24);
187         printf("\tunknown25:[0x%x]\n", i0->unknown25);
188         printf("\tunknown26:[0x%x]\n", i0->unknown26);
189         printf("\tunknown27:[0x%x]\n", i0->unknown27);
190         printf("\tunknown28:[0x%x]\n", i0->unknown28);
191         printf("\tunknown29:[0x%x]\n", i0->unknown29);
192
193         printf("\n");
194 }
195
196 /****************************************************************************
197 ****************************************************************************/
198
199 static void display_print_info_1(PRINTER_INFO_1 *i1)
200 {
201         fstring desc = "";
202         fstring name = "";
203         fstring comm = "";
204
205         rpcstr_pull(desc, i1->description.buffer, sizeof(desc), -1,
206                     STR_TERMINATE);
207
208         rpcstr_pull(name, i1->name.buffer, sizeof(name), -1, STR_TERMINATE);
209         rpcstr_pull(comm, i1->comment.buffer, sizeof(comm), -1, STR_TERMINATE);
210
211         printf("\tflags:[0x%x]\n", i1->flags);
212         printf("\tname:[%s]\n", name);
213         printf("\tdescription:[%s]\n", desc);
214         printf("\tcomment:[%s]\n", comm);
215
216         printf("\n");
217 }
218
219 /****************************************************************************
220 ****************************************************************************/
221
222 static void display_print_info_2(PRINTER_INFO_2 *i2)
223 {
224         fstring servername = "";
225         fstring printername = "";
226         fstring sharename = "";
227         fstring portname = "";
228         fstring drivername = "";
229         fstring comment = "";
230         fstring location = "";
231         fstring sepfile = "";
232         fstring printprocessor = "";
233         fstring datatype = "";
234         fstring parameters = "";
235         
236         rpcstr_pull(servername, i2->servername.buffer,sizeof(servername), -1, STR_TERMINATE);
237         rpcstr_pull(printername, i2->printername.buffer,sizeof(printername), -1, STR_TERMINATE);
238         rpcstr_pull(sharename, i2->sharename.buffer,sizeof(sharename), -1, STR_TERMINATE);
239         rpcstr_pull(portname, i2->portname.buffer,sizeof(portname), -1, STR_TERMINATE);
240         rpcstr_pull(drivername, i2->drivername.buffer,sizeof(drivername), -1, STR_TERMINATE);
241         rpcstr_pull(comment, i2->comment.buffer,sizeof(comment), -1, STR_TERMINATE);
242         rpcstr_pull(location, i2->location.buffer,sizeof(location), -1, STR_TERMINATE);
243         rpcstr_pull(sepfile, i2->sepfile.buffer,sizeof(sepfile), -1, STR_TERMINATE);
244         rpcstr_pull(printprocessor, i2->printprocessor.buffer,sizeof(printprocessor), -1, STR_TERMINATE);
245         rpcstr_pull(datatype, i2->datatype.buffer,sizeof(datatype), -1, STR_TERMINATE);
246         rpcstr_pull(parameters, i2->parameters.buffer,sizeof(parameters), -1, STR_TERMINATE);
247
248         printf("\tservername:[%s]\n", servername);
249         printf("\tprintername:[%s]\n", printername);
250         printf("\tsharename:[%s]\n", sharename);
251         printf("\tportname:[%s]\n", portname);
252         printf("\tdrivername:[%s]\n", drivername);
253         printf("\tcomment:[%s]\n", comment);
254         printf("\tlocation:[%s]\n", location);
255         printf("\tsepfile:[%s]\n", sepfile);
256         printf("\tprintprocessor:[%s]\n", printprocessor);
257         printf("\tdatatype:[%s]\n", datatype);
258         printf("\tparameters:[%s]\n", parameters);
259         printf("\tattributes:[0x%x]\n", i2->attributes);
260         printf("\tpriority:[0x%x]\n", i2->priority);
261         printf("\tdefaultpriority:[0x%x]\n", i2->defaultpriority);
262         printf("\tstarttime:[0x%x]\n", i2->starttime);
263         printf("\tuntiltime:[0x%x]\n", i2->untiltime);
264         printf("\tstatus:[0x%x]\n", i2->status);
265         printf("\tcjobs:[0x%x]\n", i2->cjobs);
266         printf("\taverageppm:[0x%x]\n", i2->averageppm);
267
268         if (i2->secdesc) 
269                 display_sec_desc(i2->secdesc);
270
271         printf("\n");
272 }
273
274 /****************************************************************************
275 ****************************************************************************/
276
277 static void display_print_info_3(PRINTER_INFO_3 *i3)
278 {
279         display_sec_desc(i3->secdesc);
280
281         printf("\n");
282 }
283
284 /****************************************************************************
285 ****************************************************************************/
286
287 static void display_print_info_7(PRINTER_INFO_7 *i7)
288 {
289         fstring guid = "";
290         rpcstr_pull(guid, i7->guid.buffer,sizeof(guid), -1, STR_TERMINATE);
291         printf("\tguid:[%s]\n", guid);
292         printf("\taction:[0x%x]\n", i7->action);
293 }
294
295
296 /****************************************************************************
297 ****************************************************************************/
298
299 static WERROR cmd_spoolss_enum_printers(struct rpc_pipe_client *cli, 
300                                           TALLOC_CTX *mem_ctx,
301                                           int argc, const char **argv)
302 {
303         WERROR                  result;
304         uint32                  info_level = 1;
305         PRINTER_INFO_CTR        ctr;
306         uint32                  i = 0, num_printers;
307         fstring name;
308
309         if (argc > 3) 
310         {
311                 printf("Usage: %s [level] [name]\n", argv[0]);
312                 return WERR_OK;
313         }
314
315         if (argc >= 2)
316                 info_level = atoi(argv[1]);
317
318         if (argc == 3)
319                 fstrcpy(name, argv[2]);
320         else {
321                 slprintf(name, sizeof(name)-1, "\\\\%s", cli->cli->desthost);
322                 strupper_m(name);
323         }
324
325         ZERO_STRUCT(ctr);
326
327         result = rpccli_spoolss_enum_printers(cli, mem_ctx, name, PRINTER_ENUM_LOCAL, 
328                 info_level, &num_printers, &ctr);
329
330         if (W_ERROR_IS_OK(result)) {
331
332                 if (!num_printers) {
333                         printf ("No printers returned.\n");
334                         goto done;
335                 }
336         
337                 for (i = 0; i < num_printers; i++) {
338                         switch(info_level) {
339                         case 0:
340                                 display_print_info_0(&ctr.printers_0[i]);
341                                 break;
342                         case 1:
343                                 display_print_info_1(&ctr.printers_1[i]);
344                                 break;
345                         case 2:
346                                 display_print_info_2(&ctr.printers_2[i]);
347                                 break;
348                         case 3:
349                                 display_print_info_3(&ctr.printers_3[i]);
350                                 break;
351                         default:
352                                 printf("unknown info level %d\n", info_level);
353                                 goto done;
354                         }
355                 }
356         }
357         done:
358
359         return result;
360 }
361
362 /****************************************************************************
363 ****************************************************************************/
364
365 static void display_port_info_1(PORT_INFO_1 *i1)
366 {
367         fstring buffer;
368         
369         rpcstr_pull(buffer, i1->port_name.buffer, sizeof(buffer), -1, STR_TERMINATE);
370         printf("\tPort Name:\t[%s]\n", buffer);
371 }
372
373 /****************************************************************************
374 ****************************************************************************/
375
376 static void display_port_info_2(PORT_INFO_2 *i2)
377 {
378         fstring buffer;
379         
380         rpcstr_pull(buffer, i2->port_name.buffer, sizeof(buffer), -1, STR_TERMINATE);
381         printf("\tPort Name:\t[%s]\n", buffer);
382         rpcstr_pull(buffer, i2->monitor_name.buffer, sizeof(buffer), -1, STR_TERMINATE);
383
384         printf("\tMonitor Name:\t[%s]\n", buffer);
385         rpcstr_pull(buffer, i2->description.buffer, sizeof(buffer), -1, STR_TERMINATE);
386
387         printf("\tDescription:\t[%s]\n", buffer);
388         printf("\tPort Type:\t" );
389         if ( i2->port_type ) {
390                 int comma = 0; /* hack */
391                 printf( "[" );
392                 if ( i2->port_type & PORT_TYPE_READ ) {
393                         printf( "Read" );
394                         comma = 1;
395                 }
396                 if ( i2->port_type & PORT_TYPE_WRITE ) {
397                         printf( "%sWrite", comma ? ", " : "" );
398                         comma = 1;
399                 }
400                 /* These two have slightly different interpretations
401                  on 95/98/ME but I'm disregarding that for now */
402                 if ( i2->port_type & PORT_TYPE_REDIRECTED ) {
403                         printf( "%sRedirected", comma ? ", " : "" );
404                         comma = 1;
405                 }
406                 if ( i2->port_type & PORT_TYPE_NET_ATTACHED ) {
407                         printf( "%sNet-Attached", comma ? ", " : "" );
408                 }
409                 printf( "]\n" );
410         } else {
411                 printf( "[Unset]\n" );
412         }
413         printf("\tReserved:\t[%d]\n", i2->reserved);
414         printf("\n");
415 }
416
417 /****************************************************************************
418 ****************************************************************************/
419
420 static WERROR cmd_spoolss_enum_ports(struct rpc_pipe_client *cli, 
421                                        TALLOC_CTX *mem_ctx, int argc, 
422                                        const char **argv)
423 {
424         WERROR                  result;
425         uint32                  info_level = 1;
426         PORT_INFO_CTR           ctr;
427         uint32                  returned;
428         
429         if (argc > 2) {
430                 printf("Usage: %s [level]\n", argv[0]);
431                 return WERR_OK;
432         }
433         
434         if (argc == 2)
435                 info_level = atoi(argv[1]);
436
437         /* Enumerate ports */
438
439         ZERO_STRUCT(ctr);
440
441         result = rpccli_spoolss_enum_ports(cli, mem_ctx, info_level, &returned, &ctr);
442
443         if (W_ERROR_IS_OK(result)) {
444                 int i;
445
446                 for (i = 0; i < returned; i++) {
447                         switch (info_level) {
448                         case 1:
449                                 display_port_info_1(&ctr.port.info_1[i]);
450                                 break;
451                         case 2:
452                                 display_port_info_2(&ctr.port.info_2[i]);
453                                 break;
454                         default:
455                                 printf("unknown info level %d\n", info_level);
456                                 break;
457                         }
458                 }
459         }
460         
461         return result;
462 }
463
464 /****************************************************************************
465 ****************************************************************************/
466
467 static WERROR cmd_spoolss_setprinter(struct rpc_pipe_client *cli,
468                                        TALLOC_CTX *mem_ctx,
469                                        int argc, const char **argv)
470 {
471         POLICY_HND      pol;
472         WERROR          result;
473         uint32          info_level = 2;
474         BOOL            opened_hnd = False;
475         PRINTER_INFO_CTR ctr;
476         fstring         printername,
477                         servername,
478                         user,
479                         comment;
480
481         if (argc == 1 || argc > 3) {
482                 printf("Usage: %s printername comment\n", argv[0]);
483
484                 return WERR_OK;
485         }
486
487         /* Open a printer handle */
488         if (argc == 3) {
489                 fstrcpy(comment, argv[2]);
490         }
491
492         slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->cli->desthost);
493         strupper_m(servername);
494         slprintf(printername, sizeof(servername)-1, "%s\\%s", servername, argv[1]);
495         fstrcpy(user, cli->user_name);
496
497         /* get a printer handle */
498         result = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername, "", 
499                                 PRINTER_ALL_ACCESS, servername,
500                                 user, &pol);
501                                 
502         if (!W_ERROR_IS_OK(result))
503                 goto done;
504
505         opened_hnd = True;
506
507         /* Get printer info */
508         result = rpccli_spoolss_getprinter(cli, mem_ctx, &pol, info_level, &ctr);
509
510         if (!W_ERROR_IS_OK(result))
511                 goto done;
512
513
514         /* Modify the comment. */
515         init_unistr(&ctr.printers_2->comment, comment);
516         ctr.printers_2->devmode = NULL;
517         ctr.printers_2->secdesc = NULL;
518
519         result = rpccli_spoolss_setprinter(cli, mem_ctx, &pol, info_level, &ctr, 0);
520         if (W_ERROR_IS_OK(result))
521                 printf("Success in setting comment.\n");
522
523  done:
524         if (opened_hnd)
525                 rpccli_spoolss_close_printer(cli, mem_ctx, &pol);
526
527         return result;
528 }
529
530 /****************************************************************************
531 ****************************************************************************/
532
533 static WERROR cmd_spoolss_setprintername(struct rpc_pipe_client *cli,
534                                        TALLOC_CTX *mem_ctx,
535                                        int argc, const char **argv)
536 {
537         POLICY_HND      pol;
538         WERROR          result;
539         uint32          info_level = 2;
540         BOOL            opened_hnd = False;
541         PRINTER_INFO_CTR ctr;
542         fstring         printername,
543                         servername,
544                         user,
545                         new_printername;
546
547         if (argc == 1 || argc > 3) {
548                 printf("Usage: %s printername new_printername\n", argv[0]);
549
550                 return WERR_OK;
551         }
552
553         /* Open a printer handle */
554         if (argc == 3) {
555                 fstrcpy(new_printername, argv[2]);
556         }
557
558         slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->cli->desthost);
559         strupper_m(servername);
560         slprintf(printername, sizeof(printername)-1, "%s\\%s", servername, argv[1]);
561         fstrcpy(user, cli->user_name);
562
563         /* get a printer handle */
564         result = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername, "", 
565                                 PRINTER_ALL_ACCESS, servername,
566                                 user, &pol);
567                                 
568         if (!W_ERROR_IS_OK(result))
569                 goto done;
570
571         opened_hnd = True;
572
573         /* Get printer info */
574         result = rpccli_spoolss_getprinter(cli, mem_ctx, &pol, info_level, &ctr);
575
576         if (!W_ERROR_IS_OK(result))
577                 goto done;
578
579         /* Modify the printername. */
580         init_unistr(&ctr.printers_2->printername, new_printername);
581         ctr.printers_2->devmode = NULL;
582         ctr.printers_2->secdesc = NULL;
583
584         result = rpccli_spoolss_setprinter(cli, mem_ctx, &pol, info_level, &ctr, 0);
585         if (W_ERROR_IS_OK(result))
586                 printf("Success in setting printername.\n");
587
588  done:
589         if (opened_hnd)
590                 rpccli_spoolss_close_printer(cli, mem_ctx, &pol);
591
592         return result;
593 }
594
595 /****************************************************************************
596 ****************************************************************************/
597
598 static WERROR cmd_spoolss_getprinter(struct rpc_pipe_client *cli,
599                                        TALLOC_CTX *mem_ctx,
600                                        int argc, const char **argv)
601 {
602         POLICY_HND      pol;
603         WERROR          result;
604         uint32          info_level = 1;
605         BOOL            opened_hnd = False;
606         PRINTER_INFO_CTR ctr;
607         fstring         printername,
608                         servername,
609                         user;
610
611         if (argc == 1 || argc > 3) {
612                 printf("Usage: %s <printername> [level]\n", argv[0]);
613                 return WERR_OK;
614         }
615
616         /* Open a printer handle */
617         if (argc == 3) {
618                 info_level = atoi(argv[2]);
619         }
620
621         slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->cli->desthost);
622         strupper_m(servername);
623         slprintf(printername, sizeof(printername)-1, "%s\\%s", servername, argv[1]);
624         fstrcpy(user, cli->user_name);
625         
626         /* get a printer handle */
627
628         result = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername, 
629                                              "", MAXIMUM_ALLOWED_ACCESS, 
630                                              servername, user, &pol);
631
632         if (!W_ERROR_IS_OK(result))
633                 goto done;
634  
635         opened_hnd = True;
636
637         /* Get printer info */
638
639         result = rpccli_spoolss_getprinter(cli, mem_ctx, &pol, info_level, &ctr);
640
641         if (!W_ERROR_IS_OK(result))
642                 goto done;
643
644         /* Display printer info */
645
646         switch (info_level) {
647         case 0: 
648                 display_print_info_0(ctr.printers_0);
649                 break;
650         case 1:
651                 display_print_info_1(ctr.printers_1);
652                 break;
653         case 2:
654                 display_print_info_2(ctr.printers_2);
655                 break;
656         case 3:
657                 display_print_info_3(ctr.printers_3);
658                 break;
659         case 7:
660                 display_print_info_7(ctr.printers_7);
661                 break;
662         default:
663                 printf("unknown info level %d\n", info_level);
664                 break;
665         }
666
667  done: 
668         if (opened_hnd) 
669                 rpccli_spoolss_close_printer(cli, mem_ctx, &pol);
670
671         return result;
672 }
673
674 /****************************************************************************
675 ****************************************************************************/
676
677 static void display_reg_value(REGISTRY_VALUE value)
678 {
679         pstring text;
680
681         switch(value.type) {
682         case REG_DWORD:
683                 printf("%s: REG_DWORD: 0x%08x\n", value.valuename, 
684                        *((uint32 *) value.data_p));
685                 break;
686         case REG_SZ:
687                 rpcstr_pull(text, value.data_p, sizeof(text), value.size,
688                             STR_TERMINATE);
689                 printf("%s: REG_SZ: %s\n", value.valuename, text);
690                 break;
691         case REG_BINARY: {
692                 char *hex = hex_encode(NULL, value.data_p, value.size);
693                 size_t i, len;
694                 printf("%s: REG_BINARY:", value.valuename);
695                 len = strlen(hex);
696                 for (i=0; i<len; i++) {
697                         if (hex[i] == '\0') {
698                                 break;
699                         }
700                         if (i%40 == 0) {
701                                 putchar('\n');
702                         }
703                         putchar(hex[i]);
704                 }
705                 TALLOC_FREE(hex);
706                 putchar('\n');
707                 break;
708         }
709         case REG_MULTI_SZ: {
710                 uint32 i, num_values;
711                 char **values;
712
713                 if (!W_ERROR_IS_OK(reg_pull_multi_sz(NULL, value.data_p,
714                                                      value.size, &num_values,
715                                                      &values))) {
716                         d_printf("reg_pull_multi_sz failed\n");
717                         break;
718                 }
719
720                 for (i=0; i<num_values; i++) {
721                         d_printf("%s\n", values[i]);
722                 }
723                 TALLOC_FREE(values);
724                 break;
725         }
726         default:
727                 printf("%s: unknown type %d\n", value.valuename, value.type);
728         }
729         
730 }
731
732 /****************************************************************************
733 ****************************************************************************/
734
735 static WERROR cmd_spoolss_getprinterdata(struct rpc_pipe_client *cli,
736                                            TALLOC_CTX *mem_ctx,
737                                            int argc, const char **argv)
738 {
739         POLICY_HND      pol;
740         WERROR          result;
741         BOOL            opened_hnd = False;
742         fstring         printername,
743                         servername,
744                         user;
745         const char *valuename;
746         REGISTRY_VALUE value;
747
748         if (argc != 3) {
749                 printf("Usage: %s <printername> <valuename>\n", argv[0]);
750                 printf("<printername> of . queries print server\n");
751                 return WERR_OK;
752         }
753         valuename = argv[2];
754
755         /* Open a printer handle */
756
757         slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->cli->desthost);
758         strupper_m(servername);
759         if (strncmp(argv[1], ".", sizeof(".")) == 0)
760                 fstrcpy(printername, servername);
761         else
762                 slprintf(printername, sizeof(servername)-1, "%s\\%s", 
763                           servername, argv[1]);
764         fstrcpy(user, cli->user_name);
765         
766         /* get a printer handle */
767
768         result = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername, 
769                                              "", MAXIMUM_ALLOWED_ACCESS, 
770                                              servername, user, &pol);
771
772         if (!W_ERROR_IS_OK(result))
773                 goto done;
774  
775         opened_hnd = True;
776
777         /* Get printer info */
778
779         result = rpccli_spoolss_getprinterdata(cli, mem_ctx, &pol, valuename, &value);
780
781         if (!W_ERROR_IS_OK(result))
782                 goto done;
783
784         /* Display printer data */
785
786         fstrcpy(value.valuename, valuename);
787         display_reg_value(value);
788         
789
790  done: 
791         if (opened_hnd) 
792                 rpccli_spoolss_close_printer(cli, mem_ctx, &pol);
793
794         return result;
795 }
796
797 /****************************************************************************
798 ****************************************************************************/
799
800 static WERROR cmd_spoolss_getprinterdataex(struct rpc_pipe_client *cli,
801                                              TALLOC_CTX *mem_ctx,
802                                              int argc, const char **argv)
803 {
804         POLICY_HND      pol;
805         WERROR          result;
806         BOOL            opened_hnd = False;
807         fstring         printername,
808                         servername,
809                         user;
810         const char *valuename, *keyname;
811         REGISTRY_VALUE value;
812
813         if (argc != 4) {
814                 printf("Usage: %s <printername> <keyname> <valuename>\n", 
815                        argv[0]);
816                 printf("<printername> of . queries print server\n");
817                 return WERR_OK;
818         }
819         valuename = argv[3];
820         keyname = argv[2];
821
822         /* Open a printer handle */
823
824         slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->cli->desthost);
825         strupper_m(servername);
826         if (strncmp(argv[1], ".", sizeof(".")) == 0)
827                 fstrcpy(printername, servername);
828         else
829                 slprintf(printername, sizeof(printername)-1, "%s\\%s", 
830                           servername, argv[1]);
831         fstrcpy(user, cli->user_name);
832         
833         /* get a printer handle */
834
835         result = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername, 
836                                              "", MAXIMUM_ALLOWED_ACCESS, 
837                                              servername, user, &pol);
838
839         if (!W_ERROR_IS_OK(result))
840                 goto done;
841  
842         opened_hnd = True;
843
844         /* Get printer info */
845
846         result = rpccli_spoolss_getprinterdataex(cli, mem_ctx, &pol, keyname, 
847                 valuename, &value);
848
849         if (!W_ERROR_IS_OK(result))
850                 goto done;
851
852         /* Display printer data */
853
854         fstrcpy(value.valuename, valuename);
855         display_reg_value(value);
856         
857
858  done: 
859         if (opened_hnd) 
860                 rpccli_spoolss_close_printer(cli, mem_ctx, &pol);
861
862         return result;
863 }
864
865 /****************************************************************************
866 ****************************************************************************/
867
868 static void display_print_driver_1(DRIVER_INFO_1 *i1)
869 {
870         fstring name;
871         if (i1 == NULL)
872                 return;
873
874         rpcstr_pull(name, i1->name.buffer, sizeof(name), -1, STR_TERMINATE);
875
876         printf ("Printer Driver Info 1:\n");
877         printf ("\tDriver Name: [%s]\n\n", name);
878         
879         return;
880 }
881
882 /****************************************************************************
883 ****************************************************************************/
884
885 static void display_print_driver_2(DRIVER_INFO_2 *i1)
886 {
887         fstring name;
888         fstring architecture;
889         fstring driverpath;
890         fstring datafile;
891         fstring configfile;
892         if (i1 == NULL)
893                 return;
894
895         rpcstr_pull(name, i1->name.buffer, sizeof(name), -1, STR_TERMINATE);
896         rpcstr_pull(architecture, i1->architecture.buffer, sizeof(architecture), -1, STR_TERMINATE);
897         rpcstr_pull(driverpath, i1->driverpath.buffer, sizeof(driverpath), -1, STR_TERMINATE);
898         rpcstr_pull(datafile, i1->datafile.buffer, sizeof(datafile), -1, STR_TERMINATE);
899         rpcstr_pull(configfile, i1->configfile.buffer, sizeof(configfile), -1, STR_TERMINATE);
900
901         printf ("Printer Driver Info 2:\n");
902         printf ("\tVersion: [%x]\n", i1->version);
903         printf ("\tDriver Name: [%s]\n", name);
904         printf ("\tArchitecture: [%s]\n", architecture);
905         printf ("\tDriver Path: [%s]\n", driverpath);
906         printf ("\tDatafile: [%s]\n", datafile);
907         printf ("\tConfigfile: [%s]\n\n", configfile);
908
909         return;
910 }
911
912 /****************************************************************************
913 ****************************************************************************/
914
915 static void display_print_driver_3(DRIVER_INFO_3 *i1)
916 {
917         fstring name = "";
918         fstring architecture = "";
919         fstring driverpath = "";
920         fstring datafile = "";
921         fstring configfile = "";
922         fstring helpfile = "";
923         fstring dependentfiles = "";
924         fstring monitorname = "";
925         fstring defaultdatatype = "";
926         
927         int length=0;
928         BOOL valid = True;
929         
930         if (i1 == NULL)
931                 return;
932
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);
938         rpcstr_pull(helpfile, i1->helpfile.buffer, sizeof(helpfile), -1, STR_TERMINATE);
939         rpcstr_pull(monitorname, i1->monitorname.buffer, sizeof(monitorname), -1, STR_TERMINATE);
940         rpcstr_pull(defaultdatatype, i1->defaultdatatype.buffer, sizeof(defaultdatatype), -1, STR_TERMINATE);
941
942         printf ("Printer Driver Info 3:\n");
943         printf ("\tVersion: [%x]\n", i1->version);
944         printf ("\tDriver Name: [%s]\n",name);
945         printf ("\tArchitecture: [%s]\n", architecture);
946         printf ("\tDriver Path: [%s]\n", driverpath);
947         printf ("\tDatafile: [%s]\n", datafile);
948         printf ("\tConfigfile: [%s]\n", configfile);
949         printf ("\tHelpfile: [%s]\n\n", helpfile);
950
951         while (valid)
952         {
953                 rpcstr_pull(dependentfiles, i1->dependentfiles+length, sizeof(dependentfiles), -1, STR_TERMINATE);
954                 
955                 length+=strlen(dependentfiles)+1;
956                 
957                 if (strlen(dependentfiles) > 0)
958                 {
959                         printf ("\tDependentfiles: [%s]\n", dependentfiles);
960                 }
961                 else
962                 {
963                         valid = False;
964                 }
965         }
966         
967         printf ("\n");
968
969         printf ("\tMonitorname: [%s]\n", monitorname);
970         printf ("\tDefaultdatatype: [%s]\n\n", defaultdatatype);
971
972         return; 
973 }
974
975 /****************************************************************************
976 ****************************************************************************/
977
978 static WERROR cmd_spoolss_getdriver(struct rpc_pipe_client *cli, 
979                                       TALLOC_CTX *mem_ctx,
980                                       int argc, const char **argv)
981 {
982         POLICY_HND      pol;
983         WERROR          werror;
984         uint32          info_level = 3;
985         BOOL            opened_hnd = False;
986         PRINTER_DRIVER_CTR      ctr;
987         fstring         printername, 
988                         servername, 
989                         user;
990         uint32          i;
991         BOOL            success = False;
992
993         if ((argc == 1) || (argc > 3)) 
994         {
995                 printf("Usage: %s <printername> [level]\n", argv[0]);
996                 return WERR_OK;
997         }
998
999         /* get the arguments need to open the printer handle */
1000         slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->cli->desthost);
1001         strupper_m(servername);
1002         fstrcpy(user, cli->user_name);
1003         slprintf(printername, sizeof(servername)-1, "%s\\%s", servername, argv[1]);
1004         if (argc == 3)
1005                 info_level = atoi(argv[2]);
1006
1007         /* Open a printer handle */
1008
1009         werror = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername, "", 
1010                                              PRINTER_ACCESS_USE,
1011                                              servername, user, &pol);
1012
1013         if (!W_ERROR_IS_OK(werror)) {
1014                 printf("Error opening printer handle for %s!\n", printername);
1015                 return werror;
1016         }
1017
1018         opened_hnd = True;
1019
1020         /* loop through and print driver info level for each architecture */
1021
1022         for (i=0; archi_table[i].long_archi!=NULL; i++) {
1023
1024                 werror = rpccli_spoolss_getprinterdriver( cli, mem_ctx, &pol, info_level, 
1025                         archi_table[i].long_archi, archi_table[i].version,
1026                         &ctr);
1027
1028                 if (!W_ERROR_IS_OK(werror))
1029                         continue;
1030                 
1031                 /* need at least one success */
1032                 
1033                 success = True;
1034                         
1035                 printf ("\n[%s]\n", archi_table[i].long_archi);
1036
1037                 switch (info_level) {
1038                 case 1:
1039                         display_print_driver_1 (ctr.info1);
1040                         break;
1041                 case 2:
1042                         display_print_driver_2 (ctr.info2);
1043                         break;
1044                 case 3:
1045                         display_print_driver_3 (ctr.info3);
1046                         break;
1047                 default:
1048                         printf("unknown info level %d\n", info_level);
1049                         break;
1050                 }
1051         }
1052         
1053         /* Cleanup */
1054
1055         if (opened_hnd)
1056                 rpccli_spoolss_close_printer (cli, mem_ctx, &pol);
1057         
1058         if ( success )
1059                 werror = WERR_OK;
1060                 
1061         return werror;
1062 }
1063
1064 /****************************************************************************
1065 ****************************************************************************/
1066
1067 static WERROR cmd_spoolss_enum_drivers(struct rpc_pipe_client *cli, 
1068                                          TALLOC_CTX *mem_ctx,
1069                                          int argc, const char **argv)
1070 {
1071         WERROR werror = WERR_OK;
1072         uint32          info_level = 1;
1073         PRINTER_DRIVER_CTR      ctr;
1074         uint32          i, j,
1075                         returned;
1076
1077         if (argc > 2) {
1078                 printf("Usage: enumdrivers [level]\n");
1079                 return WERR_OK;
1080         }
1081
1082         if (argc == 2)
1083                 info_level = atoi(argv[1]);
1084
1085
1086         /* loop through and print driver info level for each architecture */
1087         for (i=0; archi_table[i].long_archi!=NULL; i++) {
1088                 /* check to see if we already asked for this architecture string */
1089
1090                 if ( i>0 && strequal(archi_table[i].long_archi, archi_table[i-1].long_archi) )
1091                         continue;
1092
1093                 werror = rpccli_spoolss_enumprinterdrivers(
1094                         cli, mem_ctx, info_level, 
1095                         archi_table[i].long_archi, &returned, &ctr);
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 (returned == 0)
1105                         continue;
1106                         
1107                 if (!W_ERROR_IS_OK(werror)) {
1108                         printf ("Error getting driver for environment [%s] - %d\n",
1109                                 archi_table[i].long_archi, W_ERROR_V(werror));
1110                         continue;
1111                 }
1112                 
1113                 printf ("\n[%s]\n", archi_table[i].long_archi);
1114                 switch (info_level) 
1115                 {
1116                         
1117                 case 1:
1118                         for (j=0; j < returned; j++) {
1119                                 display_print_driver_1 (&ctr.info1[j]);
1120                         }
1121                         break;
1122                 case 2:
1123                         for (j=0; j < returned; j++) {
1124                                 display_print_driver_2 (&ctr.info2[j]);
1125                         }
1126                         break;
1127                 case 3:
1128                         for (j=0; j < returned; j++) {
1129                                 display_print_driver_3 (&ctr.info3[j]);
1130                         }
1131                         break;
1132                 default:
1133                         printf("unknown info level %d\n", info_level);
1134                         return WERR_UNKNOWN_LEVEL;
1135                 }
1136         }
1137         
1138         return werror;
1139 }
1140
1141 /****************************************************************************
1142 ****************************************************************************/
1143
1144 static void display_printdriverdir_1(DRIVER_DIRECTORY_1 *i1)
1145 {
1146         fstring name;
1147         if (i1 == NULL)
1148                 return;
1149  
1150         rpcstr_pull(name, i1->name.buffer, sizeof(name), -1, STR_TERMINATE);
1151  
1152         printf ("\tDirectory Name:[%s]\n", name);
1153 }
1154
1155 /****************************************************************************
1156 ****************************************************************************/
1157
1158 static WERROR cmd_spoolss_getdriverdir(struct rpc_pipe_client *cli, 
1159                                          TALLOC_CTX *mem_ctx,
1160                                          int argc, const char **argv)
1161 {
1162         WERROR result;
1163         fstring                 env;
1164         DRIVER_DIRECTORY_CTR    ctr;
1165
1166         if (argc > 2) {
1167                 printf("Usage: %s [environment]\n", argv[0]);
1168                 return WERR_OK;
1169         }
1170
1171         /* Get the arguments need to open the printer handle */
1172
1173         if (argc == 2)
1174                 fstrcpy (env, argv[1]);
1175         else
1176                 fstrcpy (env, "Windows NT x86");
1177
1178         /* Get the directory.  Only use Info level 1 */
1179
1180         result = rpccli_spoolss_getprinterdriverdir(cli, mem_ctx, 1, env, &ctr);
1181
1182         if (W_ERROR_IS_OK(result))
1183                 display_printdriverdir_1(ctr.info1);
1184
1185         return result;
1186 }
1187
1188 /****************************************************************************
1189 ****************************************************************************/
1190
1191 void set_drv_info_3_env (DRIVER_INFO_3 *info, const char *arch)
1192 {
1193
1194         int i;
1195         
1196         for (i=0; archi_table[i].long_archi != NULL; i++) 
1197         {
1198                 if (strcmp(arch, archi_table[i].short_archi) == 0)
1199                 {
1200                         info->version = archi_table[i].version;
1201                         init_unistr (&info->architecture, archi_table[i].long_archi);
1202                         break;
1203                 }
1204         }
1205         
1206         if (archi_table[i].long_archi == NULL)
1207         {
1208                 DEBUG(0, ("set_drv_info_3_env: Unknown arch [%s]\n", arch));
1209         }
1210         
1211         return;
1212 }
1213
1214
1215 /**************************************************************************
1216  wrapper for strtok to get the next parameter from a delimited list.
1217  Needed to handle the empty parameter string denoted by "NULL"
1218  *************************************************************************/
1219  
1220 static char* get_driver_3_param (char* str, const char* delim, UNISTR* dest)
1221 {
1222         char    *ptr;
1223
1224         /* get the next token */
1225         ptr = strtok(str, delim);
1226
1227         /* a string of 'NULL' is used to represent an empty
1228            parameter because two consecutive delimiters
1229            will not return an empty string.  See man strtok(3)
1230            for details */
1231         if (ptr && (StrCaseCmp(ptr, "NULL") == 0))
1232                 ptr = NULL;
1233
1234         if (dest != NULL)
1235                 init_unistr(dest, ptr); 
1236
1237         return ptr;
1238 }
1239
1240 /********************************************************************************
1241  fill in the members of a DRIVER_INFO_3 struct using a character 
1242  string in the form of
1243          <Long Printer Name>:<Driver File Name>:<Data File Name>:\
1244              <Config File Name>:<Help File Name>:<Language Monitor Name>:\
1245              <Default Data Type>:<Comma Separated list of Files> 
1246  *******************************************************************************/
1247 static BOOL init_drv_info_3_members ( TALLOC_CTX *mem_ctx, DRIVER_INFO_3 *info, 
1248                                       char *args )
1249 {
1250         char    *str, *str2;
1251         uint32  len, i;
1252         
1253         /* fill in the UNISTR fields */
1254         str = get_driver_3_param (args, ":", &info->name);
1255         str = get_driver_3_param (NULL, ":", &info->driverpath);
1256         str = get_driver_3_param (NULL, ":", &info->datafile);
1257         str = get_driver_3_param (NULL, ":", &info->configfile);
1258         str = get_driver_3_param (NULL, ":", &info->helpfile);
1259         str = get_driver_3_param (NULL, ":", &info->monitorname);
1260         str = get_driver_3_param (NULL, ":", &info->defaultdatatype);
1261
1262         /* <Comma Separated List of Dependent Files> */
1263         str2 = get_driver_3_param (NULL, ":", NULL); /* save the beginning of the string */
1264         str = str2;                     
1265
1266         /* begin to strip out each filename */
1267         str = strtok(str, ",");         
1268         len = 0;
1269         while (str != NULL)
1270         {
1271                 /* keep a cumlative count of the str lengths */
1272                 len += strlen(str)+1;
1273                 str = strtok(NULL, ",");
1274         }
1275
1276         /* allocate the space; add one extra slot for a terminating NULL.
1277            Each filename is NULL terminated and the end contains a double
1278            NULL */
1279         if ((info->dependentfiles=TALLOC_ARRAY(mem_ctx, uint16, len+1)) == NULL)
1280         {
1281                 DEBUG(0,("init_drv_info_3_members: Unable to malloc memory for dependenfiles\n"));
1282                 return False;
1283         }
1284         for (i=0; i<len; i++)
1285         {
1286                 SSVAL(&info->dependentfiles[i], 0, str2[i]);
1287         }
1288         info->dependentfiles[len] = '\0';
1289
1290         return True;
1291 }
1292
1293
1294 /****************************************************************************
1295 ****************************************************************************/
1296
1297 static WERROR cmd_spoolss_addprinterdriver(struct rpc_pipe_client *cli, 
1298                                              TALLOC_CTX *mem_ctx,
1299                                              int argc, const char **argv)
1300 {
1301         WERROR result;
1302         uint32                  level = 3;
1303         PRINTER_DRIVER_CTR      ctr;
1304         DRIVER_INFO_3           info3;
1305         const char              *arch;
1306         fstring                 driver_name;
1307         char                    *driver_args;
1308
1309         /* parse the command arguements */
1310         if (argc != 3 && argc != 4)
1311         {
1312                 printf ("Usage: %s <Environment> \\\n", argv[0]);
1313                 printf ("\t<Long Printer Name>:<Driver File Name>:<Data File Name>:\\\n");
1314                 printf ("\t<Config File Name>:<Help File Name>:<Language Monitor Name>:\\\n");
1315                 printf ("\t<Default Data Type>:<Comma Separated list of Files> \\\n");
1316                 printf ("\t[version]\n");
1317
1318             return WERR_OK;
1319         }
1320                 
1321         /* Fill in the DRIVER_INFO_3 struct */
1322         ZERO_STRUCT(info3);
1323         if (!(arch = cmd_spoolss_get_short_archi(argv[1])))
1324         {
1325                 printf ("Error Unknown architechture [%s]\n", argv[1]);
1326                 return WERR_INVALID_PARAM;
1327         }
1328         else
1329                 set_drv_info_3_env(&info3, arch);
1330
1331         driver_args = talloc_strdup( mem_ctx, argv[2] );
1332         if (!init_drv_info_3_members(mem_ctx, &info3, driver_args ))
1333         {
1334                 printf ("Error Invalid parameter list - %s.\n", argv[2]);
1335                 return WERR_INVALID_PARAM;
1336         }
1337
1338         /* if printer driver version specified, override the default version
1339          * used by the architecture.  This allows installation of Windows
1340          * 2000 (version 3) printer drivers. */
1341         if (argc == 4)
1342         {
1343                 info3.version = atoi(argv[3]);
1344         }
1345
1346
1347         ctr.info3 = &info3;
1348         result = rpccli_spoolss_addprinterdriver (cli, mem_ctx, level, &ctr);
1349
1350         if (W_ERROR_IS_OK(result)) {
1351                 rpcstr_pull(driver_name, info3.name.buffer, 
1352                             sizeof(driver_name), -1, STR_TERMINATE);
1353                 printf ("Printer Driver %s successfully installed.\n",
1354                         driver_name);
1355         }
1356
1357         return result;
1358 }
1359
1360
1361 /****************************************************************************
1362 ****************************************************************************/
1363
1364 static WERROR cmd_spoolss_addprinterex(struct rpc_pipe_client *cli, 
1365                                          TALLOC_CTX *mem_ctx,
1366                                          int argc, const char **argv)
1367 {
1368         WERROR result;
1369         uint32                  level = 2;
1370         PRINTER_INFO_CTR        ctr;
1371         PRINTER_INFO_2          info2;
1372         fstring                 servername;
1373         
1374         /* parse the command arguements */
1375         if (argc != 5)
1376         {
1377                 printf ("Usage: %s <name> <shared name> <driver> <port>\n", argv[0]);
1378                 return WERR_OK;
1379         }
1380         
1381         slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->cli->desthost);
1382         strupper_m(servername);
1383
1384         /* Fill in the DRIVER_INFO_2 struct */
1385         ZERO_STRUCT(info2);
1386         
1387         init_unistr( &info2.printername,        argv[1]);
1388         init_unistr( &info2.sharename,          argv[2]);
1389         init_unistr( &info2.drivername,         argv[3]);
1390         init_unistr( &info2.portname,           argv[4]);
1391         init_unistr( &info2.comment,            "Created by rpcclient");
1392         init_unistr( &info2.printprocessor,     "winprint");
1393         init_unistr( &info2.datatype,           "RAW");
1394         info2.devmode =         NULL;
1395         info2.secdesc =         NULL;
1396         info2.attributes        = PRINTER_ATTRIBUTE_SHARED;
1397         info2.priority          = 0;
1398         info2.defaultpriority   = 0;
1399         info2.starttime         = 0;
1400         info2.untiltime         = 0;
1401         
1402         /* These three fields must not be used by AddPrinter() 
1403            as defined in the MS Platform SDK documentation..  
1404            --jerry
1405         info2.status            = 0;
1406         info2.cjobs             = 0;
1407         info2.averageppm        = 0;
1408         */
1409
1410         ctr.printers_2 = &info2;
1411         result = rpccli_spoolss_addprinterex (cli, mem_ctx, level, &ctr);
1412
1413         if (W_ERROR_IS_OK(result))
1414                 printf ("Printer %s successfully installed.\n", argv[1]);
1415
1416         return result;
1417 }
1418
1419 /****************************************************************************
1420 ****************************************************************************/
1421
1422 static WERROR cmd_spoolss_setdriver(struct rpc_pipe_client *cli, 
1423                                       TALLOC_CTX *mem_ctx,
1424                                       int argc, const char **argv)
1425 {
1426         POLICY_HND              pol;
1427         WERROR                  result;
1428         uint32                  level = 2;
1429         BOOL                    opened_hnd = False;
1430         PRINTER_INFO_CTR        ctr;
1431         PRINTER_INFO_2          info2;
1432         fstring                 servername,
1433                                 printername,
1434                                 user;
1435         
1436         /* parse the command arguements */
1437         if (argc != 3)
1438         {
1439                 printf ("Usage: %s <printer> <driver>\n", argv[0]);
1440                 return WERR_OK;
1441         }
1442
1443         slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->cli->desthost);
1444         strupper_m(servername);
1445         slprintf(printername, sizeof(printername)-1, "%s\\%s", servername, argv[1]);
1446         fstrcpy(user, cli->user_name);
1447
1448         /* Get a printer handle */
1449
1450         result = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername, "", 
1451                                              PRINTER_ALL_ACCESS,
1452                                              servername, user, &pol);
1453
1454         if (!W_ERROR_IS_OK(result))
1455                 goto done;
1456
1457         opened_hnd = True;
1458
1459         /* Get printer info */
1460
1461         ZERO_STRUCT (info2);
1462         ctr.printers_2 = &info2;
1463
1464         result = rpccli_spoolss_getprinter(cli, mem_ctx, &pol, level, &ctr);
1465
1466         if (!W_ERROR_IS_OK(result)) {
1467                 printf ("Unable to retrieve printer information!\n");
1468                 goto done;
1469         }
1470
1471         /* Set the printer driver */
1472
1473         init_unistr(&ctr.printers_2->drivername, argv[2]);
1474
1475         result = rpccli_spoolss_setprinter(cli, mem_ctx, &pol, level, &ctr, 0);
1476
1477         if (!W_ERROR_IS_OK(result)) {
1478                 printf("SetPrinter call failed!\n");
1479                 goto done;;
1480         }
1481
1482         printf("Succesfully set %s to driver %s.\n", argv[1], argv[2]);
1483
1484 done:
1485         /* Cleanup */
1486
1487         if (opened_hnd)
1488                 rpccli_spoolss_close_printer(cli, mem_ctx, &pol);
1489
1490         return result;
1491 }
1492
1493
1494 /****************************************************************************
1495 ****************************************************************************/
1496
1497 static WERROR cmd_spoolss_deletedriverex(struct rpc_pipe_client *cli, 
1498                                          TALLOC_CTX *mem_ctx,
1499                                          int argc, const char **argv)
1500 {
1501         WERROR result, ret = WERR_UNKNOWN_PRINTER_DRIVER;
1502  
1503         int   i;
1504         int vers = -1;
1505  
1506         const char *arch = NULL;
1507  
1508         /* parse the command arguements */
1509         if (argc < 2 || argc > 4) {
1510                 printf ("Usage: %s <driver> [arch] [version]\n", argv[0]);
1511                 return WERR_OK;
1512         }
1513
1514         if (argc >= 3)
1515                 arch = argv[2];
1516         if (argc == 4)
1517                 vers = atoi (argv[3]);
1518  
1519  
1520         /* delete the driver for all architectures */
1521         for (i=0; archi_table[i].long_archi; i++) {
1522
1523                 if (arch &&  !strequal( archi_table[i].long_archi, arch)) 
1524                         continue;
1525
1526                 if (vers >= 0 && archi_table[i].version != vers)
1527                         continue;
1528
1529                 /* make the call to remove the driver */
1530                 result = rpccli_spoolss_deleteprinterdriverex(
1531                         cli, mem_ctx, archi_table[i].long_archi, argv[1], archi_table[i].version); 
1532
1533                 if ( !W_ERROR_IS_OK(result) ) 
1534                 {
1535                         if ( !W_ERROR_EQUAL(result, WERR_UNKNOWN_PRINTER_DRIVER) ) {
1536                                 printf ("Failed to remove driver %s for arch [%s] (version: %d): %s\n", 
1537                                         argv[1], archi_table[i].long_archi, archi_table[i].version, dos_errstr(result));
1538                         }
1539                 } 
1540                 else 
1541                 {
1542                         printf ("Driver %s and files removed for arch [%s] (version: %d).\n", argv[1], 
1543                         archi_table[i].long_archi, archi_table[i].version);
1544                         ret = WERR_OK;
1545                 }
1546         }
1547   
1548         return ret;
1549 }
1550
1551
1552 /****************************************************************************
1553 ****************************************************************************/
1554
1555 static WERROR cmd_spoolss_deletedriver(struct rpc_pipe_client *cli, 
1556                                          TALLOC_CTX *mem_ctx,
1557                                          int argc, const char **argv)
1558 {
1559         WERROR result = WERR_OK;
1560         fstring                 servername;
1561         int                     i;
1562         
1563         /* parse the command arguements */
1564         if (argc != 2) {
1565                 printf ("Usage: %s <driver>\n", argv[0]);
1566                 return WERR_OK;
1567         }
1568
1569         slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->cli->desthost);
1570         strupper_m(servername);
1571
1572         /* delete the driver for all architectures */
1573         for (i=0; archi_table[i].long_archi; i++) {
1574                 /* make the call to remove the driver */
1575                 result = rpccli_spoolss_deleteprinterdriver(
1576                         cli, mem_ctx, archi_table[i].long_archi, argv[1]);
1577
1578                 if ( !W_ERROR_IS_OK(result) ) {
1579                         if ( !W_ERROR_EQUAL(result, WERR_UNKNOWN_PRINTER_DRIVER) ) {
1580                                 printf ("Failed to remove driver %s for arch [%s] - error 0x%x!\n", 
1581                                         argv[1], archi_table[i].long_archi, 
1582                                         W_ERROR_V(result));
1583                         }
1584                 } else {
1585                         printf ("Driver %s removed for arch [%s].\n", argv[1], 
1586                                 archi_table[i].long_archi);
1587                 }
1588         }
1589                 
1590         return result;
1591 }
1592
1593 /****************************************************************************
1594 ****************************************************************************/
1595
1596 static WERROR cmd_spoolss_getprintprocdir(struct rpc_pipe_client *cli, 
1597                                             TALLOC_CTX *mem_ctx,
1598                                             int argc, const char **argv)
1599 {
1600         WERROR result;
1601         char *servername = NULL, *environment = NULL;
1602         fstring procdir;
1603         
1604         /* parse the command arguements */
1605         if (argc > 2) {
1606                 printf ("Usage: %s [environment]\n", argv[0]);
1607                 return WERR_OK;
1608         }
1609
1610         if (asprintf(&servername, "\\\\%s", cli->cli->desthost) < 0)
1611                 return WERR_NOMEM;
1612         strupper_m(servername);
1613
1614         if (asprintf(&environment, "%s", (argc == 2) ? argv[1] : 
1615                      PRINTER_DRIVER_ARCHITECTURE) < 0) {
1616                 SAFE_FREE(servername);
1617                 return WERR_NOMEM;
1618         }
1619
1620         result = rpccli_spoolss_getprintprocessordirectory(
1621                 cli, mem_ctx, servername, environment, procdir);
1622
1623         if (W_ERROR_IS_OK(result))
1624                 printf("%s\n", procdir);
1625
1626         SAFE_FREE(servername);
1627         SAFE_FREE(environment);
1628
1629         return result;
1630 }
1631
1632 /****************************************************************************
1633 ****************************************************************************/
1634
1635 static WERROR cmd_spoolss_addform(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
1636                                     int argc, const char **argv)
1637 {
1638         POLICY_HND handle;
1639         WERROR werror;
1640         char *servername = NULL, *printername = NULL;
1641         FORM form;
1642         BOOL got_handle = False;
1643         
1644         /* Parse the command arguements */
1645
1646         if (argc != 3) {
1647                 printf ("Usage: %s <printer> <formname>\n", argv[0]);
1648                 return WERR_OK;
1649         }
1650         
1651         /* Get a printer handle */
1652
1653         asprintf(&servername, "\\\\%s", cli->cli->desthost);
1654         strupper_m(servername);
1655         asprintf(&printername, "%s\\%s", servername, argv[1]);
1656
1657         werror = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername, "", 
1658                                              PRINTER_ALL_ACCESS, 
1659                                              servername, cli->user_name, &handle);
1660
1661         if (!W_ERROR_IS_OK(werror))
1662                 goto done;
1663
1664         got_handle = True;
1665
1666         /* Dummy up some values for the form data */
1667
1668         form.flags = FORM_USER;
1669         form.size_x = form.size_y = 100;
1670         form.left = 0;
1671         form.top = 10;
1672         form.right = 20;
1673         form.bottom = 30;
1674
1675         init_unistr2(&form.name, argv[2], UNI_STR_TERMINATE);
1676
1677         /* Add the form */
1678
1679
1680         werror = rpccli_spoolss_addform(cli, mem_ctx, &handle, 1, &form);
1681
1682  done:
1683         if (got_handle)
1684                 rpccli_spoolss_close_printer(cli, mem_ctx, &handle);
1685
1686         SAFE_FREE(servername);
1687         SAFE_FREE(printername);
1688
1689         return werror;
1690 }
1691
1692 /****************************************************************************
1693 ****************************************************************************/
1694
1695 static WERROR cmd_spoolss_setform(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
1696                                     int argc, const char **argv)
1697 {
1698         POLICY_HND handle;
1699         WERROR werror;
1700         char *servername = NULL, *printername = NULL;
1701         FORM form;
1702         BOOL got_handle = False;
1703         
1704         /* Parse the command arguements */
1705
1706         if (argc != 3) {
1707                 printf ("Usage: %s <printer> <formname>\n", argv[0]);
1708                 return WERR_OK;
1709         }
1710         
1711         /* Get a printer handle */
1712
1713         asprintf(&servername, "\\\\%s", cli->cli->desthost);
1714         strupper_m(servername);
1715         asprintf(&printername, "%s\\%s", servername, argv[1]);
1716
1717         werror = rpccli_spoolss_open_printer_ex(
1718                 cli, mem_ctx, printername, "", MAXIMUM_ALLOWED_ACCESS, 
1719                 servername, cli->user_name, &handle);
1720
1721         if (!W_ERROR_IS_OK(werror))
1722                 goto done;
1723
1724         got_handle = True;
1725
1726         /* Dummy up some values for the form data */
1727
1728         form.flags = FORM_PRINTER;
1729         form.size_x = form.size_y = 100;
1730         form.left = 0;
1731         form.top = 1000;
1732         form.right = 2000;
1733         form.bottom = 3000;
1734
1735         init_unistr2(&form.name, argv[2], UNI_STR_TERMINATE);
1736
1737         /* Set the form */
1738
1739         werror = rpccli_spoolss_setform(cli, mem_ctx, &handle, 1, argv[2], &form);
1740
1741  done:
1742         if (got_handle)
1743                 rpccli_spoolss_close_printer(cli, mem_ctx, &handle);
1744
1745         SAFE_FREE(servername);
1746         SAFE_FREE(printername);
1747
1748         return werror;
1749 }
1750
1751 /****************************************************************************
1752 ****************************************************************************/
1753
1754 static const char *get_form_flag(int form_flag)
1755 {
1756         switch (form_flag) {
1757         case FORM_USER:
1758                 return "FORM_USER";
1759         case FORM_BUILTIN:
1760                 return "FORM_BUILTIN";
1761         case FORM_PRINTER:
1762                 return "FORM_PRINTER";
1763         default:
1764                 return "unknown";
1765         }
1766 }
1767
1768 /****************************************************************************
1769 ****************************************************************************/
1770
1771 static void display_form(FORM_1 *form)
1772 {
1773         fstring form_name = "";
1774
1775         if (form->name.buffer)
1776                 rpcstr_pull(form_name, form->name.buffer,
1777                             sizeof(form_name), -1, STR_TERMINATE);
1778
1779         printf("%s\n" \
1780                 "\tflag: %s (%d)\n" \
1781                 "\twidth: %d, length: %d\n" \
1782                 "\tleft: %d, right: %d, top: %d, bottom: %d\n\n", 
1783                 form_name, get_form_flag(form->flag), form->flag,
1784                 form->width, form->length, 
1785                 form->left, form->right, 
1786                 form->top, form->bottom);
1787 }
1788
1789 /****************************************************************************
1790 ****************************************************************************/
1791
1792 static WERROR cmd_spoolss_getform(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
1793                                     int argc, const char **argv)
1794 {
1795         POLICY_HND handle;
1796         WERROR werror;
1797         char *servername = NULL, *printername = NULL;
1798         FORM_1 form;
1799         BOOL got_handle = False;
1800         
1801         /* Parse the command arguements */
1802
1803         if (argc != 3) {
1804                 printf ("Usage: %s <printer> <formname>\n", argv[0]);
1805                 return WERR_OK;
1806         }
1807         
1808         /* Get a printer handle */
1809
1810         asprintf(&servername, "\\\\%s", cli->cli->desthost);
1811         strupper_m(servername);
1812         asprintf(&printername, "%s\\%s", servername, argv[1]);
1813
1814         werror = rpccli_spoolss_open_printer_ex(
1815                 cli, mem_ctx, printername, "", MAXIMUM_ALLOWED_ACCESS, 
1816                 servername, cli->user_name, &handle);
1817
1818         if (!W_ERROR_IS_OK(werror))
1819                 goto done;
1820
1821         got_handle = True;
1822
1823         /* Get the form */
1824
1825         werror = rpccli_spoolss_getform(cli, mem_ctx, &handle, argv[2], 1, &form);
1826
1827         if (!W_ERROR_IS_OK(werror))
1828                 goto done;
1829
1830         display_form(&form);
1831
1832  done:
1833         if (got_handle)
1834                 rpccli_spoolss_close_printer(cli, mem_ctx, &handle);
1835
1836         SAFE_FREE(servername);
1837         SAFE_FREE(printername);
1838
1839         return werror;
1840 }
1841
1842 /****************************************************************************
1843 ****************************************************************************/
1844
1845 static WERROR cmd_spoolss_deleteform(struct rpc_pipe_client *cli, 
1846                                        TALLOC_CTX *mem_ctx, int argc, 
1847                                        const char **argv)
1848 {
1849         POLICY_HND handle;
1850         WERROR werror;
1851         char *servername = NULL, *printername = NULL;
1852         BOOL got_handle = False;
1853         
1854         /* Parse the command arguements */
1855
1856         if (argc != 3) {
1857                 printf ("Usage: %s <printer> <formname>\n", argv[0]);
1858                 return WERR_OK;
1859         }
1860         
1861         /* Get a printer handle */
1862
1863         asprintf(&servername, "\\\\%s", cli->cli->desthost);
1864         strupper_m(servername);
1865         asprintf(&printername, "%s\\%s", servername, argv[1]);
1866
1867         werror = rpccli_spoolss_open_printer_ex(
1868                 cli, mem_ctx, printername, "", MAXIMUM_ALLOWED_ACCESS, 
1869                 servername, cli->user_name, &handle);
1870
1871         if (!W_ERROR_IS_OK(werror))
1872                 goto done;
1873
1874         got_handle = True;
1875
1876         /* Delete the form */
1877
1878         werror = rpccli_spoolss_deleteform(cli, mem_ctx, &handle, argv[2]);
1879
1880  done:
1881         if (got_handle)
1882                 rpccli_spoolss_close_printer(cli, mem_ctx, &handle);
1883
1884         SAFE_FREE(servername);
1885         SAFE_FREE(printername);
1886
1887         return werror;
1888 }
1889
1890 /****************************************************************************
1891 ****************************************************************************/
1892
1893 static WERROR cmd_spoolss_enum_forms(struct rpc_pipe_client *cli, 
1894                                        TALLOC_CTX *mem_ctx, int argc, 
1895                                        const char **argv)
1896 {
1897         POLICY_HND handle;
1898         WERROR werror;
1899         char *servername = NULL, *printername = NULL;
1900         BOOL got_handle = False;
1901         uint32 num_forms, level = 1, i;
1902         FORM_1 *forms;
1903         
1904         /* Parse the command arguements */
1905
1906         if (argc != 2) {
1907                 printf ("Usage: %s <printer>\n", argv[0]);
1908                 return WERR_OK;
1909         }
1910         
1911         /* Get a printer handle */
1912
1913         asprintf(&servername, "\\\\%s", cli->cli->desthost);
1914         strupper_m(servername);
1915         asprintf(&printername, "%s\\%s", servername, argv[1]);
1916
1917         werror = rpccli_spoolss_open_printer_ex(
1918                 cli, mem_ctx, printername, "", MAXIMUM_ALLOWED_ACCESS, 
1919                 servername, cli->user_name, &handle);
1920
1921         if (!W_ERROR_IS_OK(werror))
1922                 goto done;
1923
1924         got_handle = True;
1925
1926         /* Enumerate forms */
1927
1928         werror = rpccli_spoolss_enumforms(cli, mem_ctx, &handle, level, &num_forms, &forms);
1929
1930         if (!W_ERROR_IS_OK(werror))
1931                 goto done;
1932
1933         /* Display output */
1934
1935         for (i = 0; i < num_forms; i++) {
1936
1937                 display_form(&forms[i]);
1938
1939         }
1940
1941  done:
1942         if (got_handle)
1943                 rpccli_spoolss_close_printer(cli, mem_ctx, &handle);
1944
1945         SAFE_FREE(servername);
1946         SAFE_FREE(printername);
1947
1948         return werror;
1949 }
1950
1951 /****************************************************************************
1952 ****************************************************************************/
1953
1954 static WERROR cmd_spoolss_setprinterdata(struct rpc_pipe_client *cli,
1955                                             TALLOC_CTX *mem_ctx,
1956                                             int argc, const char **argv)
1957 {
1958         WERROR result;
1959         fstring servername, printername, user;
1960         POLICY_HND pol;
1961         BOOL opened_hnd = False;
1962         PRINTER_INFO_CTR ctr;
1963         PRINTER_INFO_0 info;
1964         REGISTRY_VALUE value;
1965
1966         /* parse the command arguements */
1967         if (argc < 5) {
1968                 printf ("Usage: %s <printer> <string|binary|dword|multistring>"
1969                         " <value> <data>\n",
1970                         argv[0]);
1971                 return WERR_INVALID_PARAM;
1972         }
1973
1974         slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->cli->desthost);
1975         strupper_m(servername);
1976         slprintf(printername, sizeof(servername)-1, "%s\\%s", servername, argv[1]);
1977         fstrcpy(user, cli->user_name);
1978
1979         value.type = REG_NONE;
1980
1981         if (strequal(argv[2], "string")) {
1982                 value.type = REG_SZ;
1983         }
1984
1985         if (strequal(argv[2], "binary")) {
1986                 value.type = REG_BINARY;
1987         }
1988
1989         if (strequal(argv[2], "dword")) {
1990                 value.type = REG_DWORD;
1991         }
1992
1993         if (strequal(argv[2], "multistring")) {
1994                 value.type = REG_MULTI_SZ;
1995         }
1996
1997         if (value.type == REG_NONE) {
1998                 printf("Unknown data type: %s\n", argv[2]);
1999                 return WERR_INVALID_PARAM;
2000         }
2001
2002         /* get a printer handle */
2003         result = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername, "",
2004                                              MAXIMUM_ALLOWED_ACCESS, servername, 
2005                                              user, &pol);
2006         if (!W_ERROR_IS_OK(result))
2007                 goto done;
2008
2009         opened_hnd = True;
2010
2011         ctr.printers_0 = &info;
2012
2013         result = rpccli_spoolss_getprinter(cli, mem_ctx, &pol, 0, &ctr);
2014
2015         if (!W_ERROR_IS_OK(result))
2016                 goto done;
2017                 
2018         printf("%s\n", current_timestring(True));
2019         printf("\tchange_id (before set)\t:[0x%x]\n", info.change_id);
2020
2021         /* Set the printer data */
2022         
2023         fstrcpy(value.valuename, argv[3]);
2024
2025         switch (value.type) {
2026         case REG_SZ: {
2027                 UNISTR2 data;
2028                 init_unistr2(&data, argv[4], UNI_STR_TERMINATE);
2029                 value.size = data.uni_str_len * 2;
2030                 if (value.size) {
2031                         value.data_p = (uint8 *)TALLOC_MEMDUP(mem_ctx, data.buffer,
2032                                                       value.size);
2033                 } else {
2034                         value.data_p = NULL;
2035                 }
2036                 break;
2037         }
2038         case REG_DWORD: {
2039                 uint32 data = strtoul(argv[4], NULL, 10);
2040                 value.size = sizeof(data);
2041                 if (sizeof(data)) {
2042                         value.data_p = (uint8 *)TALLOC_MEMDUP(mem_ctx, &data,
2043                                                       sizeof(data));
2044                 } else {
2045                         value.data_p = NULL;
2046                 }
2047                 break;
2048         }
2049         case REG_BINARY: {
2050                 DATA_BLOB data = strhex_to_data_blob(mem_ctx, argv[4]);
2051                 value.data_p = data.data;
2052                 value.size = data.length;
2053                 break;
2054         }
2055         case REG_MULTI_SZ: {
2056                 int i;
2057                 size_t len = 0;
2058                 char *p;
2059
2060                 for (i=4; i<argc; i++) {
2061                         if (strcmp(argv[i], "NULL") == 0) {
2062                                 argv[i] = "";
2063                         }
2064                         len += strlen(argv[i])+1;
2065                 }
2066
2067                 value.size = len*2;
2068                 value.data_p = TALLOC_ARRAY(mem_ctx, unsigned char, value.size);
2069                 if (value.data_p == NULL) {
2070                         result = WERR_NOMEM;
2071                         goto done;
2072                 }
2073
2074                 p = (char *)value.data_p;
2075                 len = value.size;
2076                 for (i=4; i<argc; i++) {
2077                         size_t l = (strlen(argv[i])+1)*2;
2078                         rpcstr_push(p, argv[i], len, STR_TERMINATE);
2079                         p += l;
2080                         len -= l;
2081                 }
2082                 SMB_ASSERT(len == 0);
2083                 break;
2084         }
2085         default:
2086                 printf("Unknown data type: %s\n", argv[2]);
2087                 result = WERR_INVALID_PARAM;
2088                 goto done;
2089         }
2090
2091         result = rpccli_spoolss_setprinterdata(cli, mem_ctx, &pol, &value);
2092                 
2093         if (!W_ERROR_IS_OK(result)) {
2094                 printf ("Unable to set [%s=%s]!\n", argv[3], argv[4]);
2095                 goto done;
2096         }
2097         printf("\tSetPrinterData succeeded [%s: %s]\n", argv[3], argv[4]);
2098         
2099         result = rpccli_spoolss_getprinter(cli, mem_ctx, &pol, 0, &ctr);
2100
2101         if (!W_ERROR_IS_OK(result))
2102                 goto done;
2103                 
2104         printf("%s\n", current_timestring(True));
2105         printf("\tchange_id (after set)\t:[0x%x]\n", info.change_id);
2106
2107 done:
2108         /* cleanup */
2109         if (opened_hnd)
2110                 rpccli_spoolss_close_printer(cli, mem_ctx, &pol);
2111
2112         return result;
2113 }
2114
2115 /****************************************************************************
2116 ****************************************************************************/
2117
2118 static void display_job_info_1(JOB_INFO_1 *job)
2119 {
2120         fstring username = "", document = "", text_status = "";
2121
2122         rpcstr_pull(username, job->username.buffer,
2123                     sizeof(username), -1, STR_TERMINATE);
2124
2125         rpcstr_pull(document, job->document.buffer,
2126                     sizeof(document), -1, STR_TERMINATE);
2127
2128         rpcstr_pull(text_status, job->text_status.buffer,
2129                     sizeof(text_status), -1, STR_TERMINATE);
2130
2131         printf("%d: jobid[%d]: %s %s %s %d/%d pages\n", job->position, job->jobid,
2132                username, document, text_status, job->pagesprinted,
2133                job->totalpages);
2134 }
2135
2136 /****************************************************************************
2137 ****************************************************************************/
2138
2139 static void display_job_info_2(JOB_INFO_2 *job)
2140 {
2141         fstring username = "", document = "", text_status = "";
2142
2143         rpcstr_pull(username, job->username.buffer,
2144                     sizeof(username), -1, STR_TERMINATE);
2145
2146         rpcstr_pull(document, job->document.buffer,
2147                     sizeof(document), -1, STR_TERMINATE);
2148
2149         rpcstr_pull(text_status, job->text_status.buffer,
2150                     sizeof(text_status), -1, STR_TERMINATE);
2151
2152         printf("%d: jobid[%d]: %s %s %s %d/%d pages, %d bytes\n", job->position, job->jobid,
2153                username, document, text_status, job->pagesprinted,
2154                job->totalpages, job->size);
2155 }
2156
2157 /****************************************************************************
2158 ****************************************************************************/
2159
2160 static WERROR cmd_spoolss_enum_jobs(struct rpc_pipe_client *cli, 
2161                                       TALLOC_CTX *mem_ctx, int argc, 
2162                                       const char **argv)
2163 {
2164         WERROR result;
2165         uint32 level = 1, num_jobs, i;
2166         BOOL got_hnd = False;
2167         pstring printername;
2168         fstring servername, user;
2169         POLICY_HND hnd;
2170         JOB_INFO_CTR ctr;
2171         
2172         if (argc < 2 || argc > 3) {
2173                 printf("Usage: %s printername [level]\n", argv[0]);
2174                 return WERR_OK;
2175         }
2176         
2177         if (argc == 3)
2178                 level = atoi(argv[2]);
2179
2180         /* Open printer handle */
2181
2182         slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->cli->desthost);
2183         strupper_m(servername);
2184         fstrcpy(user, cli->user_name);
2185         slprintf(printername, sizeof(servername)-1, "\\\\%s\\", cli->cli->desthost);
2186         strupper_m(printername);
2187         pstrcat(printername, argv[1]);
2188
2189         result = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername, 
2190                                              "", MAXIMUM_ALLOWED_ACCESS, 
2191                                              servername, user, &hnd);
2192
2193         if (!W_ERROR_IS_OK(result))
2194                 goto done;
2195  
2196         got_hnd = True;
2197
2198         /* Enumerate ports */
2199
2200         result = rpccli_spoolss_enumjobs(cli, mem_ctx, &hnd, level, 0, 1000,
2201                 &num_jobs, &ctr);
2202
2203         if (!W_ERROR_IS_OK(result))
2204                 goto done;
2205
2206         for (i = 0; i < num_jobs; i++) {
2207                 switch(level) {
2208                 case 1:
2209                         display_job_info_1(&ctr.job.job_info_1[i]);
2210                         break;
2211                 case 2:
2212                         display_job_info_2(&ctr.job.job_info_2[i]);
2213                         break;
2214                 default:
2215                         d_printf("unknown info level %d\n", level);
2216                         break;
2217                 }
2218         }
2219         
2220 done:
2221         if (got_hnd)
2222                 rpccli_spoolss_close_printer(cli, mem_ctx, &hnd);
2223
2224         return result;
2225 }
2226
2227 /****************************************************************************
2228 ****************************************************************************/
2229
2230 static WERROR cmd_spoolss_enum_data( struct rpc_pipe_client *cli, 
2231                                        TALLOC_CTX *mem_ctx, int argc, 
2232                                        const char **argv)
2233 {
2234         WERROR result;
2235         uint32 i=0, val_needed, data_needed;
2236         BOOL got_hnd = False;
2237         pstring printername;
2238         fstring servername, user;
2239         POLICY_HND hnd;
2240
2241         if (argc != 2) {
2242                 printf("Usage: %s printername\n", argv[0]);
2243                 return WERR_OK;
2244         }
2245         
2246         /* Open printer handle */
2247
2248         slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->cli->desthost);
2249         strupper_m(servername);
2250         fstrcpy(user, cli->user_name);
2251         slprintf(printername, sizeof(printername)-1, "\\\\%s\\", cli->cli->desthost);
2252         strupper_m(printername);
2253         pstrcat(printername, argv[1]);
2254
2255         result = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername, 
2256                                              "", MAXIMUM_ALLOWED_ACCESS, 
2257                                              servername, user, &hnd);
2258
2259         if (!W_ERROR_IS_OK(result))
2260                 goto done;
2261  
2262         got_hnd = True;
2263
2264         /* Enumerate data */
2265
2266         result = rpccli_spoolss_enumprinterdata(cli, mem_ctx, &hnd, i, 0, 0,
2267                                              &val_needed, &data_needed,
2268                                              NULL);
2269         while (W_ERROR_IS_OK(result)) {
2270                 REGISTRY_VALUE value;
2271                 result = rpccli_spoolss_enumprinterdata(
2272                         cli, mem_ctx, &hnd, i++, val_needed,
2273                         data_needed, 0, 0, &value);
2274                 if (W_ERROR_IS_OK(result))
2275                         display_reg_value(value);
2276         }
2277         if (W_ERROR_V(result) == ERRnomoreitems)
2278                 result = W_ERROR(ERRsuccess);
2279
2280 done:
2281         if (got_hnd)
2282                 rpccli_spoolss_close_printer(cli, mem_ctx, &hnd);
2283
2284         return result;
2285 }
2286
2287 /****************************************************************************
2288 ****************************************************************************/
2289
2290 static WERROR cmd_spoolss_enum_data_ex( struct rpc_pipe_client *cli, 
2291                                           TALLOC_CTX *mem_ctx, int argc, 
2292                                           const char **argv)
2293 {
2294         WERROR result;
2295         uint32 i;
2296         BOOL got_hnd = False;
2297         pstring printername;
2298         fstring servername, user;
2299         const char *keyname = NULL;
2300         POLICY_HND hnd;
2301         REGVAL_CTR *ctr = NULL;
2302
2303         if (argc != 3) {
2304                 printf("Usage: %s printername <keyname>\n", argv[0]);
2305                 return WERR_OK;
2306         }
2307         
2308         keyname = argv[2];
2309
2310         /* Open printer handle */
2311
2312         slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->cli->desthost);
2313         strupper_m(servername);
2314         fstrcpy(user, cli->user_name);
2315         slprintf(printername, sizeof(printername)-1, "\\\\%s\\", cli->cli->desthost);
2316         strupper_m(printername);
2317         pstrcat(printername, argv[1]);
2318
2319         result = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername, 
2320                                              "", MAXIMUM_ALLOWED_ACCESS, 
2321                                              servername, user, &hnd);
2322
2323         if (!W_ERROR_IS_OK(result))
2324                 goto done;
2325  
2326         got_hnd = True;
2327
2328         /* Enumerate subkeys */
2329
2330         if ( !(ctr = TALLOC_ZERO_P( mem_ctx, REGVAL_CTR )) ) 
2331                 return WERR_NOMEM;
2332
2333         result = rpccli_spoolss_enumprinterdataex(cli, mem_ctx, &hnd, keyname, ctr);
2334
2335         if (!W_ERROR_IS_OK(result))
2336                 goto done;
2337
2338         for (i=0; i < ctr->num_values; i++) {
2339                 display_reg_value(*(ctr->values[i]));
2340         }
2341
2342         TALLOC_FREE( ctr );
2343
2344 done:
2345         if (got_hnd)
2346                 rpccli_spoolss_close_printer(cli, mem_ctx, &hnd);
2347
2348         return result;
2349 }
2350
2351 /****************************************************************************
2352 ****************************************************************************/
2353
2354 static WERROR cmd_spoolss_enum_printerkey( struct rpc_pipe_client *cli, 
2355                                              TALLOC_CTX *mem_ctx, int argc, 
2356                                              const char **argv)
2357 {
2358         WERROR result;
2359         BOOL got_hnd = False;
2360         pstring printername;
2361         fstring servername, user;
2362         const char *keyname = NULL;
2363         POLICY_HND hnd;
2364         uint16 *keylist = NULL, *curkey;
2365
2366         if (argc < 2 || argc > 3) {
2367                 printf("Usage: %s printername [keyname]\n", argv[0]);
2368                 return WERR_OK;
2369         }
2370                 
2371         if (argc == 3)
2372                 keyname = argv[2];
2373         else
2374                 keyname = "";
2375
2376         /* Open printer handle */
2377
2378         slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->cli->desthost);
2379         strupper_m(servername);
2380         fstrcpy(user, cli->user_name);
2381         slprintf(printername, sizeof(printername)-1, "\\\\%s\\", cli->cli->desthost);
2382         strupper_m(printername);
2383         pstrcat(printername, argv[1]);
2384
2385         result = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername, 
2386                                              "", MAXIMUM_ALLOWED_ACCESS, 
2387                                              servername, user, &hnd);
2388
2389         if (!W_ERROR_IS_OK(result))
2390                 goto done;
2391          
2392         got_hnd = True;
2393
2394         /* Enumerate subkeys */
2395
2396         result = rpccli_spoolss_enumprinterkey(cli, mem_ctx, &hnd, keyname, &keylist, NULL);
2397
2398         if (!W_ERROR_IS_OK(result))
2399                 goto done;
2400
2401         curkey = keylist;
2402         while (*curkey != 0) {
2403                 pstring subkey;
2404                 rpcstr_pull(subkey, curkey, sizeof(subkey), -1, 
2405                             STR_TERMINATE);
2406                 printf("%s\n", subkey);
2407                 curkey += strlen(subkey) + 1;
2408         }
2409
2410 done:
2411
2412         SAFE_FREE(keylist);
2413
2414         if (got_hnd)
2415                 rpccli_spoolss_close_printer(cli, mem_ctx, &hnd);
2416
2417         return result;
2418 }
2419
2420 /****************************************************************************
2421 ****************************************************************************/
2422
2423 static WERROR cmd_spoolss_rffpcnex(struct rpc_pipe_client *cli, 
2424                                      TALLOC_CTX *mem_ctx, int argc, 
2425                                      const char **argv)
2426 {
2427         fstring servername, printername;
2428         POLICY_HND hnd;
2429         BOOL got_hnd = False;
2430         WERROR result;
2431         SPOOL_NOTIFY_OPTION option;
2432
2433         if (argc != 2) {
2434                 printf("Usage: %s printername\n", argv[0]);
2435                 result = WERR_OK;
2436                 goto done;
2437         }
2438
2439         /* Open printer */
2440
2441         slprintf(servername, sizeof(servername) - 1, "\\\\%s", cli->cli->desthost);
2442         strupper_m(servername);
2443
2444         slprintf(printername, sizeof(printername) - 1, "\\\\%s\\%s", cli->cli->desthost,
2445                  argv[1]);
2446         strupper_m(printername);
2447
2448         result = rpccli_spoolss_open_printer_ex(
2449                 cli, mem_ctx, printername, "", MAXIMUM_ALLOWED_ACCESS, 
2450                 servername, cli->user_name, &hnd);
2451
2452         if (!W_ERROR_IS_OK(result)) {
2453                 printf("Error opening %s\n", argv[1]);
2454                 goto done;
2455         }
2456
2457         got_hnd = True;
2458
2459         /* Create spool options */
2460
2461         ZERO_STRUCT(option);
2462
2463         option.version = 2;
2464         option.option_type_ptr = 1;
2465         option.count = option.ctr.count = 2;
2466
2467         option.ctr.type = TALLOC_ARRAY(mem_ctx, SPOOL_NOTIFY_OPTION_TYPE, 2);
2468         if (option.ctr.type == NULL) {
2469                 result = WERR_NOMEM;
2470                 goto done;
2471         }
2472
2473         ZERO_STRUCT(option.ctr.type[0]);
2474         option.ctr.type[0].type = PRINTER_NOTIFY_TYPE;
2475         option.ctr.type[0].count = option.ctr.type[0].count2 = 1;
2476         option.ctr.type[0].fields_ptr = 1;
2477         option.ctr.type[0].fields[0] = PRINTER_NOTIFY_SERVER_NAME;
2478
2479         ZERO_STRUCT(option.ctr.type[1]);
2480         option.ctr.type[1].type = JOB_NOTIFY_TYPE;
2481         option.ctr.type[1].count = option.ctr.type[1].count2 = 1;
2482         option.ctr.type[1].fields_ptr = 1;
2483         option.ctr.type[1].fields[0] = JOB_NOTIFY_PRINTER_NAME;
2484
2485         /* Send rffpcnex */
2486
2487         slprintf(servername, sizeof(servername) - 1, "\\\\%s", myhostname());
2488         strupper_m(servername);
2489
2490         result = rpccli_spoolss_rffpcnex(
2491                 cli, mem_ctx, &hnd, 0, 0, servername, 123, &option);
2492
2493         if (!W_ERROR_IS_OK(result)) {
2494                 printf("Error rffpcnex %s\n", argv[1]);
2495                 goto done;
2496         }
2497
2498 done:           
2499         if (got_hnd)
2500                 rpccli_spoolss_close_printer(cli, mem_ctx, &hnd);
2501
2502         return result;
2503 }
2504
2505 /****************************************************************************
2506 ****************************************************************************/
2507
2508 static BOOL compare_printer( struct rpc_pipe_client *cli1, POLICY_HND *hnd1,
2509                              struct rpc_pipe_client *cli2, POLICY_HND *hnd2 )
2510 {
2511         PRINTER_INFO_CTR ctr1, ctr2;
2512         WERROR werror;
2513         TALLOC_CTX *mem_ctx = talloc_init("compare_printer");
2514
2515         printf("Retrieving printer propertiesfor %s...", cli1->cli->desthost);
2516         werror = rpccli_spoolss_getprinter( cli1, mem_ctx, hnd1, 2, &ctr1);
2517         if ( !W_ERROR_IS_OK(werror) ) {
2518                 printf("failed (%s)\n", dos_errstr(werror));
2519                 talloc_destroy(mem_ctx);
2520                 return False;
2521         }
2522         printf("ok\n");
2523
2524         printf("Retrieving printer properties for %s...", cli2->cli->desthost);
2525         werror = rpccli_spoolss_getprinter( cli2, mem_ctx, hnd2, 2, &ctr2);
2526         if ( !W_ERROR_IS_OK(werror) ) {
2527                 printf("failed (%s)\n", dos_errstr(werror));
2528                 talloc_destroy(mem_ctx);
2529                 return False;
2530         }
2531         printf("ok\n");
2532
2533         talloc_destroy(mem_ctx);
2534
2535         return True;
2536 }
2537
2538 /****************************************************************************
2539 ****************************************************************************/
2540
2541 static BOOL compare_printer_secdesc( struct rpc_pipe_client *cli1, POLICY_HND *hnd1,
2542                                      struct rpc_pipe_client *cli2, POLICY_HND *hnd2 )
2543 {
2544         PRINTER_INFO_CTR ctr1, ctr2;
2545         WERROR werror;
2546         TALLOC_CTX *mem_ctx = talloc_init("compare_printer_secdesc");
2547         SEC_DESC *sd1, *sd2;
2548         BOOL result = True;
2549
2550
2551         printf("Retreiving printer security for %s...", cli1->cli->desthost);
2552         werror = rpccli_spoolss_getprinter( cli1, mem_ctx, hnd1, 3, &ctr1);
2553         if ( !W_ERROR_IS_OK(werror) ) {
2554                 printf("failed (%s)\n", dos_errstr(werror));
2555                 result = False;
2556                 goto done;
2557         }
2558         printf("ok\n");
2559
2560         printf("Retrieving printer security for %s...", cli2->cli->desthost);
2561         werror = rpccli_spoolss_getprinter( cli2, mem_ctx, hnd2, 3, &ctr2);
2562         if ( !W_ERROR_IS_OK(werror) ) {
2563                 printf("failed (%s)\n", dos_errstr(werror));
2564                 result = False;
2565                 goto done;
2566         }
2567         printf("ok\n");
2568         
2569
2570         printf("++ ");
2571
2572         if ( (ctr1.printers_3 != ctr2.printers_3) && (!ctr1.printers_3 || !ctr2.printers_3) ) {
2573                 printf("NULL PRINTER_INFO_3!\n");
2574                 result = False;
2575                 goto done;
2576         }
2577         
2578         sd1 = ctr1.printers_3->secdesc;
2579         sd2 = ctr2.printers_3->secdesc;
2580         
2581         if ( (sd1 != sd2) && ( !sd1 || !sd2 ) ) {
2582                 printf("NULL secdesc!\n");
2583                 result = False;
2584                 goto done;
2585         }
2586         
2587         if (!sec_desc_equal( sd1, sd2 ) ) {
2588                 printf("Security Descriptors *not* equal!\n");
2589                 result = False;
2590                 goto done;
2591         }
2592         
2593         printf("Security descriptors match\n");
2594         
2595 done:
2596         talloc_destroy(mem_ctx);
2597         return result;
2598 }
2599
2600
2601 /****************************************************************************
2602 ****************************************************************************/
2603
2604 static WERROR cmd_spoolss_printercmp(struct rpc_pipe_client *cli, 
2605                                      TALLOC_CTX *mem_ctx, int argc, 
2606                                      const char **argv)
2607 {
2608         fstring printername, servername1, servername2;
2609         pstring printername_path;
2610         struct cli_state *cli_server1 = cli->cli;
2611         struct cli_state *cli_server2 = NULL;
2612         struct rpc_pipe_client *cli2 = NULL;
2613         POLICY_HND hPrinter1, hPrinter2;
2614         NTSTATUS nt_status;
2615         WERROR werror;
2616         
2617         if ( argc != 3 )  {
2618                 printf("Usage: %s <printer> <server>\n", argv[0]);
2619                 return WERR_OK;
2620         }
2621         
2622         fstrcpy( printername, argv[1] );
2623         
2624         fstr_sprintf( servername1, cli->cli->desthost );
2625         fstrcpy( servername2, argv[2] );
2626         strupper_m( servername1 );
2627         strupper_m( servername2 );
2628         
2629         
2630         /* first get the connection to the remote server */
2631         
2632         nt_status = cli_full_connection(&cli_server2, global_myname(), servername2, 
2633                                         NULL, 0,
2634                                         "IPC$", "IPC",  
2635                                         cmdline_auth_info.username, 
2636                                         lp_workgroup(),
2637                                         cmdline_auth_info.password, 
2638                                         cmdline_auth_info.use_kerberos ? CLI_FULL_CONNECTION_USE_KERBEROS : 0,
2639                                         cmdline_auth_info.signing_state, NULL);
2640                                         
2641         if ( !NT_STATUS_IS_OK(nt_status) )
2642                 return WERR_GENERAL_FAILURE;
2643
2644         cli2 = cli_rpc_pipe_open_noauth(cli_server2, PI_SPOOLSS, &nt_status);
2645         if (!cli2) {
2646                 printf("failed to open spoolss pipe on server %s (%s)\n",
2647                         servername2, nt_errstr(nt_status));
2648                 return WERR_GENERAL_FAILURE;
2649         }
2650                                         
2651         /* now open up both printers */
2652
2653         pstr_sprintf( printername_path, "\\\\%s\\%s", servername1, printername );
2654         printf("Opening %s...", printername_path);
2655         werror = rpccli_spoolss_open_printer_ex( cli, mem_ctx, printername_path, 
2656                 "", PRINTER_ALL_ACCESS, servername1, cli_server1->user_name, &hPrinter1);
2657         if ( !W_ERROR_IS_OK(werror) ) {
2658                 printf("failed (%s)\n", dos_errstr(werror));
2659                 goto done;
2660         }
2661         printf("ok\n");
2662         
2663         pstr_sprintf( printername_path, "\\\\%s\\%s", servername2, printername );
2664         printf("Opening %s...", printername_path);
2665         werror = rpccli_spoolss_open_printer_ex( cli2, mem_ctx, printername_path,  
2666                 "", PRINTER_ALL_ACCESS, servername2, cli_server2->user_name, &hPrinter2 );
2667         if ( !W_ERROR_IS_OK(werror) ) {
2668                  printf("failed (%s)\n", dos_errstr(werror));
2669                 goto done;
2670         }
2671         printf("ok\n");
2672         
2673         
2674         compare_printer( cli, &hPrinter1, cli2, &hPrinter2 );
2675         compare_printer_secdesc( cli, &hPrinter1, cli2, &hPrinter2 );
2676 #if 0
2677         compare_printerdata( cli_server1, &hPrinter1, cli_server2, &hPrinter2 );
2678 #endif
2679
2680
2681 done:
2682         /* cleanup */
2683
2684         printf("Closing printers...");  
2685         rpccli_spoolss_close_printer( cli, mem_ctx, &hPrinter1 );
2686         rpccli_spoolss_close_printer( cli2, mem_ctx, &hPrinter2 );
2687         printf("ok\n");
2688         
2689         /* close the second remote connection */
2690         
2691         cli_shutdown( cli_server2 );
2692         
2693         return WERR_OK;
2694 }
2695
2696 /* List of commands exported by this module */
2697 struct cmd_set spoolss_commands[] = {
2698
2699         { "SPOOLSS"  },
2700
2701         { "adddriver",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_addprinterdriver,   PI_SPOOLSS, NULL, "Add a print driver",                  "" },
2702         { "addprinter",         RPC_RTYPE_WERROR, NULL, cmd_spoolss_addprinterex,       PI_SPOOLSS, NULL, "Add a printer",                       "" },
2703         { "deldriver",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_deletedriver,       PI_SPOOLSS, NULL, "Delete a printer driver",             "" },
2704         { "deldriverex",        RPC_RTYPE_WERROR, NULL, cmd_spoolss_deletedriverex,     PI_SPOOLSS, NULL, "Delete a printer driver with files",  "" },
2705         { "enumdata",           RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_data,          PI_SPOOLSS, NULL, "Enumerate printer data",              "" },
2706         { "enumdataex",         RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_data_ex,       PI_SPOOLSS, NULL, "Enumerate printer data for a key",    "" },
2707         { "enumkey",            RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_printerkey,    PI_SPOOLSS, NULL, "Enumerate printer keys",              "" },
2708         { "enumjobs",           RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_jobs,          PI_SPOOLSS, NULL, "Enumerate print jobs",                "" },
2709         { "enumports",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_ports,         PI_SPOOLSS, NULL, "Enumerate printer ports",             "" },
2710         { "enumdrivers",        RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_drivers,       PI_SPOOLSS, NULL, "Enumerate installed printer drivers", "" },
2711         { "enumprinters",       RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_printers,      PI_SPOOLSS, NULL, "Enumerate printers",                  "" },
2712         { "getdata",            RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprinterdata,     PI_SPOOLSS, NULL, "Get print driver data",               "" },
2713         { "getdataex",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprinterdataex,   PI_SPOOLSS, NULL, "Get printer driver data with keyname", ""},
2714         { "getdriver",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_getdriver,          PI_SPOOLSS, NULL, "Get print driver information",        "" },
2715         { "getdriverdir",       RPC_RTYPE_WERROR, NULL, cmd_spoolss_getdriverdir,       PI_SPOOLSS, NULL, "Get print driver upload directory",   "" },
2716         { "getprinter",         RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprinter,         PI_SPOOLSS, NULL, "Get printer info",                    "" },
2717         { "openprinter",        RPC_RTYPE_WERROR, NULL, cmd_spoolss_open_printer_ex,    PI_SPOOLSS, NULL, "Open printer handle",                 "" },
2718         { "setdriver",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_setdriver,          PI_SPOOLSS, NULL, "Set printer driver",                  "" },
2719         { "getprintprocdir",    RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprintprocdir,    PI_SPOOLSS, NULL, "Get print processor directory",       "" },
2720         { "addform",            RPC_RTYPE_WERROR, NULL, cmd_spoolss_addform,            PI_SPOOLSS, NULL, "Add form",                            "" },
2721         { "setform",            RPC_RTYPE_WERROR, NULL, cmd_spoolss_setform,            PI_SPOOLSS, NULL, "Set form",                            "" },
2722         { "getform",            RPC_RTYPE_WERROR, NULL, cmd_spoolss_getform,            PI_SPOOLSS, NULL, "Get form",                            "" },
2723         { "deleteform",         RPC_RTYPE_WERROR, NULL, cmd_spoolss_deleteform,         PI_SPOOLSS, NULL, "Delete form",                         "" },
2724         { "enumforms",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_forms,         PI_SPOOLSS, NULL, "Enumerate forms",                     "" },
2725         { "setprinter",         RPC_RTYPE_WERROR, NULL, cmd_spoolss_setprinter,         PI_SPOOLSS, NULL, "Set printer comment",                 "" },
2726         { "setprintername",     RPC_RTYPE_WERROR, NULL, cmd_spoolss_setprintername,     PI_SPOOLSS, NULL, "Set printername",                 "" },
2727         { "setprinterdata",     RPC_RTYPE_WERROR, NULL, cmd_spoolss_setprinterdata,     PI_SPOOLSS, NULL, "Set REG_SZ printer data",             "" },
2728         { "rffpcnex",           RPC_RTYPE_WERROR, NULL, cmd_spoolss_rffpcnex,           PI_SPOOLSS, NULL, "Rffpcnex test", "" },
2729         { "printercmp",         RPC_RTYPE_WERROR, NULL, cmd_spoolss_printercmp,         PI_SPOOLSS, NULL, "Printer comparison test", "" },
2730
2731         { NULL }
2732 };