r16945: Sync trunk -> 3.0 for 3.0.24 code. Still need
[ira/wip.git] / source3 / rpcclient / cmd_spoolss.c
1 /*
2    Unix SMB/CIFS implementation.
3    RPC pipe client
4
5    Copyright (C) Gerald Carter                2001-2005
6    Copyright (C) Tim Potter                        2000
7    Copyright (C) Andrew Tridgell              1992-1999
8    Copyright (C) Luke Kenneth Casson Leighton 1996-1999
9  
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 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                 int i, num_values;
713                 char **values;
714
715                 if (!NT_STATUS_IS_OK(reg_pull_multi_sz(NULL, value.data_p,
716                                                        value.size,
717                                                        &num_values,
718                                                        &values))) {
719                         d_printf("reg_pull_multi_sz failed\n");
720                         break;
721                 }
722
723                 for (i=0; i<num_values; i++) {
724                         d_printf("%s\n", values[i]);
725                 }
726                 TALLOC_FREE(values);
727                 break;
728         }
729         default:
730                 printf("%s: unknown type %d\n", value.valuename, value.type);
731         }
732         
733 }
734
735 /****************************************************************************
736 ****************************************************************************/
737
738 static WERROR cmd_spoolss_getprinterdata(struct rpc_pipe_client *cli,
739                                            TALLOC_CTX *mem_ctx,
740                                            int argc, const char **argv)
741 {
742         POLICY_HND      pol;
743         WERROR          result;
744         BOOL            opened_hnd = False;
745         fstring         printername,
746                         servername,
747                         user;
748         const char *valuename;
749         REGISTRY_VALUE value;
750
751         if (argc != 3) {
752                 printf("Usage: %s <printername> <valuename>\n", argv[0]);
753                 printf("<printername> of . queries print server\n");
754                 return WERR_OK;
755         }
756         valuename = argv[2];
757
758         /* Open a printer handle */
759
760         slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->cli->desthost);
761         strupper_m(servername);
762         if (strncmp(argv[1], ".", sizeof(".")) == 0)
763                 fstrcpy(printername, servername);
764         else
765                 slprintf(printername, sizeof(servername)-1, "%s\\%s", 
766                           servername, argv[1]);
767         fstrcpy(user, cli->user_name);
768         
769         /* get a printer handle */
770
771         result = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername, 
772                                              "", MAXIMUM_ALLOWED_ACCESS, 
773                                              servername, user, &pol);
774
775         if (!W_ERROR_IS_OK(result))
776                 goto done;
777  
778         opened_hnd = True;
779
780         /* Get printer info */
781
782         result = rpccli_spoolss_getprinterdata(cli, mem_ctx, &pol, valuename, &value);
783
784         if (!W_ERROR_IS_OK(result))
785                 goto done;
786
787         /* Display printer data */
788
789         fstrcpy(value.valuename, valuename);
790         display_reg_value(value);
791         
792
793  done: 
794         if (opened_hnd) 
795                 rpccli_spoolss_close_printer(cli, mem_ctx, &pol);
796
797         return result;
798 }
799
800 /****************************************************************************
801 ****************************************************************************/
802
803 static WERROR cmd_spoolss_getprinterdataex(struct rpc_pipe_client *cli,
804                                              TALLOC_CTX *mem_ctx,
805                                              int argc, const char **argv)
806 {
807         POLICY_HND      pol;
808         WERROR          result;
809         BOOL            opened_hnd = False;
810         fstring         printername,
811                         servername,
812                         user;
813         const char *valuename, *keyname;
814         REGISTRY_VALUE value;
815
816         if (argc != 4) {
817                 printf("Usage: %s <printername> <keyname> <valuename>\n", 
818                        argv[0]);
819                 printf("<printername> of . queries print server\n");
820                 return WERR_OK;
821         }
822         valuename = argv[3];
823         keyname = argv[2];
824
825         /* Open a printer handle */
826
827         slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->cli->desthost);
828         strupper_m(servername);
829         if (strncmp(argv[1], ".", sizeof(".")) == 0)
830                 fstrcpy(printername, servername);
831         else
832                 slprintf(printername, sizeof(printername)-1, "%s\\%s", 
833                           servername, argv[1]);
834         fstrcpy(user, cli->user_name);
835         
836         /* get a printer handle */
837
838         result = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername, 
839                                              "", MAXIMUM_ALLOWED_ACCESS, 
840                                              servername, user, &pol);
841
842         if (!W_ERROR_IS_OK(result))
843                 goto done;
844  
845         opened_hnd = True;
846
847         /* Get printer info */
848
849         result = rpccli_spoolss_getprinterdataex(cli, mem_ctx, &pol, keyname, 
850                 valuename, &value);
851
852         if (!W_ERROR_IS_OK(result))
853                 goto done;
854
855         /* Display printer data */
856
857         fstrcpy(value.valuename, valuename);
858         display_reg_value(value);
859         
860
861  done: 
862         if (opened_hnd) 
863                 rpccli_spoolss_close_printer(cli, mem_ctx, &pol);
864
865         return result;
866 }
867
868 /****************************************************************************
869 ****************************************************************************/
870
871 static void display_print_driver_1(DRIVER_INFO_1 *i1)
872 {
873         fstring name;
874         if (i1 == NULL)
875                 return;
876
877         rpcstr_pull(name, i1->name.buffer, sizeof(name), -1, STR_TERMINATE);
878
879         printf ("Printer Driver Info 1:\n");
880         printf ("\tDriver Name: [%s]\n\n", name);
881         
882         return;
883 }
884
885 /****************************************************************************
886 ****************************************************************************/
887
888 static void display_print_driver_2(DRIVER_INFO_2 *i1)
889 {
890         fstring name;
891         fstring architecture;
892         fstring driverpath;
893         fstring datafile;
894         fstring configfile;
895         if (i1 == NULL)
896                 return;
897
898         rpcstr_pull(name, i1->name.buffer, sizeof(name), -1, STR_TERMINATE);
899         rpcstr_pull(architecture, i1->architecture.buffer, sizeof(architecture), -1, STR_TERMINATE);
900         rpcstr_pull(driverpath, i1->driverpath.buffer, sizeof(driverpath), -1, STR_TERMINATE);
901         rpcstr_pull(datafile, i1->datafile.buffer, sizeof(datafile), -1, STR_TERMINATE);
902         rpcstr_pull(configfile, i1->configfile.buffer, sizeof(configfile), -1, STR_TERMINATE);
903
904         printf ("Printer Driver Info 2:\n");
905         printf ("\tVersion: [%x]\n", i1->version);
906         printf ("\tDriver Name: [%s]\n", name);
907         printf ("\tArchitecture: [%s]\n", architecture);
908         printf ("\tDriver Path: [%s]\n", driverpath);
909         printf ("\tDatafile: [%s]\n", datafile);
910         printf ("\tConfigfile: [%s]\n\n", configfile);
911
912         return;
913 }
914
915 /****************************************************************************
916 ****************************************************************************/
917
918 static void display_print_driver_3(DRIVER_INFO_3 *i1)
919 {
920         fstring name = "";
921         fstring architecture = "";
922         fstring driverpath = "";
923         fstring datafile = "";
924         fstring configfile = "";
925         fstring helpfile = "";
926         fstring dependentfiles = "";
927         fstring monitorname = "";
928         fstring defaultdatatype = "";
929         
930         int length=0;
931         BOOL valid = True;
932         
933         if (i1 == NULL)
934                 return;
935
936         rpcstr_pull(name, i1->name.buffer, sizeof(name), -1, STR_TERMINATE);
937         rpcstr_pull(architecture, i1->architecture.buffer, sizeof(architecture), -1, STR_TERMINATE);
938         rpcstr_pull(driverpath, i1->driverpath.buffer, sizeof(driverpath), -1, STR_TERMINATE);
939         rpcstr_pull(datafile, i1->datafile.buffer, sizeof(datafile), -1, STR_TERMINATE);
940         rpcstr_pull(configfile, i1->configfile.buffer, sizeof(configfile), -1, STR_TERMINATE);
941         rpcstr_pull(helpfile, i1->helpfile.buffer, sizeof(helpfile), -1, STR_TERMINATE);
942         rpcstr_pull(monitorname, i1->monitorname.buffer, sizeof(monitorname), -1, STR_TERMINATE);
943         rpcstr_pull(defaultdatatype, i1->defaultdatatype.buffer, sizeof(defaultdatatype), -1, STR_TERMINATE);
944
945         printf ("Printer Driver Info 3:\n");
946         printf ("\tVersion: [%x]\n", i1->version);
947         printf ("\tDriver Name: [%s]\n",name);
948         printf ("\tArchitecture: [%s]\n", architecture);
949         printf ("\tDriver Path: [%s]\n", driverpath);
950         printf ("\tDatafile: [%s]\n", datafile);
951         printf ("\tConfigfile: [%s]\n", configfile);
952         printf ("\tHelpfile: [%s]\n\n", helpfile);
953
954         while (valid)
955         {
956                 rpcstr_pull(dependentfiles, i1->dependentfiles+length, sizeof(dependentfiles), -1, STR_TERMINATE);
957                 
958                 length+=strlen(dependentfiles)+1;
959                 
960                 if (strlen(dependentfiles) > 0)
961                 {
962                         printf ("\tDependentfiles: [%s]\n", dependentfiles);
963                 }
964                 else
965                 {
966                         valid = False;
967                 }
968         }
969         
970         printf ("\n");
971
972         printf ("\tMonitorname: [%s]\n", monitorname);
973         printf ("\tDefaultdatatype: [%s]\n\n", defaultdatatype);
974
975         return; 
976 }
977
978 /****************************************************************************
979 ****************************************************************************/
980
981 static WERROR cmd_spoolss_getdriver(struct rpc_pipe_client *cli, 
982                                       TALLOC_CTX *mem_ctx,
983                                       int argc, const char **argv)
984 {
985         POLICY_HND      pol;
986         WERROR          werror;
987         uint32          info_level = 3;
988         BOOL            opened_hnd = False;
989         PRINTER_DRIVER_CTR      ctr;
990         fstring         printername, 
991                         servername, 
992                         user;
993         uint32          i;
994         BOOL            success = False;
995
996         if ((argc == 1) || (argc > 3)) 
997         {
998                 printf("Usage: %s <printername> [level]\n", argv[0]);
999                 return WERR_OK;
1000         }
1001
1002         /* get the arguments need to open the printer handle */
1003         slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->cli->desthost);
1004         strupper_m(servername);
1005         fstrcpy(user, cli->user_name);
1006         slprintf(printername, sizeof(servername)-1, "%s\\%s", servername, argv[1]);
1007         if (argc == 3)
1008                 info_level = atoi(argv[2]);
1009
1010         /* Open a printer handle */
1011
1012         werror = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername, "", 
1013                                              PRINTER_ACCESS_USE,
1014                                              servername, user, &pol);
1015
1016         if (!W_ERROR_IS_OK(werror)) {
1017                 printf("Error opening printer handle for %s!\n", printername);
1018                 return werror;
1019         }
1020
1021         opened_hnd = True;
1022
1023         /* loop through and print driver info level for each architecture */
1024
1025         for (i=0; archi_table[i].long_archi!=NULL; i++) {
1026
1027                 werror = rpccli_spoolss_getprinterdriver( cli, mem_ctx, &pol, info_level, 
1028                         archi_table[i].long_archi, archi_table[i].version,
1029                         &ctr);
1030
1031                 if (!W_ERROR_IS_OK(werror))
1032                         continue;
1033                 
1034                 /* need at least one success */
1035                 
1036                 success = True;
1037                         
1038                 printf ("\n[%s]\n", archi_table[i].long_archi);
1039
1040                 switch (info_level) {
1041                 case 1:
1042                         display_print_driver_1 (ctr.info1);
1043                         break;
1044                 case 2:
1045                         display_print_driver_2 (ctr.info2);
1046                         break;
1047                 case 3:
1048                         display_print_driver_3 (ctr.info3);
1049                         break;
1050                 default:
1051                         printf("unknown info level %d\n", info_level);
1052                         break;
1053                 }
1054         }
1055         
1056         /* Cleanup */
1057
1058         if (opened_hnd)
1059                 rpccli_spoolss_close_printer (cli, mem_ctx, &pol);
1060         
1061         if ( success )
1062                 werror = WERR_OK;
1063                 
1064         return werror;
1065 }
1066
1067 /****************************************************************************
1068 ****************************************************************************/
1069
1070 static WERROR cmd_spoolss_enum_drivers(struct rpc_pipe_client *cli, 
1071                                          TALLOC_CTX *mem_ctx,
1072                                          int argc, const char **argv)
1073 {
1074         WERROR werror = WERR_OK;
1075         uint32          info_level = 1;
1076         PRINTER_DRIVER_CTR      ctr;
1077         uint32          i, j,
1078                         returned;
1079
1080         if (argc > 2) {
1081                 printf("Usage: enumdrivers [level]\n");
1082                 return WERR_OK;
1083         }
1084
1085         if (argc == 2)
1086                 info_level = atoi(argv[1]);
1087
1088
1089         /* loop through and print driver info level for each architecture */
1090         for (i=0; archi_table[i].long_archi!=NULL; i++) {
1091                 /* check to see if we already asked for this architecture string */
1092
1093                 if ( i>0 && strequal(archi_table[i].long_archi, archi_table[i-1].long_archi) )
1094                         continue;
1095
1096                 werror = rpccli_spoolss_enumprinterdrivers(
1097                         cli, mem_ctx, info_level, 
1098                         archi_table[i].long_archi, &returned, &ctr);
1099
1100                 if (W_ERROR_V(werror) == W_ERROR_V(WERR_INVALID_ENVIRONMENT)) {
1101                         printf ("Server does not support environment [%s]\n", 
1102                                 archi_table[i].long_archi);
1103                         werror = WERR_OK;
1104                         continue;
1105                 }
1106
1107                 if (returned == 0)
1108                         continue;
1109                         
1110                 if (!W_ERROR_IS_OK(werror)) {
1111                         printf ("Error getting driver for environment [%s] - %d\n",
1112                                 archi_table[i].long_archi, W_ERROR_V(werror));
1113                         continue;
1114                 }
1115                 
1116                 printf ("\n[%s]\n", archi_table[i].long_archi);
1117                 switch (info_level) 
1118                 {
1119                         
1120                 case 1:
1121                         for (j=0; j < returned; j++) {
1122                                 display_print_driver_1 (&ctr.info1[j]);
1123                         }
1124                         break;
1125                 case 2:
1126                         for (j=0; j < returned; j++) {
1127                                 display_print_driver_2 (&ctr.info2[j]);
1128                         }
1129                         break;
1130                 case 3:
1131                         for (j=0; j < returned; j++) {
1132                                 display_print_driver_3 (&ctr.info3[j]);
1133                         }
1134                         break;
1135                 default:
1136                         printf("unknown info level %d\n", info_level);
1137                         return WERR_UNKNOWN_LEVEL;
1138                 }
1139         }
1140         
1141         return werror;
1142 }
1143
1144 /****************************************************************************
1145 ****************************************************************************/
1146
1147 static void display_printdriverdir_1(DRIVER_DIRECTORY_1 *i1)
1148 {
1149         fstring name;
1150         if (i1 == NULL)
1151                 return;
1152  
1153         rpcstr_pull(name, i1->name.buffer, sizeof(name), -1, STR_TERMINATE);
1154  
1155         printf ("\tDirectory Name:[%s]\n", name);
1156 }
1157
1158 /****************************************************************************
1159 ****************************************************************************/
1160
1161 static WERROR cmd_spoolss_getdriverdir(struct rpc_pipe_client *cli, 
1162                                          TALLOC_CTX *mem_ctx,
1163                                          int argc, const char **argv)
1164 {
1165         WERROR result;
1166         fstring                 env;
1167         DRIVER_DIRECTORY_CTR    ctr;
1168
1169         if (argc > 2) {
1170                 printf("Usage: %s [environment]\n", argv[0]);
1171                 return WERR_OK;
1172         }
1173
1174         /* Get the arguments need to open the printer handle */
1175
1176         if (argc == 2)
1177                 fstrcpy (env, argv[1]);
1178         else
1179                 fstrcpy (env, "Windows NT x86");
1180
1181         /* Get the directory.  Only use Info level 1 */
1182
1183         result = rpccli_spoolss_getprinterdriverdir(cli, mem_ctx, 1, env, &ctr);
1184
1185         if (W_ERROR_IS_OK(result))
1186                 display_printdriverdir_1(ctr.info1);
1187
1188         return result;
1189 }
1190
1191 /****************************************************************************
1192 ****************************************************************************/
1193
1194 void set_drv_info_3_env (DRIVER_INFO_3 *info, const char *arch)
1195 {
1196
1197         int i;
1198         
1199         for (i=0; archi_table[i].long_archi != NULL; i++) 
1200         {
1201                 if (strcmp(arch, archi_table[i].short_archi) == 0)
1202                 {
1203                         info->version = archi_table[i].version;
1204                         init_unistr (&info->architecture, archi_table[i].long_archi);
1205                         break;
1206                 }
1207         }
1208         
1209         if (archi_table[i].long_archi == NULL)
1210         {
1211                 DEBUG(0, ("set_drv_info_3_env: Unknown arch [%s]\n", arch));
1212         }
1213         
1214         return;
1215 }
1216
1217
1218 /**************************************************************************
1219  wrapper for strtok to get the next parameter from a delimited list.
1220  Needed to handle the empty parameter string denoted by "NULL"
1221  *************************************************************************/
1222  
1223 static char* get_driver_3_param (char* str, const char* delim, UNISTR* dest)
1224 {
1225         char    *ptr;
1226
1227         /* get the next token */
1228         ptr = strtok(str, delim);
1229
1230         /* a string of 'NULL' is used to represent an empty
1231            parameter because two consecutive delimiters
1232            will not return an empty string.  See man strtok(3)
1233            for details */
1234         if (ptr && (StrCaseCmp(ptr, "NULL") == 0))
1235                 ptr = NULL;
1236
1237         if (dest != NULL)
1238                 init_unistr(dest, ptr); 
1239
1240         return ptr;
1241 }
1242
1243 /********************************************************************************
1244  fill in the members of a DRIVER_INFO_3 struct using a character 
1245  string in the form of
1246          <Long Printer Name>:<Driver File Name>:<Data File Name>:\
1247              <Config File Name>:<Help File Name>:<Language Monitor Name>:\
1248              <Default Data Type>:<Comma Separated list of Files> 
1249  *******************************************************************************/
1250 static BOOL init_drv_info_3_members ( TALLOC_CTX *mem_ctx, DRIVER_INFO_3 *info, 
1251                                       char *args )
1252 {
1253         char    *str, *str2;
1254         uint32  len, i;
1255         
1256         /* fill in the UNISTR fields */
1257         str = get_driver_3_param (args, ":", &info->name);
1258         str = get_driver_3_param (NULL, ":", &info->driverpath);
1259         str = get_driver_3_param (NULL, ":", &info->datafile);
1260         str = get_driver_3_param (NULL, ":", &info->configfile);
1261         str = get_driver_3_param (NULL, ":", &info->helpfile);
1262         str = get_driver_3_param (NULL, ":", &info->monitorname);
1263         str = get_driver_3_param (NULL, ":", &info->defaultdatatype);
1264
1265         /* <Comma Separated List of Dependent Files> */
1266         str2 = get_driver_3_param (NULL, ":", NULL); /* save the beginning of the string */
1267         str = str2;                     
1268
1269         /* begin to strip out each filename */
1270         str = strtok(str, ",");         
1271         len = 0;
1272         while (str != NULL)
1273         {
1274                 /* keep a cumlative count of the str lengths */
1275                 len += strlen(str)+1;
1276                 str = strtok(NULL, ",");
1277         }
1278
1279         /* allocate the space; add one extra slot for a terminating NULL.
1280            Each filename is NULL terminated and the end contains a double
1281            NULL */
1282         if ((info->dependentfiles=TALLOC_ARRAY(mem_ctx, uint16, len+1)) == NULL)
1283         {
1284                 DEBUG(0,("init_drv_info_3_members: Unable to malloc memory for dependenfiles\n"));
1285                 return False;
1286         }
1287         for (i=0; i<len; i++)
1288         {
1289                 SSVAL(&info->dependentfiles[i], 0, str2[i]);
1290         }
1291         info->dependentfiles[len] = '\0';
1292
1293         return True;
1294 }
1295
1296
1297 /****************************************************************************
1298 ****************************************************************************/
1299
1300 static WERROR cmd_spoolss_addprinterdriver(struct rpc_pipe_client *cli, 
1301                                              TALLOC_CTX *mem_ctx,
1302                                              int argc, const char **argv)
1303 {
1304         WERROR result;
1305         uint32                  level = 3;
1306         PRINTER_DRIVER_CTR      ctr;
1307         DRIVER_INFO_3           info3;
1308         const char              *arch;
1309         fstring                 driver_name;
1310         char                    *driver_args;
1311
1312         /* parse the command arguements */
1313         if (argc != 3 && argc != 4)
1314         {
1315                 printf ("Usage: %s <Environment> \\\n", argv[0]);
1316                 printf ("\t<Long Printer Name>:<Driver File Name>:<Data File Name>:\\\n");
1317                 printf ("\t<Config File Name>:<Help File Name>:<Language Monitor Name>:\\\n");
1318                 printf ("\t<Default Data Type>:<Comma Separated list of Files> \\\n");
1319                 printf ("\t[version]\n");
1320
1321             return WERR_OK;
1322         }
1323                 
1324         /* Fill in the DRIVER_INFO_3 struct */
1325         ZERO_STRUCT(info3);
1326         if (!(arch = cmd_spoolss_get_short_archi(argv[1])))
1327         {
1328                 printf ("Error Unknown architechture [%s]\n", argv[1]);
1329                 return WERR_INVALID_PARAM;
1330         }
1331         else
1332                 set_drv_info_3_env(&info3, arch);
1333
1334         driver_args = talloc_strdup( mem_ctx, argv[2] );
1335         if (!init_drv_info_3_members(mem_ctx, &info3, driver_args ))
1336         {
1337                 printf ("Error Invalid parameter list - %s.\n", argv[2]);
1338                 return WERR_INVALID_PARAM;
1339         }
1340
1341         /* if printer driver version specified, override the default version
1342          * used by the architecture.  This allows installation of Windows
1343          * 2000 (version 3) printer drivers. */
1344         if (argc == 4)
1345         {
1346                 info3.version = atoi(argv[3]);
1347         }
1348
1349
1350         ctr.info3 = &info3;
1351         result = rpccli_spoolss_addprinterdriver (cli, mem_ctx, level, &ctr);
1352
1353         if (W_ERROR_IS_OK(result)) {
1354                 rpcstr_pull(driver_name, info3.name.buffer, 
1355                             sizeof(driver_name), -1, STR_TERMINATE);
1356                 printf ("Printer Driver %s successfully installed.\n",
1357                         driver_name);
1358         }
1359
1360         return result;
1361 }
1362
1363
1364 /****************************************************************************
1365 ****************************************************************************/
1366
1367 static WERROR cmd_spoolss_addprinterex(struct rpc_pipe_client *cli, 
1368                                          TALLOC_CTX *mem_ctx,
1369                                          int argc, const char **argv)
1370 {
1371         WERROR result;
1372         uint32                  level = 2;
1373         PRINTER_INFO_CTR        ctr;
1374         PRINTER_INFO_2          info2;
1375         fstring                 servername;
1376         
1377         /* parse the command arguements */
1378         if (argc != 5)
1379         {
1380                 printf ("Usage: %s <name> <shared name> <driver> <port>\n", argv[0]);
1381                 return WERR_OK;
1382         }
1383         
1384         slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->cli->desthost);
1385         strupper_m(servername);
1386
1387         /* Fill in the DRIVER_INFO_2 struct */
1388         ZERO_STRUCT(info2);
1389         
1390         init_unistr( &info2.printername,        argv[1]);
1391         init_unistr( &info2.sharename,          argv[2]);
1392         init_unistr( &info2.drivername,         argv[3]);
1393         init_unistr( &info2.portname,           argv[4]);
1394         init_unistr( &info2.comment,            "Created by rpcclient");
1395         init_unistr( &info2.printprocessor,     "winprint");
1396         init_unistr( &info2.datatype,           "RAW");
1397         info2.devmode =         NULL;
1398         info2.secdesc =         NULL;
1399         info2.attributes        = PRINTER_ATTRIBUTE_SHARED;
1400         info2.priority          = 0;
1401         info2.defaultpriority   = 0;
1402         info2.starttime         = 0;
1403         info2.untiltime         = 0;
1404         
1405         /* These three fields must not be used by AddPrinter() 
1406            as defined in the MS Platform SDK documentation..  
1407            --jerry
1408         info2.status            = 0;
1409         info2.cjobs             = 0;
1410         info2.averageppm        = 0;
1411         */
1412
1413         ctr.printers_2 = &info2;
1414         result = rpccli_spoolss_addprinterex (cli, mem_ctx, level, &ctr);
1415
1416         if (W_ERROR_IS_OK(result))
1417                 printf ("Printer %s successfully installed.\n", argv[1]);
1418
1419         return result;
1420 }
1421
1422 /****************************************************************************
1423 ****************************************************************************/
1424
1425 static WERROR cmd_spoolss_setdriver(struct rpc_pipe_client *cli, 
1426                                       TALLOC_CTX *mem_ctx,
1427                                       int argc, const char **argv)
1428 {
1429         POLICY_HND              pol;
1430         WERROR                  result;
1431         uint32                  level = 2;
1432         BOOL                    opened_hnd = False;
1433         PRINTER_INFO_CTR        ctr;
1434         PRINTER_INFO_2          info2;
1435         fstring                 servername,
1436                                 printername,
1437                                 user;
1438         
1439         /* parse the command arguements */
1440         if (argc != 3)
1441         {
1442                 printf ("Usage: %s <printer> <driver>\n", argv[0]);
1443                 return WERR_OK;
1444         }
1445
1446         slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->cli->desthost);
1447         strupper_m(servername);
1448         slprintf(printername, sizeof(printername)-1, "%s\\%s", servername, argv[1]);
1449         fstrcpy(user, cli->user_name);
1450
1451         /* Get a printer handle */
1452
1453         result = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername, "", 
1454                                              PRINTER_ALL_ACCESS,
1455                                              servername, user, &pol);
1456
1457         if (!W_ERROR_IS_OK(result))
1458                 goto done;
1459
1460         opened_hnd = True;
1461
1462         /* Get printer info */
1463
1464         ZERO_STRUCT (info2);
1465         ctr.printers_2 = &info2;
1466
1467         result = rpccli_spoolss_getprinter(cli, mem_ctx, &pol, level, &ctr);
1468
1469         if (!W_ERROR_IS_OK(result)) {
1470                 printf ("Unable to retrieve printer information!\n");
1471                 goto done;
1472         }
1473
1474         /* Set the printer driver */
1475
1476         init_unistr(&ctr.printers_2->drivername, argv[2]);
1477
1478         result = rpccli_spoolss_setprinter(cli, mem_ctx, &pol, level, &ctr, 0);
1479
1480         if (!W_ERROR_IS_OK(result)) {
1481                 printf("SetPrinter call failed!\n");
1482                 goto done;;
1483         }
1484
1485         printf("Succesfully set %s to driver %s.\n", argv[1], argv[2]);
1486
1487 done:
1488         /* Cleanup */
1489
1490         if (opened_hnd)
1491                 rpccli_spoolss_close_printer(cli, mem_ctx, &pol);
1492
1493         return result;
1494 }
1495
1496
1497 /****************************************************************************
1498 ****************************************************************************/
1499
1500 static WERROR cmd_spoolss_deletedriverex(struct rpc_pipe_client *cli, 
1501                                          TALLOC_CTX *mem_ctx,
1502                                          int argc, const char **argv)
1503 {
1504         WERROR result, ret = WERR_UNKNOWN_PRINTER_DRIVER;
1505  
1506         int   i;
1507         int vers = -1;
1508  
1509         const char *arch = NULL;
1510  
1511         /* parse the command arguements */
1512         if (argc < 2 || argc > 4) {
1513                 printf ("Usage: %s <driver> [arch] [version]\n", argv[0]);
1514                 return WERR_OK;
1515         }
1516
1517         if (argc >= 3)
1518                 arch = argv[2];
1519         if (argc == 4)
1520                 vers = atoi (argv[3]);
1521  
1522  
1523         /* delete the driver for all architectures */
1524         for (i=0; archi_table[i].long_archi; i++) {
1525
1526                 if (arch &&  !strequal( archi_table[i].long_archi, arch)) 
1527                         continue;
1528
1529                 if (vers >= 0 && archi_table[i].version != vers)
1530                         continue;
1531
1532                 /* make the call to remove the driver */
1533                 result = rpccli_spoolss_deleteprinterdriverex(
1534                         cli, mem_ctx, archi_table[i].long_archi, argv[1], archi_table[i].version); 
1535
1536                 if ( !W_ERROR_IS_OK(result) ) 
1537                 {
1538                         if ( !W_ERROR_EQUAL(result, WERR_UNKNOWN_PRINTER_DRIVER) ) {
1539                                 printf ("Failed to remove driver %s for arch [%s] (version: %d): %s\n", 
1540                                         argv[1], archi_table[i].long_archi, archi_table[i].version, dos_errstr(result));
1541                         }
1542                 } 
1543                 else 
1544                 {
1545                         printf ("Driver %s and files removed for arch [%s] (version: %d).\n", argv[1], 
1546                         archi_table[i].long_archi, archi_table[i].version);
1547                         ret = WERR_OK;
1548                 }
1549         }
1550   
1551         return ret;
1552 }
1553
1554
1555 /****************************************************************************
1556 ****************************************************************************/
1557
1558 static WERROR cmd_spoolss_deletedriver(struct rpc_pipe_client *cli, 
1559                                          TALLOC_CTX *mem_ctx,
1560                                          int argc, const char **argv)
1561 {
1562         WERROR result = WERR_OK;
1563         fstring                 servername;
1564         int                     i;
1565         
1566         /* parse the command arguements */
1567         if (argc != 2) {
1568                 printf ("Usage: %s <driver>\n", argv[0]);
1569                 return WERR_OK;
1570         }
1571
1572         slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->cli->desthost);
1573         strupper_m(servername);
1574
1575         /* delete the driver for all architectures */
1576         for (i=0; archi_table[i].long_archi; i++) {
1577                 /* make the call to remove the driver */
1578                 result = rpccli_spoolss_deleteprinterdriver(
1579                         cli, mem_ctx, archi_table[i].long_archi, argv[1]);
1580
1581                 if ( !W_ERROR_IS_OK(result) ) {
1582                         if ( !W_ERROR_EQUAL(result, WERR_UNKNOWN_PRINTER_DRIVER) ) {
1583                                 printf ("Failed to remove driver %s for arch [%s] - error 0x%x!\n", 
1584                                         argv[1], archi_table[i].long_archi, 
1585                                         W_ERROR_V(result));
1586                         }
1587                 } else {
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 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         werror = rpccli_spoolss_enumforms(cli, mem_ctx, &handle, level, &num_forms, &forms);
1932
1933         if (!W_ERROR_IS_OK(werror))
1934                 goto done;
1935
1936         /* Display output */
1937
1938         for (i = 0; i < num_forms; i++) {
1939
1940                 display_form(&forms[i]);
1941
1942         }
1943
1944  done:
1945         if (got_handle)
1946                 rpccli_spoolss_close_printer(cli, mem_ctx, &handle);
1947
1948         SAFE_FREE(servername);
1949         SAFE_FREE(printername);
1950
1951         return werror;
1952 }
1953
1954 /****************************************************************************
1955 ****************************************************************************/
1956
1957 static WERROR cmd_spoolss_setprinterdata(struct rpc_pipe_client *cli,
1958                                             TALLOC_CTX *mem_ctx,
1959                                             int argc, const char **argv)
1960 {
1961         WERROR result;
1962         fstring servername, printername, user;
1963         POLICY_HND pol;
1964         BOOL opened_hnd = False;
1965         PRINTER_INFO_CTR ctr;
1966         PRINTER_INFO_0 info;
1967         REGISTRY_VALUE value;
1968
1969         /* parse the command arguements */
1970         if (argc < 5) {
1971                 printf ("Usage: %s <printer> <string|binary|dword|multistring>"
1972                         " <value> <data>\n",
1973                         argv[0]);
1974                 return WERR_INVALID_PARAM;
1975         }
1976
1977         slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->cli->desthost);
1978         strupper_m(servername);
1979         slprintf(printername, sizeof(servername)-1, "%s\\%s", servername, argv[1]);
1980         fstrcpy(user, cli->user_name);
1981
1982         value.type = REG_NONE;
1983
1984         if (strequal(argv[2], "string")) {
1985                 value.type = REG_SZ;
1986         }
1987
1988         if (strequal(argv[2], "binary")) {
1989                 value.type = REG_BINARY;
1990         }
1991
1992         if (strequal(argv[2], "dword")) {
1993                 value.type = REG_DWORD;
1994         }
1995
1996         if (strequal(argv[2], "multistring")) {
1997                 value.type = REG_MULTI_SZ;
1998         }
1999
2000         if (value.type == REG_NONE) {
2001                 printf("Unknown data type: %s\n", argv[2]);
2002                 return WERR_INVALID_PARAM;
2003         }
2004
2005         /* get a printer handle */
2006         result = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername, "",
2007                                              MAXIMUM_ALLOWED_ACCESS, servername, 
2008                                              user, &pol);
2009         if (!W_ERROR_IS_OK(result))
2010                 goto done;
2011
2012         opened_hnd = True;
2013
2014         ctr.printers_0 = &info;
2015
2016         result = rpccli_spoolss_getprinter(cli, mem_ctx, &pol, 0, &ctr);
2017
2018         if (!W_ERROR_IS_OK(result))
2019                 goto done;
2020                 
2021         printf("%s\n", current_timestring(True));
2022         printf("\tchange_id (before set)\t:[0x%x]\n", info.change_id);
2023
2024         /* Set the printer data */
2025         
2026         fstrcpy(value.valuename, argv[3]);
2027
2028         switch (value.type) {
2029         case REG_SZ: {
2030                 UNISTR2 data;
2031                 init_unistr2(&data, argv[4], UNI_STR_TERMINATE);
2032                 value.size = data.uni_str_len * 2;
2033                 value.data_p = TALLOC_MEMDUP(mem_ctx, data.buffer, value.size);
2034                 break;
2035         }
2036         case REG_DWORD: {
2037                 uint32 data = strtoul(argv[4], NULL, 10);
2038                 value.size = sizeof(data);
2039                 value.data_p = TALLOC_MEMDUP(mem_ctx, &data, sizeof(data));
2040                 break;
2041         }
2042         case REG_BINARY: {
2043                 DATA_BLOB data = strhex_to_data_blob(mem_ctx, argv[4]);
2044                 value.data_p = data.data;
2045                 value.size = data.length;
2046                 break;
2047         }
2048         case REG_MULTI_SZ: {
2049                 int i;
2050                 size_t len = 0;
2051                 char *p;
2052
2053                 for (i=4; i<argc; i++) {
2054                         if (strcmp(argv[i], "NULL") == 0) {
2055                                 argv[i] = "";
2056                         }
2057                         len += strlen(argv[i])+1;
2058                 }
2059
2060                 value.size = len*2;
2061                 value.data_p = TALLOC_ARRAY(mem_ctx, unsigned char, value.size);
2062                 if (value.data_p == NULL) {
2063                         result = WERR_NOMEM;
2064                         goto done;
2065                 }
2066
2067                 p = (char *)value.data_p;
2068                 len = value.size;
2069                 for (i=4; i<argc; i++) {
2070                         size_t l = (strlen(argv[i])+1)*2;
2071                         rpcstr_push(p, argv[i], len, STR_TERMINATE);
2072                         p += l;
2073                         len -= l;
2074                 }
2075                 SMB_ASSERT(len == 0);
2076                 break;
2077         }
2078         default:
2079                 printf("Unknown data type: %s\n", argv[2]);
2080                 result = WERR_INVALID_PARAM;
2081                 goto done;
2082         }
2083
2084         result = rpccli_spoolss_setprinterdata(cli, mem_ctx, &pol, &value);
2085                 
2086         if (!W_ERROR_IS_OK(result)) {
2087                 printf ("Unable to set [%s=%s]!\n", argv[3], argv[4]);
2088                 goto done;
2089         }
2090         printf("\tSetPrinterData succeeded [%s: %s]\n", argv[3], argv[4]);
2091         
2092         result = rpccli_spoolss_getprinter(cli, mem_ctx, &pol, 0, &ctr);
2093
2094         if (!W_ERROR_IS_OK(result))
2095                 goto done;
2096                 
2097         printf("%s\n", current_timestring(True));
2098         printf("\tchange_id (after set)\t:[0x%x]\n", info.change_id);
2099
2100 done:
2101         /* cleanup */
2102         if (opened_hnd)
2103                 rpccli_spoolss_close_printer(cli, mem_ctx, &pol);
2104
2105         return result;
2106 }
2107
2108 /****************************************************************************
2109 ****************************************************************************/
2110
2111 static void display_job_info_1(JOB_INFO_1 *job)
2112 {
2113         fstring username = "", document = "", text_status = "";
2114
2115         rpcstr_pull(username, job->username.buffer,
2116                     sizeof(username), -1, STR_TERMINATE);
2117
2118         rpcstr_pull(document, job->document.buffer,
2119                     sizeof(document), -1, STR_TERMINATE);
2120
2121         rpcstr_pull(text_status, job->text_status.buffer,
2122                     sizeof(text_status), -1, STR_TERMINATE);
2123
2124         printf("%d: jobid[%d]: %s %s %s %d/%d pages\n", job->position, job->jobid,
2125                username, document, text_status, job->pagesprinted,
2126                job->totalpages);
2127 }
2128
2129 /****************************************************************************
2130 ****************************************************************************/
2131
2132 static void display_job_info_2(JOB_INFO_2 *job)
2133 {
2134         fstring username = "", document = "", text_status = "";
2135
2136         rpcstr_pull(username, job->username.buffer,
2137                     sizeof(username), -1, STR_TERMINATE);
2138
2139         rpcstr_pull(document, job->document.buffer,
2140                     sizeof(document), -1, STR_TERMINATE);
2141
2142         rpcstr_pull(text_status, job->text_status.buffer,
2143                     sizeof(text_status), -1, STR_TERMINATE);
2144
2145         printf("%d: jobid[%d]: %s %s %s %d/%d pages, %d bytes\n", job->position, job->jobid,
2146                username, document, text_status, job->pagesprinted,
2147                job->totalpages, job->size);
2148 }
2149
2150 /****************************************************************************
2151 ****************************************************************************/
2152
2153 static WERROR cmd_spoolss_enum_jobs(struct rpc_pipe_client *cli, 
2154                                       TALLOC_CTX *mem_ctx, int argc, 
2155                                       const char **argv)
2156 {
2157         WERROR result;
2158         uint32 level = 1, num_jobs, i;
2159         BOOL got_hnd = False;
2160         pstring printername;
2161         fstring servername, user;
2162         POLICY_HND hnd;
2163         JOB_INFO_CTR ctr;
2164         
2165         if (argc < 2 || argc > 3) {
2166                 printf("Usage: %s printername [level]\n", argv[0]);
2167                 return WERR_OK;
2168         }
2169         
2170         if (argc == 3)
2171                 level = atoi(argv[2]);
2172
2173         /* Open printer handle */
2174
2175         slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->cli->desthost);
2176         strupper_m(servername);
2177         fstrcpy(user, cli->user_name);
2178         slprintf(printername, sizeof(servername)-1, "\\\\%s\\", cli->cli->desthost);
2179         strupper_m(printername);
2180         pstrcat(printername, argv[1]);
2181
2182         result = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername, 
2183                                              "", MAXIMUM_ALLOWED_ACCESS, 
2184                                              servername, user, &hnd);
2185
2186         if (!W_ERROR_IS_OK(result))
2187                 goto done;
2188  
2189         got_hnd = True;
2190
2191         /* Enumerate ports */
2192
2193         result = rpccli_spoolss_enumjobs(cli, mem_ctx, &hnd, level, 0, 1000,
2194                 &num_jobs, &ctr);
2195
2196         if (!W_ERROR_IS_OK(result))
2197                 goto done;
2198
2199         for (i = 0; i < num_jobs; i++) {
2200                 switch(level) {
2201                 case 1:
2202                         display_job_info_1(&ctr.job.job_info_1[i]);
2203                         break;
2204                 case 2:
2205                         display_job_info_2(&ctr.job.job_info_2[i]);
2206                         break;
2207                 default:
2208                         d_printf("unknown info level %d\n", level);
2209                         break;
2210                 }
2211         }
2212         
2213 done:
2214         if (got_hnd)
2215                 rpccli_spoolss_close_printer(cli, mem_ctx, &hnd);
2216
2217         return result;
2218 }
2219
2220 /****************************************************************************
2221 ****************************************************************************/
2222
2223 static WERROR cmd_spoolss_enum_data( struct rpc_pipe_client *cli, 
2224                                        TALLOC_CTX *mem_ctx, int argc, 
2225                                        const char **argv)
2226 {
2227         WERROR result;
2228         uint32 i=0, val_needed, data_needed;
2229         BOOL got_hnd = False;
2230         pstring printername;
2231         fstring servername, user;
2232         POLICY_HND hnd;
2233
2234         if (argc != 2) {
2235                 printf("Usage: %s printername\n", argv[0]);
2236                 return WERR_OK;
2237         }
2238         
2239         /* Open printer handle */
2240
2241         slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->cli->desthost);
2242         strupper_m(servername);
2243         fstrcpy(user, cli->user_name);
2244         slprintf(printername, sizeof(printername)-1, "\\\\%s\\", cli->cli->desthost);
2245         strupper_m(printername);
2246         pstrcat(printername, argv[1]);
2247
2248         result = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername, 
2249                                              "", MAXIMUM_ALLOWED_ACCESS, 
2250                                              servername, user, &hnd);
2251
2252         if (!W_ERROR_IS_OK(result))
2253                 goto done;
2254  
2255         got_hnd = True;
2256
2257         /* Enumerate data */
2258
2259         result = rpccli_spoolss_enumprinterdata(cli, mem_ctx, &hnd, i, 0, 0,
2260                                              &val_needed, &data_needed,
2261                                              NULL);
2262         while (W_ERROR_IS_OK(result)) {
2263                 REGISTRY_VALUE value;
2264                 result = rpccli_spoolss_enumprinterdata(
2265                         cli, mem_ctx, &hnd, i++, val_needed,
2266                         data_needed, 0, 0, &value);
2267                 if (W_ERROR_IS_OK(result))
2268                         display_reg_value(value);
2269         }
2270         if (W_ERROR_V(result) == ERRnomoreitems)
2271                 result = W_ERROR(ERRsuccess);
2272
2273 done:
2274         if (got_hnd)
2275                 rpccli_spoolss_close_printer(cli, mem_ctx, &hnd);
2276
2277         return result;
2278 }
2279
2280 /****************************************************************************
2281 ****************************************************************************/
2282
2283 static WERROR cmd_spoolss_enum_data_ex( struct rpc_pipe_client *cli, 
2284                                           TALLOC_CTX *mem_ctx, int argc, 
2285                                           const char **argv)
2286 {
2287         WERROR result;
2288         uint32 i;
2289         BOOL got_hnd = False;
2290         pstring printername;
2291         fstring servername, user;
2292         const char *keyname = NULL;
2293         POLICY_HND hnd;
2294         REGVAL_CTR *ctr = NULL;
2295
2296         if (argc != 3) {
2297                 printf("Usage: %s printername <keyname>\n", argv[0]);
2298                 return WERR_OK;
2299         }
2300         
2301         keyname = argv[2];
2302
2303         /* Open printer handle */
2304
2305         slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->cli->desthost);
2306         strupper_m(servername);
2307         fstrcpy(user, cli->user_name);
2308         slprintf(printername, sizeof(printername)-1, "\\\\%s\\", cli->cli->desthost);
2309         strupper_m(printername);
2310         pstrcat(printername, argv[1]);
2311
2312         result = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername, 
2313                                              "", MAXIMUM_ALLOWED_ACCESS, 
2314                                              servername, user, &hnd);
2315
2316         if (!W_ERROR_IS_OK(result))
2317                 goto done;
2318  
2319         got_hnd = True;
2320
2321         /* Enumerate subkeys */
2322
2323         if ( !(ctr = TALLOC_ZERO_P( mem_ctx, REGVAL_CTR )) ) 
2324                 return WERR_NOMEM;
2325
2326         result = rpccli_spoolss_enumprinterdataex(cli, mem_ctx, &hnd, keyname, ctr);
2327
2328         if (!W_ERROR_IS_OK(result))
2329                 goto done;
2330
2331         for (i=0; i < ctr->num_values; i++) {
2332                 display_reg_value(*(ctr->values[i]));
2333         }
2334
2335         TALLOC_FREE( ctr );
2336
2337 done:
2338         if (got_hnd)
2339                 rpccli_spoolss_close_printer(cli, mem_ctx, &hnd);
2340
2341         return result;
2342 }
2343
2344 /****************************************************************************
2345 ****************************************************************************/
2346
2347 static WERROR cmd_spoolss_enum_printerkey( struct rpc_pipe_client *cli, 
2348                                              TALLOC_CTX *mem_ctx, int argc, 
2349                                              const char **argv)
2350 {
2351         WERROR result;
2352         BOOL got_hnd = False;
2353         pstring printername;
2354         fstring servername, user;
2355         const char *keyname = NULL;
2356         POLICY_HND hnd;
2357         uint16 *keylist = NULL, *curkey;
2358
2359         if (argc < 2 || argc > 3) {
2360                 printf("Usage: %s printername [keyname]\n", argv[0]);
2361                 return WERR_OK;
2362         }
2363                 
2364         if (argc == 3)
2365                 keyname = argv[2];
2366         else
2367                 keyname = "";
2368
2369         /* Open printer handle */
2370
2371         slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->cli->desthost);
2372         strupper_m(servername);
2373         fstrcpy(user, cli->user_name);
2374         slprintf(printername, sizeof(printername)-1, "\\\\%s\\", cli->cli->desthost);
2375         strupper_m(printername);
2376         pstrcat(printername, argv[1]);
2377
2378         result = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername, 
2379                                              "", MAXIMUM_ALLOWED_ACCESS, 
2380                                              servername, user, &hnd);
2381
2382         if (!W_ERROR_IS_OK(result))
2383                 goto done;
2384          
2385         got_hnd = True;
2386
2387         /* Enumerate subkeys */
2388
2389         result = rpccli_spoolss_enumprinterkey(cli, mem_ctx, &hnd, keyname, &keylist, NULL);
2390
2391         if (!W_ERROR_IS_OK(result))
2392                 goto done;
2393
2394         curkey = keylist;
2395         while (*curkey != 0) {
2396                 pstring subkey;
2397                 rpcstr_pull(subkey, curkey, sizeof(subkey), -1, 
2398                             STR_TERMINATE);
2399                 printf("%s\n", subkey);
2400                 curkey += strlen(subkey) + 1;
2401         }
2402
2403 done:
2404
2405         SAFE_FREE(keylist);
2406
2407         if (got_hnd)
2408                 rpccli_spoolss_close_printer(cli, mem_ctx, &hnd);
2409
2410         return result;
2411 }
2412
2413 /****************************************************************************
2414 ****************************************************************************/
2415
2416 static WERROR cmd_spoolss_rffpcnex(struct rpc_pipe_client *cli, 
2417                                      TALLOC_CTX *mem_ctx, int argc, 
2418                                      const char **argv)
2419 {
2420         fstring servername, printername;
2421         POLICY_HND hnd;
2422         BOOL got_hnd = False;
2423         WERROR result;
2424         SPOOL_NOTIFY_OPTION option;
2425
2426         if (argc != 2) {
2427                 printf("Usage: %s printername\n", argv[0]);
2428                 result = WERR_OK;
2429                 goto done;
2430         }
2431
2432         /* Open printer */
2433
2434         slprintf(servername, sizeof(servername) - 1, "\\\\%s", cli->cli->desthost);
2435         strupper_m(servername);
2436
2437         slprintf(printername, sizeof(printername) - 1, "\\\\%s\\%s", cli->cli->desthost,
2438                  argv[1]);
2439         strupper_m(printername);
2440
2441         result = rpccli_spoolss_open_printer_ex(
2442                 cli, mem_ctx, printername, "", MAXIMUM_ALLOWED_ACCESS, 
2443                 servername, cli->user_name, &hnd);
2444
2445         if (!W_ERROR_IS_OK(result)) {
2446                 printf("Error opening %s\n", argv[1]);
2447                 goto done;
2448         }
2449
2450         got_hnd = True;
2451
2452         /* Create spool options */
2453
2454         ZERO_STRUCT(option);
2455
2456         option.version = 2;
2457         option.option_type_ptr = 1;
2458         option.count = option.ctr.count = 2;
2459
2460         option.ctr.type = TALLOC_ARRAY(mem_ctx, SPOOL_NOTIFY_OPTION_TYPE, 2);
2461         if (option.ctr.type == NULL) {
2462                 result = WERR_NOMEM;
2463                 goto done;
2464         }
2465
2466         ZERO_STRUCT(option.ctr.type[0]);
2467         option.ctr.type[0].type = PRINTER_NOTIFY_TYPE;
2468         option.ctr.type[0].count = option.ctr.type[0].count2 = 1;
2469         option.ctr.type[0].fields_ptr = 1;
2470         option.ctr.type[0].fields[0] = PRINTER_NOTIFY_SERVER_NAME;
2471
2472         ZERO_STRUCT(option.ctr.type[1]);
2473         option.ctr.type[1].type = JOB_NOTIFY_TYPE;
2474         option.ctr.type[1].count = option.ctr.type[1].count2 = 1;
2475         option.ctr.type[1].fields_ptr = 1;
2476         option.ctr.type[1].fields[0] = JOB_NOTIFY_PRINTER_NAME;
2477
2478         /* Send rffpcnex */
2479
2480         slprintf(servername, sizeof(servername) - 1, "\\\\%s", myhostname());
2481         strupper_m(servername);
2482
2483         result = rpccli_spoolss_rffpcnex(
2484                 cli, mem_ctx, &hnd, 0, 0, servername, 123, &option);
2485
2486         if (!W_ERROR_IS_OK(result)) {
2487                 printf("Error rffpcnex %s\n", argv[1]);
2488                 goto done;
2489         }
2490
2491 done:           
2492         if (got_hnd)
2493                 rpccli_spoolss_close_printer(cli, mem_ctx, &hnd);
2494
2495         return result;
2496 }
2497
2498 /****************************************************************************
2499 ****************************************************************************/
2500
2501 static BOOL compare_printer( struct rpc_pipe_client *cli1, POLICY_HND *hnd1,
2502                              struct rpc_pipe_client *cli2, POLICY_HND *hnd2 )
2503 {
2504         PRINTER_INFO_CTR ctr1, ctr2;
2505         WERROR werror;
2506         TALLOC_CTX *mem_ctx = talloc_init("compare_printer");
2507
2508         printf("Retrieving printer propertiesfor %s...", cli1->cli->desthost);
2509         werror = rpccli_spoolss_getprinter( cli1, mem_ctx, hnd1, 2, &ctr1);
2510         if ( !W_ERROR_IS_OK(werror) ) {
2511                 printf("failed (%s)\n", dos_errstr(werror));
2512                 talloc_destroy(mem_ctx);
2513                 return False;
2514         }
2515         printf("ok\n");
2516
2517         printf("Retrieving printer properties for %s...", cli2->cli->desthost);
2518         werror = rpccli_spoolss_getprinter( cli2, mem_ctx, hnd2, 2, &ctr2);
2519         if ( !W_ERROR_IS_OK(werror) ) {
2520                 printf("failed (%s)\n", dos_errstr(werror));
2521                 talloc_destroy(mem_ctx);
2522                 return False;
2523         }
2524         printf("ok\n");
2525
2526         talloc_destroy(mem_ctx);
2527
2528         return True;
2529 }
2530
2531 /****************************************************************************
2532 ****************************************************************************/
2533
2534 static BOOL compare_printer_secdesc( struct rpc_pipe_client *cli1, POLICY_HND *hnd1,
2535                                      struct rpc_pipe_client *cli2, POLICY_HND *hnd2 )
2536 {
2537         PRINTER_INFO_CTR ctr1, ctr2;
2538         WERROR werror;
2539         TALLOC_CTX *mem_ctx = talloc_init("compare_printer_secdesc");
2540         SEC_DESC *sd1, *sd2;
2541         BOOL result = True;
2542
2543
2544         printf("Retreiving printer security for %s...", cli1->cli->desthost);
2545         werror = rpccli_spoolss_getprinter( cli1, mem_ctx, hnd1, 3, &ctr1);
2546         if ( !W_ERROR_IS_OK(werror) ) {
2547                 printf("failed (%s)\n", dos_errstr(werror));
2548                 result = False;
2549                 goto done;
2550         }
2551         printf("ok\n");
2552
2553         printf("Retrieving printer security for %s...", cli2->cli->desthost);
2554         werror = rpccli_spoolss_getprinter( cli2, mem_ctx, hnd2, 3, &ctr2);
2555         if ( !W_ERROR_IS_OK(werror) ) {
2556                 printf("failed (%s)\n", dos_errstr(werror));
2557                 result = False;
2558                 goto done;
2559         }
2560         printf("ok\n");
2561         
2562
2563         printf("++ ");
2564
2565         if ( (ctr1.printers_3 != ctr2.printers_3) && (!ctr1.printers_3 || !ctr2.printers_3) ) {
2566                 printf("NULL PRINTER_INFO_3!\n");
2567                 result = False;
2568                 goto done;
2569         }
2570         
2571         sd1 = ctr1.printers_3->secdesc;
2572         sd2 = ctr2.printers_3->secdesc;
2573         
2574         if ( (sd1 != sd2) && ( !sd1 || !sd2 ) ) {
2575                 printf("NULL secdesc!\n");
2576                 result = False;
2577                 goto done;
2578         }
2579         
2580         if ( (ctr1.printers_3->flags != ctr1.printers_3->flags ) || !sec_desc_equal( sd1, sd2 ) ) {
2581                 printf("Security Descriptors *not* equal!\n");
2582                 result = False;
2583                 goto done;
2584         }
2585         
2586         printf("Security descriptors match\n");
2587         
2588 done:
2589         talloc_destroy(mem_ctx);
2590         return result;
2591 }
2592
2593
2594 /****************************************************************************
2595 ****************************************************************************/
2596
2597 static WERROR cmd_spoolss_printercmp(struct rpc_pipe_client *cli, 
2598                                      TALLOC_CTX *mem_ctx, int argc, 
2599                                      const char **argv)
2600 {
2601         fstring printername, servername1, servername2;
2602         pstring printername_path;
2603         struct cli_state *cli_server1 = cli->cli;
2604         struct cli_state *cli_server2 = NULL;
2605         struct rpc_pipe_client *cli2 = NULL;
2606         POLICY_HND hPrinter1, hPrinter2;
2607         NTSTATUS nt_status;
2608         WERROR werror;
2609         
2610         if ( argc != 3 )  {
2611                 printf("Usage: %s <printer> <server>\n", argv[0]);
2612                 return WERR_OK;
2613         }
2614         
2615         fstrcpy( printername, argv[1] );
2616         
2617         fstr_sprintf( servername1, cli->cli->desthost );
2618         fstrcpy( servername2, argv[2] );
2619         strupper_m( servername1 );
2620         strupper_m( servername2 );
2621         
2622         
2623         /* first get the connection to the remote server */
2624         
2625         nt_status = cli_full_connection(&cli_server2, global_myname(), servername2, 
2626                                         NULL, 0,
2627                                         "IPC$", "IPC",  
2628                                         cmdline_auth_info.username, 
2629                                         lp_workgroup(),
2630                                         cmdline_auth_info.password, 
2631                                         cmdline_auth_info.use_kerberos ? CLI_FULL_CONNECTION_USE_KERBEROS : 0,
2632                                         cmdline_auth_info.signing_state, NULL);
2633                                         
2634         if ( !NT_STATUS_IS_OK(nt_status) )
2635                 return WERR_GENERAL_FAILURE;
2636
2637         cli2 = cli_rpc_pipe_open_noauth(cli_server2, PI_SPOOLSS, &nt_status);
2638         if (!cli2) {
2639                 printf("failed to open spoolss pipe on server %s (%s)\n",
2640                         servername2, nt_errstr(nt_status));
2641                 return WERR_GENERAL_FAILURE;
2642         }
2643                                         
2644         /* now open up both printers */
2645
2646         pstr_sprintf( printername_path, "\\\\%s\\%s", servername1, printername );
2647         printf("Opening %s...", printername_path);
2648         werror = rpccli_spoolss_open_printer_ex( cli, mem_ctx, printername_path, 
2649                 "", PRINTER_ALL_ACCESS, servername1, cli_server1->user_name, &hPrinter1);
2650         if ( !W_ERROR_IS_OK(werror) ) {
2651                 printf("failed (%s)\n", dos_errstr(werror));
2652                 goto done;
2653         }
2654         printf("ok\n");
2655         
2656         pstr_sprintf( printername_path, "\\\\%s\\%s", servername2, printername );
2657         printf("Opening %s...", printername_path);
2658         werror = rpccli_spoolss_open_printer_ex( cli2, mem_ctx, printername_path,  
2659                 "", PRINTER_ALL_ACCESS, servername2, cli_server2->user_name, &hPrinter2 );
2660         if ( !W_ERROR_IS_OK(werror) ) {
2661                  printf("failed (%s)\n", dos_errstr(werror));
2662                 goto done;
2663         }
2664         printf("ok\n");
2665         
2666         
2667         compare_printer( cli, &hPrinter1, cli2, &hPrinter2 );
2668         compare_printer_secdesc( cli, &hPrinter1, cli2, &hPrinter2 );
2669 #if 0
2670         compare_printerdata( cli_server1, &hPrinter1, cli_server2, &hPrinter2 );
2671 #endif
2672
2673
2674 done:
2675         /* cleanup */
2676
2677         printf("Closing printers...");  
2678         rpccli_spoolss_close_printer( cli, mem_ctx, &hPrinter1 );
2679         rpccli_spoolss_close_printer( cli2, mem_ctx, &hPrinter2 );
2680         printf("ok\n");
2681         
2682         /* close the second remote connection */
2683         
2684         cli_shutdown( cli_server2 );
2685         
2686         return WERR_OK;
2687 }
2688
2689 /* List of commands exported by this module */
2690 struct cmd_set spoolss_commands[] = {
2691
2692         { "SPOOLSS"  },
2693
2694         { "adddriver",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_addprinterdriver,   PI_SPOOLSS, NULL, "Add a print driver",                  "" },
2695         { "addprinter",         RPC_RTYPE_WERROR, NULL, cmd_spoolss_addprinterex,       PI_SPOOLSS, NULL, "Add a printer",                       "" },
2696         { "deldriver",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_deletedriver,       PI_SPOOLSS, NULL, "Delete a printer driver",             "" },
2697         { "deldriverex",        RPC_RTYPE_WERROR, NULL, cmd_spoolss_deletedriverex,     PI_SPOOLSS, NULL, "Delete a printer driver with files",  "" },
2698         { "enumdata",           RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_data,          PI_SPOOLSS, NULL, "Enumerate printer data",              "" },
2699         { "enumdataex",         RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_data_ex,       PI_SPOOLSS, NULL, "Enumerate printer data for a key",    "" },
2700         { "enumkey",            RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_printerkey,    PI_SPOOLSS, NULL, "Enumerate printer keys",              "" },
2701         { "enumjobs",           RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_jobs,          PI_SPOOLSS, NULL, "Enumerate print jobs",                "" },
2702         { "enumports",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_ports,         PI_SPOOLSS, NULL, "Enumerate printer ports",             "" },
2703         { "enumdrivers",        RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_drivers,       PI_SPOOLSS, NULL, "Enumerate installed printer drivers", "" },
2704         { "enumprinters",       RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_printers,      PI_SPOOLSS, NULL, "Enumerate printers",                  "" },
2705         { "getdata",            RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprinterdata,     PI_SPOOLSS, NULL, "Get print driver data",               "" },
2706         { "getdataex",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprinterdataex,   PI_SPOOLSS, NULL, "Get printer driver data with keyname", ""},
2707         { "getdriver",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_getdriver,          PI_SPOOLSS, NULL, "Get print driver information",        "" },
2708         { "getdriverdir",       RPC_RTYPE_WERROR, NULL, cmd_spoolss_getdriverdir,       PI_SPOOLSS, NULL, "Get print driver upload directory",   "" },
2709         { "getprinter",         RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprinter,         PI_SPOOLSS, NULL, "Get printer info",                    "" },
2710         { "openprinter",        RPC_RTYPE_WERROR, NULL, cmd_spoolss_open_printer_ex,    PI_SPOOLSS, NULL, "Open printer handle",                 "" },
2711         { "setdriver",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_setdriver,          PI_SPOOLSS, NULL, "Set printer driver",                  "" },
2712         { "getprintprocdir",    RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprintprocdir,    PI_SPOOLSS, NULL, "Get print processor directory",       "" },
2713         { "addform",            RPC_RTYPE_WERROR, NULL, cmd_spoolss_addform,            PI_SPOOLSS, NULL, "Add form",                            "" },
2714         { "setform",            RPC_RTYPE_WERROR, NULL, cmd_spoolss_setform,            PI_SPOOLSS, NULL, "Set form",                            "" },
2715         { "getform",            RPC_RTYPE_WERROR, NULL, cmd_spoolss_getform,            PI_SPOOLSS, NULL, "Get form",                            "" },
2716         { "deleteform",         RPC_RTYPE_WERROR, NULL, cmd_spoolss_deleteform,         PI_SPOOLSS, NULL, "Delete form",                         "" },
2717         { "enumforms",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_forms,         PI_SPOOLSS, NULL, "Enumerate forms",                     "" },
2718         { "setprinter",         RPC_RTYPE_WERROR, NULL, cmd_spoolss_setprinter,         PI_SPOOLSS, NULL, "Set printer comment",                 "" },
2719         { "setprintername",     RPC_RTYPE_WERROR, NULL, cmd_spoolss_setprintername,     PI_SPOOLSS, NULL, "Set printername",                 "" },
2720         { "setprinterdata",     RPC_RTYPE_WERROR, NULL, cmd_spoolss_setprinterdata,     PI_SPOOLSS, NULL, "Set REG_SZ printer data",             "" },
2721         { "rffpcnex",           RPC_RTYPE_WERROR, NULL, cmd_spoolss_rffpcnex,           PI_SPOOLSS, NULL, "Rffpcnex test", "" },
2722         { "printercmp",         RPC_RTYPE_WERROR, NULL, cmd_spoolss_printercmp,         PI_SPOOLSS, NULL, "Printer comparison test", "" },
2723
2724         { NULL }
2725 };