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