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