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