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