Merge branch 'v3-2-test' of ssh://jra@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->cli->desthost);
113         strupper_m(servername);
114         fstrcpy(user, cli->user_name);
115         fstrcpy(printername, argv[1]);
116
117         /* Open the printer handle */
118
119         werror = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername, 
120                                              "", PRINTER_ALL_ACCESS, 
121                                              servername, user, &hnd);
122
123         if (W_ERROR_IS_OK(werror)) {
124                 printf("Printer %s opened successfully\n", printername);
125                 werror = rpccli_spoolss_close_printer(cli, mem_ctx, &hnd);
126
127                 if (!W_ERROR_IS_OK(werror)) {
128                         printf("Error closing printer handle! (%s)\n", 
129                                 get_dos_error_msg(werror));
130                 }
131         }
132
133         return werror;
134 }
135
136
137 /****************************************************************************
138 ****************************************************************************/
139
140 static void display_print_info_0(PRINTER_INFO_0 *i0)
141 {
142         fstring name = "";
143         fstring servername = "";
144
145         if (!i0)
146                 return;
147
148         rpcstr_pull(name, i0->printername.buffer, sizeof(name), -1, STR_TERMINATE);
149
150         rpcstr_pull(servername, i0->servername.buffer, sizeof(servername), -1,STR_TERMINATE);
151   
152         printf("\tprintername:[%s]\n", name);
153         printf("\tservername:[%s]\n", servername);
154         printf("\tcjobs:[0x%x]\n", i0->cjobs);
155         printf("\ttotal_jobs:[0x%x]\n", i0->total_jobs);
156         
157         printf("\t:date: [%d]-[%d]-[%d] (%d)\n", i0->year, i0->month, 
158                i0->day, i0->dayofweek);
159         printf("\t:time: [%d]-[%d]-[%d]-[%d]\n", i0->hour, i0->minute, 
160                i0->second, i0->milliseconds);
161         
162         printf("\tglobal_counter:[0x%x]\n", i0->global_counter);
163         printf("\ttotal_pages:[0x%x]\n", i0->total_pages);
164         
165         printf("\tmajorversion:[0x%x]\n", i0->major_version);
166         printf("\tbuildversion:[0x%x]\n", i0->build_version);
167         
168         printf("\tunknown7:[0x%x]\n", i0->unknown7);
169         printf("\tunknown8:[0x%x]\n", i0->unknown8);
170         printf("\tunknown9:[0x%x]\n", i0->unknown9);
171         printf("\tsession_counter:[0x%x]\n", i0->session_counter);
172         printf("\tunknown11:[0x%x]\n", i0->unknown11);
173         printf("\tprinter_errors:[0x%x]\n", i0->printer_errors);
174         printf("\tunknown13:[0x%x]\n", i0->unknown13);
175         printf("\tunknown14:[0x%x]\n", i0->unknown14);
176         printf("\tunknown15:[0x%x]\n", i0->unknown15);
177         printf("\tunknown16:[0x%x]\n", i0->unknown16);
178         printf("\tchange_id:[0x%x]\n", i0->change_id);
179         printf("\tunknown18:[0x%x]\n", i0->unknown18);
180         printf("\tstatus:[0x%x]\n", i0->status);
181         printf("\tunknown20:[0x%x]\n", i0->unknown20);
182         printf("\tc_setprinter:[0x%x]\n", i0->c_setprinter);
183         printf("\tunknown22:[0x%x]\n", i0->unknown22);
184         printf("\tunknown23:[0x%x]\n", i0->unknown23);
185         printf("\tunknown24:[0x%x]\n", i0->unknown24);
186         printf("\tunknown25:[0x%x]\n", i0->unknown25);
187         printf("\tunknown26:[0x%x]\n", i0->unknown26);
188         printf("\tunknown27:[0x%x]\n", i0->unknown27);
189         printf("\tunknown28:[0x%x]\n", i0->unknown28);
190         printf("\tunknown29:[0x%x]\n", i0->unknown29);
191
192         printf("\n");
193 }
194
195 /****************************************************************************
196 ****************************************************************************/
197
198 static void display_print_info_1(PRINTER_INFO_1 *i1)
199 {
200         fstring desc = "";
201         fstring name = "";
202         fstring comm = "";
203
204         rpcstr_pull(desc, i1->description.buffer, sizeof(desc), -1,
205                     STR_TERMINATE);
206
207         rpcstr_pull(name, i1->name.buffer, sizeof(name), -1, STR_TERMINATE);
208         rpcstr_pull(comm, i1->comment.buffer, sizeof(comm), -1, STR_TERMINATE);
209
210         printf("\tflags:[0x%x]\n", i1->flags);
211         printf("\tname:[%s]\n", name);
212         printf("\tdescription:[%s]\n", desc);
213         printf("\tcomment:[%s]\n", comm);
214
215         printf("\n");
216 }
217
218 /****************************************************************************
219 ****************************************************************************/
220
221 static void display_print_info_2(PRINTER_INFO_2 *i2)
222 {
223         fstring servername = "";
224         fstring printername = "";
225         fstring sharename = "";
226         fstring portname = "";
227         fstring drivername = "";
228         fstring comment = "";
229         fstring location = "";
230         fstring sepfile = "";
231         fstring printprocessor = "";
232         fstring datatype = "";
233         fstring parameters = "";
234         
235         rpcstr_pull(servername, i2->servername.buffer,sizeof(servername), -1, STR_TERMINATE);
236         rpcstr_pull(printername, i2->printername.buffer,sizeof(printername), -1, STR_TERMINATE);
237         rpcstr_pull(sharename, i2->sharename.buffer,sizeof(sharename), -1, STR_TERMINATE);
238         rpcstr_pull(portname, i2->portname.buffer,sizeof(portname), -1, STR_TERMINATE);
239         rpcstr_pull(drivername, i2->drivername.buffer,sizeof(drivername), -1, STR_TERMINATE);
240         rpcstr_pull(comment, i2->comment.buffer,sizeof(comment), -1, STR_TERMINATE);
241         rpcstr_pull(location, i2->location.buffer,sizeof(location), -1, STR_TERMINATE);
242         rpcstr_pull(sepfile, i2->sepfile.buffer,sizeof(sepfile), -1, STR_TERMINATE);
243         rpcstr_pull(printprocessor, i2->printprocessor.buffer,sizeof(printprocessor), -1, STR_TERMINATE);
244         rpcstr_pull(datatype, i2->datatype.buffer,sizeof(datatype), -1, STR_TERMINATE);
245         rpcstr_pull(parameters, i2->parameters.buffer,sizeof(parameters), -1, STR_TERMINATE);
246
247         printf("\tservername:[%s]\n", servername);
248         printf("\tprintername:[%s]\n", printername);
249         printf("\tsharename:[%s]\n", sharename);
250         printf("\tportname:[%s]\n", portname);
251         printf("\tdrivername:[%s]\n", drivername);
252         printf("\tcomment:[%s]\n", comment);
253         printf("\tlocation:[%s]\n", location);
254         printf("\tsepfile:[%s]\n", sepfile);
255         printf("\tprintprocessor:[%s]\n", printprocessor);
256         printf("\tdatatype:[%s]\n", datatype);
257         printf("\tparameters:[%s]\n", parameters);
258         printf("\tattributes:[0x%x]\n", i2->attributes);
259         printf("\tpriority:[0x%x]\n", i2->priority);
260         printf("\tdefaultpriority:[0x%x]\n", i2->defaultpriority);
261         printf("\tstarttime:[0x%x]\n", i2->starttime);
262         printf("\tuntiltime:[0x%x]\n", i2->untiltime);
263         printf("\tstatus:[0x%x]\n", i2->status);
264         printf("\tcjobs:[0x%x]\n", i2->cjobs);
265         printf("\taverageppm:[0x%x]\n", i2->averageppm);
266
267         if (i2->secdesc) 
268                 display_sec_desc(i2->secdesc);
269
270         printf("\n");
271 }
272
273 /****************************************************************************
274 ****************************************************************************/
275
276 static void display_print_info_3(PRINTER_INFO_3 *i3)
277 {
278         display_sec_desc(i3->secdesc);
279
280         printf("\n");
281 }
282
283 /****************************************************************************
284 ****************************************************************************/
285
286 static void display_print_info_7(PRINTER_INFO_7 *i7)
287 {
288         fstring guid = "";
289         rpcstr_pull(guid, i7->guid.buffer,sizeof(guid), -1, STR_TERMINATE);
290         printf("\tguid:[%s]\n", guid);
291         printf("\taction:[0x%x]\n", i7->action);
292 }
293
294
295 /****************************************************************************
296 ****************************************************************************/
297
298 static WERROR cmd_spoolss_enum_printers(struct rpc_pipe_client *cli, 
299                                           TALLOC_CTX *mem_ctx,
300                                           int argc, const char **argv)
301 {
302         WERROR                  result;
303         uint32                  info_level = 1;
304         PRINTER_INFO_CTR        ctr;
305         uint32                  i = 0, num_printers;
306         fstring name;
307
308         if (argc > 3) 
309         {
310                 printf("Usage: %s [level] [name]\n", argv[0]);
311                 return WERR_OK;
312         }
313
314         if (argc >= 2)
315                 info_level = atoi(argv[1]);
316
317         if (argc == 3)
318                 fstrcpy(name, argv[2]);
319         else {
320                 slprintf(name, sizeof(name)-1, "\\\\%s", cli->cli->desthost);
321                 strupper_m(name);
322         }
323
324         ZERO_STRUCT(ctr);
325
326         result = rpccli_spoolss_enum_printers(cli, mem_ctx, name, PRINTER_ENUM_LOCAL, 
327                 info_level, &num_printers, &ctr);
328
329         if (W_ERROR_IS_OK(result)) {
330
331                 if (!num_printers) {
332                         printf ("No printers returned.\n");
333                         goto done;
334                 }
335         
336                 for (i = 0; i < num_printers; i++) {
337                         switch(info_level) {
338                         case 0:
339                                 display_print_info_0(&ctr.printers_0[i]);
340                                 break;
341                         case 1:
342                                 display_print_info_1(&ctr.printers_1[i]);
343                                 break;
344                         case 2:
345                                 display_print_info_2(&ctr.printers_2[i]);
346                                 break;
347                         case 3:
348                                 display_print_info_3(&ctr.printers_3[i]);
349                                 break;
350                         default:
351                                 printf("unknown info level %d\n", info_level);
352                                 goto done;
353                         }
354                 }
355         }
356         done:
357
358         return result;
359 }
360
361 /****************************************************************************
362 ****************************************************************************/
363
364 static void display_port_info_1(PORT_INFO_1 *i1)
365 {
366         fstring buffer;
367         
368         rpcstr_pull(buffer, i1->port_name.buffer, sizeof(buffer), -1, STR_TERMINATE);
369         printf("\tPort Name:\t[%s]\n", buffer);
370 }
371
372 /****************************************************************************
373 ****************************************************************************/
374
375 static void display_port_info_2(PORT_INFO_2 *i2)
376 {
377         fstring buffer;
378         
379         rpcstr_pull(buffer, i2->port_name.buffer, sizeof(buffer), -1, STR_TERMINATE);
380         printf("\tPort Name:\t[%s]\n", buffer);
381         rpcstr_pull(buffer, i2->monitor_name.buffer, sizeof(buffer), -1, STR_TERMINATE);
382
383         printf("\tMonitor Name:\t[%s]\n", buffer);
384         rpcstr_pull(buffer, i2->description.buffer, sizeof(buffer), -1, STR_TERMINATE);
385
386         printf("\tDescription:\t[%s]\n", buffer);
387         printf("\tPort Type:\t" );
388         if ( i2->port_type ) {
389                 int comma = 0; /* hack */
390                 printf( "[" );
391                 if ( i2->port_type & PORT_TYPE_READ ) {
392                         printf( "Read" );
393                         comma = 1;
394                 }
395                 if ( i2->port_type & PORT_TYPE_WRITE ) {
396                         printf( "%sWrite", comma ? ", " : "" );
397                         comma = 1;
398                 }
399                 /* These two have slightly different interpretations
400                  on 95/98/ME but I'm disregarding that for now */
401                 if ( i2->port_type & PORT_TYPE_REDIRECTED ) {
402                         printf( "%sRedirected", comma ? ", " : "" );
403                         comma = 1;
404                 }
405                 if ( i2->port_type & PORT_TYPE_NET_ATTACHED ) {
406                         printf( "%sNet-Attached", comma ? ", " : "" );
407                 }
408                 printf( "]\n" );
409         } else {
410                 printf( "[Unset]\n" );
411         }
412         printf("\tReserved:\t[%d]\n", i2->reserved);
413         printf("\n");
414 }
415
416 /****************************************************************************
417 ****************************************************************************/
418
419 static WERROR cmd_spoolss_enum_ports(struct rpc_pipe_client *cli, 
420                                        TALLOC_CTX *mem_ctx, int argc, 
421                                        const char **argv)
422 {
423         WERROR                  result;
424         uint32                  info_level = 1;
425         PORT_INFO_CTR           ctr;
426         uint32                  returned;
427         
428         if (argc > 2) {
429                 printf("Usage: %s [level]\n", argv[0]);
430                 return WERR_OK;
431         }
432         
433         if (argc == 2)
434                 info_level = atoi(argv[1]);
435
436         /* Enumerate ports */
437
438         ZERO_STRUCT(ctr);
439
440         result = rpccli_spoolss_enum_ports(cli, mem_ctx, info_level, &returned, &ctr);
441
442         if (W_ERROR_IS_OK(result)) {
443                 int i;
444
445                 for (i = 0; i < returned; i++) {
446                         switch (info_level) {
447                         case 1:
448                                 display_port_info_1(&ctr.port.info_1[i]);
449                                 break;
450                         case 2:
451                                 display_port_info_2(&ctr.port.info_2[i]);
452                                 break;
453                         default:
454                                 printf("unknown info level %d\n", info_level);
455                                 break;
456                         }
457                 }
458         }
459         
460         return result;
461 }
462
463 /****************************************************************************
464 ****************************************************************************/
465
466 static WERROR cmd_spoolss_setprinter(struct rpc_pipe_client *cli,
467                                        TALLOC_CTX *mem_ctx,
468                                        int argc, const char **argv)
469 {
470         POLICY_HND      pol;
471         WERROR          result;
472         uint32          info_level = 2;
473         bool            opened_hnd = False;
474         PRINTER_INFO_CTR ctr;
475         fstring         printername,
476                         servername,
477                         user,
478                         comment;
479
480         if (argc == 1 || argc > 3) {
481                 printf("Usage: %s printername comment\n", argv[0]);
482
483                 return WERR_OK;
484         }
485
486         /* Open a printer handle */
487         if (argc == 3) {
488                 fstrcpy(comment, argv[2]);
489         }
490
491         slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->cli->desthost);
492         strupper_m(servername);
493         slprintf(printername, sizeof(servername)-1, "%s\\%s", servername, argv[1]);
494         fstrcpy(user, cli->user_name);
495
496         /* get a printer handle */
497         result = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername, "", 
498                                 PRINTER_ALL_ACCESS, servername,
499                                 user, &pol);
500                                 
501         if (!W_ERROR_IS_OK(result))
502                 goto done;
503
504         opened_hnd = True;
505
506         /* Get printer info */
507         result = rpccli_spoolss_getprinter(cli, mem_ctx, &pol, info_level, &ctr);
508
509         if (!W_ERROR_IS_OK(result))
510                 goto done;
511
512
513         /* Modify the comment. */
514         init_unistr(&ctr.printers_2->comment, comment);
515         ctr.printers_2->devmode = NULL;
516         ctr.printers_2->secdesc = NULL;
517
518         result = rpccli_spoolss_setprinter(cli, mem_ctx, &pol, info_level, &ctr, 0);
519         if (W_ERROR_IS_OK(result))
520                 printf("Success in setting comment.\n");
521
522  done:
523         if (opened_hnd)
524                 rpccli_spoolss_close_printer(cli, mem_ctx, &pol);
525
526         return result;
527 }
528
529 /****************************************************************************
530 ****************************************************************************/
531
532 static WERROR cmd_spoolss_setprintername(struct rpc_pipe_client *cli,
533                                        TALLOC_CTX *mem_ctx,
534                                        int argc, const char **argv)
535 {
536         POLICY_HND      pol;
537         WERROR          result;
538         uint32          info_level = 2;
539         bool            opened_hnd = False;
540         PRINTER_INFO_CTR ctr;
541         fstring         printername,
542                         servername,
543                         user,
544                         new_printername;
545
546         if (argc == 1 || argc > 3) {
547                 printf("Usage: %s printername new_printername\n", argv[0]);
548
549                 return WERR_OK;
550         }
551
552         /* Open a printer handle */
553         if (argc == 3) {
554                 fstrcpy(new_printername, argv[2]);
555         }
556
557         slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->cli->desthost);
558         strupper_m(servername);
559         slprintf(printername, sizeof(printername)-1, "%s\\%s", servername, argv[1]);
560         fstrcpy(user, cli->user_name);
561
562         /* get a printer handle */
563         result = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername, "", 
564                                 PRINTER_ALL_ACCESS, servername,
565                                 user, &pol);
566                                 
567         if (!W_ERROR_IS_OK(result))
568                 goto done;
569
570         opened_hnd = True;
571
572         /* Get printer info */
573         result = rpccli_spoolss_getprinter(cli, mem_ctx, &pol, info_level, &ctr);
574
575         if (!W_ERROR_IS_OK(result))
576                 goto done;
577
578         /* Modify the printername. */
579         init_unistr(&ctr.printers_2->printername, new_printername);
580         ctr.printers_2->devmode = NULL;
581         ctr.printers_2->secdesc = NULL;
582
583         result = rpccli_spoolss_setprinter(cli, mem_ctx, &pol, info_level, &ctr, 0);
584         if (W_ERROR_IS_OK(result))
585                 printf("Success in setting printername.\n");
586
587  done:
588         if (opened_hnd)
589                 rpccli_spoolss_close_printer(cli, mem_ctx, &pol);
590
591         return result;
592 }
593
594 /****************************************************************************
595 ****************************************************************************/
596
597 static WERROR cmd_spoolss_getprinter(struct rpc_pipe_client *cli,
598                                        TALLOC_CTX *mem_ctx,
599                                        int argc, const char **argv)
600 {
601         POLICY_HND      pol;
602         WERROR          result;
603         uint32          info_level = 1;
604         bool            opened_hnd = False;
605         PRINTER_INFO_CTR ctr;
606         fstring         printername,
607                         servername,
608                         user;
609
610         if (argc == 1 || argc > 3) {
611                 printf("Usage: %s <printername> [level]\n", argv[0]);
612                 return WERR_OK;
613         }
614
615         /* Open a printer handle */
616         if (argc == 3) {
617                 info_level = atoi(argv[2]);
618         }
619
620         slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->cli->desthost);
621         strupper_m(servername);
622         slprintf(printername, sizeof(printername)-1, "%s\\%s", servername, argv[1]);
623         fstrcpy(user, cli->user_name);
624         
625         /* get a printer handle */
626
627         result = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername, 
628                                              "", MAXIMUM_ALLOWED_ACCESS, 
629                                              servername, user, &pol);
630
631         if (!W_ERROR_IS_OK(result))
632                 goto done;
633  
634         opened_hnd = True;
635
636         /* Get printer info */
637
638         result = rpccli_spoolss_getprinter(cli, mem_ctx, &pol, info_level, &ctr);
639
640         if (!W_ERROR_IS_OK(result))
641                 goto done;
642
643         /* Display printer info */
644
645         switch (info_level) {
646         case 0: 
647                 display_print_info_0(ctr.printers_0);
648                 break;
649         case 1:
650                 display_print_info_1(ctr.printers_1);
651                 break;
652         case 2:
653                 display_print_info_2(ctr.printers_2);
654                 break;
655         case 3:
656                 display_print_info_3(ctr.printers_3);
657                 break;
658         case 7:
659                 display_print_info_7(ctr.printers_7);
660                 break;
661         default:
662                 printf("unknown info level %d\n", info_level);
663                 break;
664         }
665
666  done: 
667         if (opened_hnd) 
668                 rpccli_spoolss_close_printer(cli, mem_ctx, &pol);
669
670         return result;
671 }
672
673 /****************************************************************************
674 ****************************************************************************/
675
676 static void display_reg_value(REGISTRY_VALUE value)
677 {
678         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->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->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->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
1226         /* get the next token */
1227         ptr = strtok(str, delim);
1228
1229         /* a string of 'NULL' is used to represent an empty
1230            parameter because two consecutive delimiters
1231            will not return an empty string.  See man strtok(3)
1232            for details */
1233         if (ptr && (StrCaseCmp(ptr, "NULL") == 0))
1234                 ptr = NULL;
1235
1236         if (dest != NULL)
1237                 init_unistr(dest, ptr); 
1238
1239         return ptr;
1240 }
1241
1242 /********************************************************************************
1243  fill in the members of a DRIVER_INFO_3 struct using a character 
1244  string in the form of
1245          <Long Printer Name>:<Driver File Name>:<Data File Name>:\
1246              <Config File Name>:<Help File Name>:<Language Monitor Name>:\
1247              <Default Data Type>:<Comma Separated list of Files> 
1248  *******************************************************************************/
1249 static bool init_drv_info_3_members ( TALLOC_CTX *mem_ctx, DRIVER_INFO_3 *info, 
1250                                       char *args )
1251 {
1252         char    *str, *str2;
1253         uint32  len, i;
1254         
1255         /* fill in the UNISTR fields */
1256         str = get_driver_3_param (args, ":", &info->name);
1257         str = get_driver_3_param (NULL, ":", &info->driverpath);
1258         str = get_driver_3_param (NULL, ":", &info->datafile);
1259         str = get_driver_3_param (NULL, ":", &info->configfile);
1260         str = get_driver_3_param (NULL, ":", &info->helpfile);
1261         str = get_driver_3_param (NULL, ":", &info->monitorname);
1262         str = get_driver_3_param (NULL, ":", &info->defaultdatatype);
1263
1264         /* <Comma Separated List of Dependent Files> */
1265         str2 = get_driver_3_param (NULL, ":", NULL); /* save the beginning of the string */
1266         str = str2;                     
1267
1268         /* begin to strip out each filename */
1269         str = strtok(str, ",");         
1270         len = 0;
1271         while (str != NULL)
1272         {
1273                 /* keep a cumlative count of the str lengths */
1274                 len += strlen(str)+1;
1275                 str = strtok(NULL, ",");
1276         }
1277
1278         /* allocate the space; add one extra slot for a terminating NULL.
1279            Each filename is NULL terminated and the end contains a double
1280            NULL */
1281         if ((info->dependentfiles=TALLOC_ARRAY(mem_ctx, uint16, len+1)) == NULL)
1282         {
1283                 DEBUG(0,("init_drv_info_3_members: Unable to malloc memory for dependenfiles\n"));
1284                 return False;
1285         }
1286         for (i=0; i<len; i++)
1287         {
1288                 SSVAL(&info->dependentfiles[i], 0, str2[i]);
1289         }
1290         info->dependentfiles[len] = '\0';
1291
1292         return True;
1293 }
1294
1295
1296 /****************************************************************************
1297 ****************************************************************************/
1298
1299 static WERROR cmd_spoolss_addprinterdriver(struct rpc_pipe_client *cli, 
1300                                              TALLOC_CTX *mem_ctx,
1301                                              int argc, const char **argv)
1302 {
1303         WERROR result;
1304         uint32                  level = 3;
1305         PRINTER_DRIVER_CTR      ctr;
1306         DRIVER_INFO_3           info3;
1307         const char              *arch;
1308         fstring                 driver_name;
1309         char                    *driver_args;
1310
1311         /* parse the command arguements */
1312         if (argc != 3 && argc != 4)
1313         {
1314                 printf ("Usage: %s <Environment> \\\n", argv[0]);
1315                 printf ("\t<Long Printer Name>:<Driver File Name>:<Data File Name>:\\\n");
1316                 printf ("\t<Config File Name>:<Help File Name>:<Language Monitor Name>:\\\n");
1317                 printf ("\t<Default Data Type>:<Comma Separated list of Files> \\\n");
1318                 printf ("\t[version]\n");
1319
1320             return WERR_OK;
1321         }
1322                 
1323         /* Fill in the DRIVER_INFO_3 struct */
1324         ZERO_STRUCT(info3);
1325         if (!(arch = cmd_spoolss_get_short_archi(argv[1])))
1326         {
1327                 printf ("Error Unknown architechture [%s]\n", argv[1]);
1328                 return WERR_INVALID_PARAM;
1329         }
1330         else
1331                 set_drv_info_3_env(&info3, arch);
1332
1333         driver_args = talloc_strdup( mem_ctx, argv[2] );
1334         if (!init_drv_info_3_members(mem_ctx, &info3, driver_args ))
1335         {
1336                 printf ("Error Invalid parameter list - %s.\n", argv[2]);
1337                 return WERR_INVALID_PARAM;
1338         }
1339
1340         /* if printer driver version specified, override the default version
1341          * used by the architecture.  This allows installation of Windows
1342          * 2000 (version 3) printer drivers. */
1343         if (argc == 4)
1344         {
1345                 info3.version = atoi(argv[3]);
1346         }
1347
1348
1349         ctr.info3 = &info3;
1350         result = rpccli_spoolss_addprinterdriver (cli, mem_ctx, level, &ctr);
1351
1352         if (W_ERROR_IS_OK(result)) {
1353                 rpcstr_pull(driver_name, info3.name.buffer, 
1354                             sizeof(driver_name), -1, STR_TERMINATE);
1355                 printf ("Printer Driver %s successfully installed.\n",
1356                         driver_name);
1357         }
1358
1359         return result;
1360 }
1361
1362
1363 /****************************************************************************
1364 ****************************************************************************/
1365
1366 static WERROR cmd_spoolss_addprinterex(struct rpc_pipe_client *cli, 
1367                                          TALLOC_CTX *mem_ctx,
1368                                          int argc, const char **argv)
1369 {
1370         WERROR result;
1371         uint32                  level = 2;
1372         PRINTER_INFO_CTR        ctr;
1373         PRINTER_INFO_2          info2;
1374         fstring                 servername;
1375         
1376         /* parse the command arguements */
1377         if (argc != 5)
1378         {
1379                 printf ("Usage: %s <name> <shared name> <driver> <port>\n", argv[0]);
1380                 return WERR_OK;
1381         }
1382         
1383         slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->cli->desthost);
1384         strupper_m(servername);
1385
1386         /* Fill in the DRIVER_INFO_2 struct */
1387         ZERO_STRUCT(info2);
1388         
1389         init_unistr( &info2.printername,        argv[1]);
1390         init_unistr( &info2.sharename,          argv[2]);
1391         init_unistr( &info2.drivername,         argv[3]);
1392         init_unistr( &info2.portname,           argv[4]);
1393         init_unistr( &info2.comment,            "Created by rpcclient");
1394         init_unistr( &info2.printprocessor,     "winprint");
1395         init_unistr( &info2.datatype,           "RAW");
1396         info2.devmode =         NULL;
1397         info2.secdesc =         NULL;
1398         info2.attributes        = PRINTER_ATTRIBUTE_SHARED;
1399         info2.priority          = 0;
1400         info2.defaultpriority   = 0;
1401         info2.starttime         = 0;
1402         info2.untiltime         = 0;
1403         
1404         /* These three fields must not be used by AddPrinter() 
1405            as defined in the MS Platform SDK documentation..  
1406            --jerry
1407         info2.status            = 0;
1408         info2.cjobs             = 0;
1409         info2.averageppm        = 0;
1410         */
1411
1412         ctr.printers_2 = &info2;
1413         result = rpccli_spoolss_addprinterex (cli, mem_ctx, level, &ctr);
1414
1415         if (W_ERROR_IS_OK(result))
1416                 printf ("Printer %s successfully installed.\n", argv[1]);
1417
1418         return result;
1419 }
1420
1421 /****************************************************************************
1422 ****************************************************************************/
1423
1424 static WERROR cmd_spoolss_setdriver(struct rpc_pipe_client *cli, 
1425                                       TALLOC_CTX *mem_ctx,
1426                                       int argc, const char **argv)
1427 {
1428         POLICY_HND              pol;
1429         WERROR                  result;
1430         uint32                  level = 2;
1431         bool                    opened_hnd = False;
1432         PRINTER_INFO_CTR        ctr;
1433         PRINTER_INFO_2          info2;
1434         fstring                 servername,
1435                                 printername,
1436                                 user;
1437         
1438         /* parse the command arguements */
1439         if (argc != 3)
1440         {
1441                 printf ("Usage: %s <printer> <driver>\n", argv[0]);
1442                 return WERR_OK;
1443         }
1444
1445         slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->cli->desthost);
1446         strupper_m(servername);
1447         slprintf(printername, sizeof(printername)-1, "%s\\%s", servername, argv[1]);
1448         fstrcpy(user, cli->user_name);
1449
1450         /* Get a printer handle */
1451
1452         result = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername, "", 
1453                                              PRINTER_ALL_ACCESS,
1454                                              servername, user, &pol);
1455
1456         if (!W_ERROR_IS_OK(result))
1457                 goto done;
1458
1459         opened_hnd = True;
1460
1461         /* Get printer info */
1462
1463         ZERO_STRUCT (info2);
1464         ctr.printers_2 = &info2;
1465
1466         result = rpccli_spoolss_getprinter(cli, mem_ctx, &pol, level, &ctr);
1467
1468         if (!W_ERROR_IS_OK(result)) {
1469                 printf ("Unable to retrieve printer information!\n");
1470                 goto done;
1471         }
1472
1473         /* Set the printer driver */
1474
1475         init_unistr(&ctr.printers_2->drivername, argv[2]);
1476
1477         result = rpccli_spoolss_setprinter(cli, mem_ctx, &pol, level, &ctr, 0);
1478
1479         if (!W_ERROR_IS_OK(result)) {
1480                 printf("SetPrinter call failed!\n");
1481                 goto done;;
1482         }
1483
1484         printf("Succesfully set %s to driver %s.\n", argv[1], argv[2]);
1485
1486 done:
1487         /* Cleanup */
1488
1489         if (opened_hnd)
1490                 rpccli_spoolss_close_printer(cli, mem_ctx, &pol);
1491
1492         return result;
1493 }
1494
1495
1496 /****************************************************************************
1497 ****************************************************************************/
1498
1499 static WERROR cmd_spoolss_deletedriverex(struct rpc_pipe_client *cli, 
1500                                          TALLOC_CTX *mem_ctx,
1501                                          int argc, const char **argv)
1502 {
1503         WERROR result, ret = WERR_UNKNOWN_PRINTER_DRIVER;
1504  
1505         int   i;
1506         int vers = -1;
1507  
1508         const char *arch = NULL;
1509  
1510         /* parse the command arguements */
1511         if (argc < 2 || argc > 4) {
1512                 printf ("Usage: %s <driver> [arch] [version]\n", argv[0]);
1513                 return WERR_OK;
1514         }
1515
1516         if (argc >= 3)
1517                 arch = argv[2];
1518         if (argc == 4)
1519                 vers = atoi (argv[3]);
1520  
1521  
1522         /* delete the driver for all architectures */
1523         for (i=0; archi_table[i].long_archi; i++) {
1524
1525                 if (arch &&  !strequal( archi_table[i].long_archi, arch)) 
1526                         continue;
1527
1528                 if (vers >= 0 && archi_table[i].version != vers)
1529                         continue;
1530
1531                 /* make the call to remove the driver */
1532                 result = rpccli_spoolss_deleteprinterdriverex(
1533                         cli, mem_ctx, archi_table[i].long_archi, argv[1], archi_table[i].version); 
1534
1535                 if ( !W_ERROR_IS_OK(result) ) 
1536                 {
1537                         if ( !W_ERROR_EQUAL(result, WERR_UNKNOWN_PRINTER_DRIVER) ) {
1538                                 printf ("Failed to remove driver %s for arch [%s] (version: %d): %s\n", 
1539                                         argv[1], archi_table[i].long_archi, archi_table[i].version, dos_errstr(result));
1540                         }
1541                 } 
1542                 else 
1543                 {
1544                         printf ("Driver %s and files removed for arch [%s] (version: %d).\n", argv[1], 
1545                         archi_table[i].long_archi, archi_table[i].version);
1546                         ret = WERR_OK;
1547                 }
1548         }
1549   
1550         return ret;
1551 }
1552
1553
1554 /****************************************************************************
1555 ****************************************************************************/
1556
1557 static WERROR cmd_spoolss_deletedriver(struct rpc_pipe_client *cli, 
1558                                          TALLOC_CTX *mem_ctx,
1559                                          int argc, const char **argv)
1560 {
1561         WERROR result = WERR_OK;
1562         fstring                 servername;
1563         int                     i;
1564         
1565         /* parse the command arguements */
1566         if (argc != 2) {
1567                 printf ("Usage: %s <driver>\n", argv[0]);
1568                 return WERR_OK;
1569         }
1570
1571         slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->cli->desthost);
1572         strupper_m(servername);
1573
1574         /* delete the driver for all architectures */
1575         for (i=0; archi_table[i].long_archi; i++) {
1576                 /* make the call to remove the driver */
1577                 result = rpccli_spoolss_deleteprinterdriver(
1578                         cli, mem_ctx, archi_table[i].long_archi, argv[1]);
1579
1580                 if ( !W_ERROR_IS_OK(result) ) {
1581                         if ( !W_ERROR_EQUAL(result, WERR_UNKNOWN_PRINTER_DRIVER) ) {
1582                                 printf ("Failed to remove driver %s for arch [%s] - error 0x%x!\n", 
1583                                         argv[1], archi_table[i].long_archi, 
1584                                         W_ERROR_V(result));
1585                         }
1586                 } else {
1587                         printf ("Driver %s removed for arch [%s].\n", argv[1], 
1588                                 archi_table[i].long_archi);
1589                 }
1590         }
1591                 
1592         return result;
1593 }
1594
1595 /****************************************************************************
1596 ****************************************************************************/
1597
1598 static WERROR cmd_spoolss_getprintprocdir(struct rpc_pipe_client *cli, 
1599                                             TALLOC_CTX *mem_ctx,
1600                                             int argc, const char **argv)
1601 {
1602         WERROR result;
1603         char *servername = NULL, *environment = NULL;
1604         fstring procdir;
1605         
1606         /* parse the command arguements */
1607         if (argc > 2) {
1608                 printf ("Usage: %s [environment]\n", argv[0]);
1609                 return WERR_OK;
1610         }
1611
1612         if (asprintf(&servername, "\\\\%s", cli->cli->desthost) < 0)
1613                 return WERR_NOMEM;
1614         strupper_m(servername);
1615
1616         if (asprintf(&environment, "%s", (argc == 2) ? argv[1] : 
1617                      PRINTER_DRIVER_ARCHITECTURE) < 0) {
1618                 SAFE_FREE(servername);
1619                 return WERR_NOMEM;
1620         }
1621
1622         result = rpccli_spoolss_getprintprocessordirectory(
1623                 cli, mem_ctx, servername, environment, procdir);
1624
1625         if (W_ERROR_IS_OK(result))
1626                 printf("%s\n", procdir);
1627
1628         SAFE_FREE(servername);
1629         SAFE_FREE(environment);
1630
1631         return result;
1632 }
1633
1634 /****************************************************************************
1635 ****************************************************************************/
1636
1637 static WERROR cmd_spoolss_addform(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
1638                                     int argc, const char **argv)
1639 {
1640         POLICY_HND handle;
1641         WERROR werror;
1642         char *servername = NULL, *printername = NULL;
1643         FORM form;
1644         bool got_handle = False;
1645         
1646         /* Parse the command arguements */
1647
1648         if (argc != 3) {
1649                 printf ("Usage: %s <printer> <formname>\n", argv[0]);
1650                 return WERR_OK;
1651         }
1652         
1653         /* Get a printer handle */
1654
1655         asprintf(&servername, "\\\\%s", cli->cli->desthost);
1656         strupper_m(servername);
1657         asprintf(&printername, "%s\\%s", servername, argv[1]);
1658
1659         werror = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername, "", 
1660                                              PRINTER_ALL_ACCESS, 
1661                                              servername, cli->user_name, &handle);
1662
1663         if (!W_ERROR_IS_OK(werror))
1664                 goto done;
1665
1666         got_handle = True;
1667
1668         /* Dummy up some values for the form data */
1669
1670         form.flags = FORM_USER;
1671         form.size_x = form.size_y = 100;
1672         form.left = 0;
1673         form.top = 10;
1674         form.right = 20;
1675         form.bottom = 30;
1676
1677         init_unistr2(&form.name, argv[2], UNI_STR_TERMINATE);
1678
1679         /* Add the form */
1680
1681
1682         werror = rpccli_spoolss_addform(cli, mem_ctx, &handle, 1, &form);
1683
1684  done:
1685         if (got_handle)
1686                 rpccli_spoolss_close_printer(cli, mem_ctx, &handle);
1687
1688         SAFE_FREE(servername);
1689         SAFE_FREE(printername);
1690
1691         return werror;
1692 }
1693
1694 /****************************************************************************
1695 ****************************************************************************/
1696
1697 static WERROR cmd_spoolss_setform(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
1698                                     int argc, const char **argv)
1699 {
1700         POLICY_HND handle;
1701         WERROR werror;
1702         char *servername = NULL, *printername = NULL;
1703         FORM form;
1704         bool got_handle = False;
1705         
1706         /* Parse the command arguements */
1707
1708         if (argc != 3) {
1709                 printf ("Usage: %s <printer> <formname>\n", argv[0]);
1710                 return WERR_OK;
1711         }
1712         
1713         /* Get a printer handle */
1714
1715         asprintf(&servername, "\\\\%s", cli->cli->desthost);
1716         strupper_m(servername);
1717         asprintf(&printername, "%s\\%s", servername, argv[1]);
1718
1719         werror = rpccli_spoolss_open_printer_ex(
1720                 cli, mem_ctx, printername, "", MAXIMUM_ALLOWED_ACCESS, 
1721                 servername, cli->user_name, &handle);
1722
1723         if (!W_ERROR_IS_OK(werror))
1724                 goto done;
1725
1726         got_handle = True;
1727
1728         /* Dummy up some values for the form data */
1729
1730         form.flags = FORM_PRINTER;
1731         form.size_x = form.size_y = 100;
1732         form.left = 0;
1733         form.top = 1000;
1734         form.right = 2000;
1735         form.bottom = 3000;
1736
1737         init_unistr2(&form.name, argv[2], UNI_STR_TERMINATE);
1738
1739         /* Set the form */
1740
1741         werror = rpccli_spoolss_setform(cli, mem_ctx, &handle, 1, argv[2], &form);
1742
1743  done:
1744         if (got_handle)
1745                 rpccli_spoolss_close_printer(cli, mem_ctx, &handle);
1746
1747         SAFE_FREE(servername);
1748         SAFE_FREE(printername);
1749
1750         return werror;
1751 }
1752
1753 /****************************************************************************
1754 ****************************************************************************/
1755
1756 static const char *get_form_flag(int form_flag)
1757 {
1758         switch (form_flag) {
1759         case FORM_USER:
1760                 return "FORM_USER";
1761         case FORM_BUILTIN:
1762                 return "FORM_BUILTIN";
1763         case FORM_PRINTER:
1764                 return "FORM_PRINTER";
1765         default:
1766                 return "unknown";
1767         }
1768 }
1769
1770 /****************************************************************************
1771 ****************************************************************************/
1772
1773 static void display_form(FORM_1 *form)
1774 {
1775         fstring form_name = "";
1776
1777         if (form->name.buffer)
1778                 rpcstr_pull(form_name, form->name.buffer,
1779                             sizeof(form_name), -1, STR_TERMINATE);
1780
1781         printf("%s\n" \
1782                 "\tflag: %s (%d)\n" \
1783                 "\twidth: %d, length: %d\n" \
1784                 "\tleft: %d, right: %d, top: %d, bottom: %d\n\n", 
1785                 form_name, get_form_flag(form->flag), form->flag,
1786                 form->width, form->length, 
1787                 form->left, form->right, 
1788                 form->top, form->bottom);
1789 }
1790
1791 /****************************************************************************
1792 ****************************************************************************/
1793
1794 static WERROR cmd_spoolss_getform(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
1795                                     int argc, const char **argv)
1796 {
1797         POLICY_HND handle;
1798         WERROR werror;
1799         char *servername = NULL, *printername = NULL;
1800         FORM_1 form;
1801         bool got_handle = False;
1802         
1803         /* Parse the command arguements */
1804
1805         if (argc != 3) {
1806                 printf ("Usage: %s <printer> <formname>\n", argv[0]);
1807                 return WERR_OK;
1808         }
1809         
1810         /* Get a printer handle */
1811
1812         asprintf(&servername, "\\\\%s", cli->cli->desthost);
1813         strupper_m(servername);
1814         asprintf(&printername, "%s\\%s", servername, argv[1]);
1815
1816         werror = rpccli_spoolss_open_printer_ex(
1817                 cli, mem_ctx, printername, "", MAXIMUM_ALLOWED_ACCESS, 
1818                 servername, cli->user_name, &handle);
1819
1820         if (!W_ERROR_IS_OK(werror))
1821                 goto done;
1822
1823         got_handle = True;
1824
1825         /* Get the form */
1826
1827         werror = rpccli_spoolss_getform(cli, mem_ctx, &handle, argv[2], 1, &form);
1828
1829         if (!W_ERROR_IS_OK(werror))
1830                 goto done;
1831
1832         display_form(&form);
1833
1834  done:
1835         if (got_handle)
1836                 rpccli_spoolss_close_printer(cli, mem_ctx, &handle);
1837
1838         SAFE_FREE(servername);
1839         SAFE_FREE(printername);
1840
1841         return werror;
1842 }
1843
1844 /****************************************************************************
1845 ****************************************************************************/
1846
1847 static WERROR cmd_spoolss_deleteform(struct rpc_pipe_client *cli, 
1848                                        TALLOC_CTX *mem_ctx, int argc, 
1849                                        const char **argv)
1850 {
1851         POLICY_HND handle;
1852         WERROR werror;
1853         char *servername = NULL, *printername = NULL;
1854         bool got_handle = False;
1855         
1856         /* Parse the command arguements */
1857
1858         if (argc != 3) {
1859                 printf ("Usage: %s <printer> <formname>\n", argv[0]);
1860                 return WERR_OK;
1861         }
1862         
1863         /* Get a printer handle */
1864
1865         asprintf(&servername, "\\\\%s", cli->cli->desthost);
1866         strupper_m(servername);
1867         asprintf(&printername, "%s\\%s", servername, argv[1]);
1868
1869         werror = rpccli_spoolss_open_printer_ex(
1870                 cli, mem_ctx, printername, "", MAXIMUM_ALLOWED_ACCESS, 
1871                 servername, cli->user_name, &handle);
1872
1873         if (!W_ERROR_IS_OK(werror))
1874                 goto done;
1875
1876         got_handle = True;
1877
1878         /* Delete the form */
1879
1880         werror = rpccli_spoolss_deleteform(cli, mem_ctx, &handle, argv[2]);
1881
1882  done:
1883         if (got_handle)
1884                 rpccli_spoolss_close_printer(cli, mem_ctx, &handle);
1885
1886         SAFE_FREE(servername);
1887         SAFE_FREE(printername);
1888
1889         return werror;
1890 }
1891
1892 /****************************************************************************
1893 ****************************************************************************/
1894
1895 static WERROR cmd_spoolss_enum_forms(struct rpc_pipe_client *cli, 
1896                                        TALLOC_CTX *mem_ctx, int argc, 
1897                                        const char **argv)
1898 {
1899         POLICY_HND handle;
1900         WERROR werror;
1901         char *servername = NULL, *printername = NULL;
1902         bool got_handle = False;
1903         uint32 num_forms, level = 1, i;
1904         FORM_1 *forms;
1905         
1906         /* Parse the command arguements */
1907
1908         if (argc != 2) {
1909                 printf ("Usage: %s <printer>\n", argv[0]);
1910                 return WERR_OK;
1911         }
1912         
1913         /* Get a printer handle */
1914
1915         asprintf(&servername, "\\\\%s", cli->cli->desthost);
1916         strupper_m(servername);
1917         asprintf(&printername, "%s\\%s", servername, argv[1]);
1918
1919         werror = rpccli_spoolss_open_printer_ex(
1920                 cli, mem_ctx, printername, "", MAXIMUM_ALLOWED_ACCESS, 
1921                 servername, cli->user_name, &handle);
1922
1923         if (!W_ERROR_IS_OK(werror))
1924                 goto done;
1925
1926         got_handle = True;
1927
1928         /* Enumerate forms */
1929
1930         werror = rpccli_spoolss_enumforms(cli, mem_ctx, &handle, level, &num_forms, &forms);
1931
1932         if (!W_ERROR_IS_OK(werror))
1933                 goto done;
1934
1935         /* Display output */
1936
1937         for (i = 0; i < num_forms; i++) {
1938
1939                 display_form(&forms[i]);
1940
1941         }
1942
1943  done:
1944         if (got_handle)
1945                 rpccli_spoolss_close_printer(cli, mem_ctx, &handle);
1946
1947         SAFE_FREE(servername);
1948         SAFE_FREE(printername);
1949
1950         return werror;
1951 }
1952
1953 /****************************************************************************
1954 ****************************************************************************/
1955
1956 static WERROR cmd_spoolss_setprinterdata(struct rpc_pipe_client *cli,
1957                                             TALLOC_CTX *mem_ctx,
1958                                             int argc, const char **argv)
1959 {
1960         WERROR result;
1961         fstring servername, printername, user;
1962         POLICY_HND pol;
1963         bool opened_hnd = False;
1964         PRINTER_INFO_CTR ctr;
1965         PRINTER_INFO_0 info;
1966         REGISTRY_VALUE value;
1967
1968         /* parse the command arguements */
1969         if (argc < 5) {
1970                 printf ("Usage: %s <printer> <string|binary|dword|multistring>"
1971                         " <value> <data>\n",
1972                         argv[0]);
1973                 return WERR_INVALID_PARAM;
1974         }
1975
1976         slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->cli->desthost);
1977         strupper_m(servername);
1978         slprintf(printername, sizeof(servername)-1, "%s\\%s", servername, argv[1]);
1979         fstrcpy(user, cli->user_name);
1980
1981         value.type = REG_NONE;
1982
1983         if (strequal(argv[2], "string")) {
1984                 value.type = REG_SZ;
1985         }
1986
1987         if (strequal(argv[2], "binary")) {
1988                 value.type = REG_BINARY;
1989         }
1990
1991         if (strequal(argv[2], "dword")) {
1992                 value.type = REG_DWORD;
1993         }
1994
1995         if (strequal(argv[2], "multistring")) {
1996                 value.type = REG_MULTI_SZ;
1997         }
1998
1999         if (value.type == REG_NONE) {
2000                 printf("Unknown data type: %s\n", argv[2]);
2001                 return WERR_INVALID_PARAM;
2002         }
2003
2004         /* get a printer handle */
2005         result = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername, "",
2006                                              MAXIMUM_ALLOWED_ACCESS, servername, 
2007                                              user, &pol);
2008         if (!W_ERROR_IS_OK(result))
2009                 goto done;
2010
2011         opened_hnd = True;
2012
2013         ctr.printers_0 = &info;
2014
2015         result = rpccli_spoolss_getprinter(cli, mem_ctx, &pol, 0, &ctr);
2016
2017         if (!W_ERROR_IS_OK(result))
2018                 goto done;
2019                 
2020         printf("%s\n", current_timestring(True));
2021         printf("\tchange_id (before set)\t:[0x%x]\n", info.change_id);
2022
2023         /* Set the printer data */
2024         
2025         fstrcpy(value.valuename, argv[3]);
2026
2027         switch (value.type) {
2028         case REG_SZ: {
2029                 UNISTR2 data;
2030                 init_unistr2(&data, argv[4], UNI_STR_TERMINATE);
2031                 value.size = data.uni_str_len * 2;
2032                 if (value.size) {
2033                         value.data_p = (uint8 *)TALLOC_MEMDUP(mem_ctx, data.buffer,
2034                                                       value.size);
2035                 } else {
2036                         value.data_p = NULL;
2037                 }
2038                 break;
2039         }
2040         case REG_DWORD: {
2041                 uint32 data = strtoul(argv[4], NULL, 10);
2042                 value.size = sizeof(data);
2043                 if (sizeof(data)) {
2044                         value.data_p = (uint8 *)TALLOC_MEMDUP(mem_ctx, &data,
2045                                                       sizeof(data));
2046                 } else {
2047                         value.data_p = NULL;
2048                 }
2049                 break;
2050         }
2051         case REG_BINARY: {
2052                 DATA_BLOB data = strhex_to_data_blob(mem_ctx, argv[4]);
2053                 value.data_p = data.data;
2054                 value.size = data.length;
2055                 break;
2056         }
2057         case REG_MULTI_SZ: {
2058                 int i;
2059                 size_t len = 0;
2060                 char *p;
2061
2062                 for (i=4; i<argc; i++) {
2063                         if (strcmp(argv[i], "NULL") == 0) {
2064                                 argv[i] = "";
2065                         }
2066                         len += strlen(argv[i])+1;
2067                 }
2068
2069                 value.size = len*2;
2070                 value.data_p = TALLOC_ARRAY(mem_ctx, unsigned char, value.size);
2071                 if (value.data_p == NULL) {
2072                         result = WERR_NOMEM;
2073                         goto done;
2074                 }
2075
2076                 p = (char *)value.data_p;
2077                 len = value.size;
2078                 for (i=4; i<argc; i++) {
2079                         size_t l = (strlen(argv[i])+1)*2;
2080                         rpcstr_push(p, argv[i], len, STR_TERMINATE);
2081                         p += l;
2082                         len -= l;
2083                 }
2084                 SMB_ASSERT(len == 0);
2085                 break;
2086         }
2087         default:
2088                 printf("Unknown data type: %s\n", argv[2]);
2089                 result = WERR_INVALID_PARAM;
2090                 goto done;
2091         }
2092
2093         result = rpccli_spoolss_setprinterdata(cli, mem_ctx, &pol, &value);
2094                 
2095         if (!W_ERROR_IS_OK(result)) {
2096                 printf ("Unable to set [%s=%s]!\n", argv[3], argv[4]);
2097                 goto done;
2098         }
2099         printf("\tSetPrinterData succeeded [%s: %s]\n", argv[3], argv[4]);
2100         
2101         result = rpccli_spoolss_getprinter(cli, mem_ctx, &pol, 0, &ctr);
2102
2103         if (!W_ERROR_IS_OK(result))
2104                 goto done;
2105                 
2106         printf("%s\n", current_timestring(True));
2107         printf("\tchange_id (after set)\t:[0x%x]\n", info.change_id);
2108
2109 done:
2110         /* cleanup */
2111         if (opened_hnd)
2112                 rpccli_spoolss_close_printer(cli, mem_ctx, &pol);
2113
2114         return result;
2115 }
2116
2117 /****************************************************************************
2118 ****************************************************************************/
2119
2120 static void display_job_info_1(JOB_INFO_1 *job)
2121 {
2122         fstring username = "", document = "", text_status = "";
2123
2124         rpcstr_pull(username, job->username.buffer,
2125                     sizeof(username), -1, STR_TERMINATE);
2126
2127         rpcstr_pull(document, job->document.buffer,
2128                     sizeof(document), -1, STR_TERMINATE);
2129
2130         rpcstr_pull(text_status, job->text_status.buffer,
2131                     sizeof(text_status), -1, STR_TERMINATE);
2132
2133         printf("%d: jobid[%d]: %s %s %s %d/%d pages\n", job->position, job->jobid,
2134                username, document, text_status, job->pagesprinted,
2135                job->totalpages);
2136 }
2137
2138 /****************************************************************************
2139 ****************************************************************************/
2140
2141 static void display_job_info_2(JOB_INFO_2 *job)
2142 {
2143         fstring username = "", document = "", text_status = "";
2144
2145         rpcstr_pull(username, job->username.buffer,
2146                     sizeof(username), -1, STR_TERMINATE);
2147
2148         rpcstr_pull(document, job->document.buffer,
2149                     sizeof(document), -1, STR_TERMINATE);
2150
2151         rpcstr_pull(text_status, job->text_status.buffer,
2152                     sizeof(text_status), -1, STR_TERMINATE);
2153
2154         printf("%d: jobid[%d]: %s %s %s %d/%d pages, %d bytes\n", job->position, job->jobid,
2155                username, document, text_status, job->pagesprinted,
2156                job->totalpages, job->size);
2157 }
2158
2159 /****************************************************************************
2160 ****************************************************************************/
2161
2162 static WERROR cmd_spoolss_enum_jobs(struct rpc_pipe_client *cli, 
2163                                       TALLOC_CTX *mem_ctx, int argc, 
2164                                       const char **argv)
2165 {
2166         WERROR result;
2167         uint32 level = 1, num_jobs, i;
2168         bool got_hnd = False;
2169         char *printername = NULL;
2170         fstring servername, user;
2171         POLICY_HND hnd;
2172         JOB_INFO_CTR ctr;
2173
2174         if (argc < 2 || argc > 3) {
2175                 printf("Usage: %s printername [level]\n", argv[0]);
2176                 return WERR_OK;
2177         }
2178
2179         if (argc == 3)
2180                 level = atoi(argv[2]);
2181
2182         /* Open printer handle */
2183
2184         slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->cli->desthost);
2185         strupper_m(servername);
2186         fstrcpy(user, cli->user_name);
2187         printername = talloc_asprintf(mem_ctx,
2188                                 "\\\\%s\\",
2189                                 cli->cli->desthost);
2190         if (!printername) {
2191                 return WERR_NOMEM;
2192         }
2193         strupper_m(printername);
2194         printername = talloc_asprintf_append(printername, "%s", argv[1]);
2195         if (!printername) {
2196                 return WERR_NOMEM;
2197         }
2198
2199         result = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername,
2200                                              "", MAXIMUM_ALLOWED_ACCESS,
2201                                              servername, user, &hnd);
2202
2203         if (!W_ERROR_IS_OK(result))
2204                 goto done;
2205
2206         got_hnd = True;
2207
2208         /* Enumerate ports */
2209
2210         result = rpccli_spoolss_enumjobs(cli, mem_ctx, &hnd, level, 0, 1000,
2211                 &num_jobs, &ctr);
2212
2213         if (!W_ERROR_IS_OK(result))
2214                 goto done;
2215
2216         for (i = 0; i < num_jobs; i++) {
2217                 switch(level) {
2218                 case 1:
2219                         display_job_info_1(&ctr.job.job_info_1[i]);
2220                         break;
2221                 case 2:
2222                         display_job_info_2(&ctr.job.job_info_2[i]);
2223                         break;
2224                 default:
2225                         d_printf("unknown info level %d\n", level);
2226                         break;
2227                 }
2228         }
2229         
2230 done:
2231         if (got_hnd)
2232                 rpccli_spoolss_close_printer(cli, mem_ctx, &hnd);
2233
2234         return result;
2235 }
2236
2237 /****************************************************************************
2238 ****************************************************************************/
2239
2240 static WERROR cmd_spoolss_enum_data( struct rpc_pipe_client *cli, 
2241                                        TALLOC_CTX *mem_ctx, int argc, 
2242                                        const char **argv)
2243 {
2244         WERROR result;
2245         uint32 i=0, val_needed, data_needed;
2246         bool got_hnd = False;
2247         char *printername = NULL;
2248         fstring servername, user;
2249         POLICY_HND hnd;
2250
2251         if (argc != 2) {
2252                 printf("Usage: %s printername\n", argv[0]);
2253                 return WERR_OK;
2254         }
2255
2256         /* Open printer handle */
2257
2258         slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->cli->desthost);
2259         strupper_m(servername);
2260         fstrcpy(user, cli->user_name);
2261         printername = talloc_asprintf(mem_ctx,
2262                                 "\\\\%s\\",
2263                                 cli->cli->desthost);
2264         if (!printername) {
2265                 return WERR_NOMEM;
2266         }
2267         strupper_m(printername);
2268         printername = talloc_asprintf_append(printername, "%s", argv[1]);
2269         if (!printername) {
2270                 return WERR_NOMEM;
2271         }
2272
2273         result = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername,
2274                                              "", MAXIMUM_ALLOWED_ACCESS,
2275                                              servername, user, &hnd);
2276
2277         if (!W_ERROR_IS_OK(result))
2278                 goto done;
2279  
2280         got_hnd = True;
2281
2282         /* Enumerate data */
2283
2284         result = rpccli_spoolss_enumprinterdata(cli, mem_ctx, &hnd, i, 0, 0,
2285                                              &val_needed, &data_needed,
2286                                              NULL);
2287         while (W_ERROR_IS_OK(result)) {
2288                 REGISTRY_VALUE value;
2289                 result = rpccli_spoolss_enumprinterdata(
2290                         cli, mem_ctx, &hnd, i++, val_needed,
2291                         data_needed, 0, 0, &value);
2292                 if (W_ERROR_IS_OK(result))
2293                         display_reg_value(value);
2294         }
2295         if (W_ERROR_V(result) == ERRnomoreitems)
2296                 result = W_ERROR(ERRsuccess);
2297
2298 done:
2299         if (got_hnd)
2300                 rpccli_spoolss_close_printer(cli, mem_ctx, &hnd);
2301
2302         return result;
2303 }
2304
2305 /****************************************************************************
2306 ****************************************************************************/
2307
2308 static WERROR cmd_spoolss_enum_data_ex( struct rpc_pipe_client *cli, 
2309                                           TALLOC_CTX *mem_ctx, int argc, 
2310                                           const char **argv)
2311 {
2312         WERROR result;
2313         uint32 i;
2314         bool got_hnd = False;
2315         char *printername = NULL;
2316         fstring servername, user;
2317         const char *keyname = NULL;
2318         POLICY_HND hnd;
2319         REGVAL_CTR *ctr = NULL;
2320
2321         if (argc != 3) {
2322                 printf("Usage: %s printername <keyname>\n", argv[0]);
2323                 return WERR_OK;
2324         }
2325
2326         keyname = argv[2];
2327
2328         /* Open printer handle */
2329
2330         slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->cli->desthost);
2331         strupper_m(servername);
2332         fstrcpy(user, cli->user_name);
2333
2334         printername = talloc_asprintf(mem_ctx,
2335                                 "\\\\%s\\",
2336                                 cli->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->cli->desthost);
2406         strupper_m(servername);
2407         fstrcpy(user, cli->user_name);
2408
2409         printername = talloc_asprintf(mem_ctx,
2410                                 "\\\\%s\\",
2411                                 cli->cli->desthost);
2412         if (!printername) {
2413                 return WERR_NOMEM;
2414         }
2415         strupper_m(printername);
2416         printername = talloc_asprintf_append(printername, "%s", argv[1]);
2417         if (!printername) {
2418                 return WERR_NOMEM;
2419         }
2420
2421
2422         result = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername, 
2423                                              "", MAXIMUM_ALLOWED_ACCESS, 
2424                                              servername, user, &hnd);
2425
2426         if (!W_ERROR_IS_OK(result))
2427                 goto done;
2428          
2429         got_hnd = True;
2430
2431         /* Enumerate subkeys */
2432
2433         result = rpccli_spoolss_enumprinterkey(cli, mem_ctx, &hnd, keyname, &keylist, NULL);
2434
2435         if (!W_ERROR_IS_OK(result))
2436                 goto done;
2437
2438         curkey = keylist;
2439         while (*curkey != 0) {
2440                 char *subkey = NULL;
2441                 rpcstr_pull_talloc(mem_ctx, &subkey, curkey, -1,
2442                             STR_TERMINATE);
2443                 if (!subkey) {
2444                         break;
2445                 }
2446                 printf("%s\n", subkey);
2447                 curkey += strlen(subkey) + 1;
2448         }
2449
2450 done:
2451
2452         SAFE_FREE(keylist);
2453
2454         if (got_hnd)
2455                 rpccli_spoolss_close_printer(cli, mem_ctx, &hnd);
2456
2457         return result;
2458 }
2459
2460 /****************************************************************************
2461 ****************************************************************************/
2462
2463 static WERROR cmd_spoolss_rffpcnex(struct rpc_pipe_client *cli, 
2464                                      TALLOC_CTX *mem_ctx, int argc, 
2465                                      const char **argv)
2466 {
2467         fstring servername, printername;
2468         POLICY_HND hnd;
2469         bool got_hnd = False;
2470         WERROR result;
2471         SPOOL_NOTIFY_OPTION option;
2472
2473         if (argc != 2) {
2474                 printf("Usage: %s printername\n", argv[0]);
2475                 result = WERR_OK;
2476                 goto done;
2477         }
2478
2479         /* Open printer */
2480
2481         slprintf(servername, sizeof(servername) - 1, "\\\\%s", cli->cli->desthost);
2482         strupper_m(servername);
2483
2484         slprintf(printername, sizeof(printername) - 1, "\\\\%s\\%s", cli->cli->desthost,
2485                  argv[1]);
2486         strupper_m(printername);
2487
2488         result = rpccli_spoolss_open_printer_ex(
2489                 cli, mem_ctx, printername, "", MAXIMUM_ALLOWED_ACCESS, 
2490                 servername, cli->user_name, &hnd);
2491
2492         if (!W_ERROR_IS_OK(result)) {
2493                 printf("Error opening %s\n", argv[1]);
2494                 goto done;
2495         }
2496
2497         got_hnd = True;
2498
2499         /* Create spool options */
2500
2501         ZERO_STRUCT(option);
2502
2503         option.version = 2;
2504         option.option_type_ptr = 1;
2505         option.count = option.ctr.count = 2;
2506
2507         option.ctr.type = TALLOC_ARRAY(mem_ctx, SPOOL_NOTIFY_OPTION_TYPE, 2);
2508         if (option.ctr.type == NULL) {
2509                 result = WERR_NOMEM;
2510                 goto done;
2511         }
2512
2513         ZERO_STRUCT(option.ctr.type[0]);
2514         option.ctr.type[0].type = PRINTER_NOTIFY_TYPE;
2515         option.ctr.type[0].count = option.ctr.type[0].count2 = 1;
2516         option.ctr.type[0].fields_ptr = 1;
2517         option.ctr.type[0].fields[0] = PRINTER_NOTIFY_SERVER_NAME;
2518
2519         ZERO_STRUCT(option.ctr.type[1]);
2520         option.ctr.type[1].type = JOB_NOTIFY_TYPE;
2521         option.ctr.type[1].count = option.ctr.type[1].count2 = 1;
2522         option.ctr.type[1].fields_ptr = 1;
2523         option.ctr.type[1].fields[0] = JOB_NOTIFY_PRINTER_NAME;
2524
2525         /* Send rffpcnex */
2526
2527         slprintf(servername, sizeof(servername) - 1, "\\\\%s", myhostname());
2528         strupper_m(servername);
2529
2530         result = rpccli_spoolss_rffpcnex(
2531                 cli, mem_ctx, &hnd, 0, 0, servername, 123, &option);
2532
2533         if (!W_ERROR_IS_OK(result)) {
2534                 printf("Error rffpcnex %s\n", argv[1]);
2535                 goto done;
2536         }
2537
2538 done:           
2539         if (got_hnd)
2540                 rpccli_spoolss_close_printer(cli, mem_ctx, &hnd);
2541
2542         return result;
2543 }
2544
2545 /****************************************************************************
2546 ****************************************************************************/
2547
2548 static bool compare_printer( struct rpc_pipe_client *cli1, POLICY_HND *hnd1,
2549                              struct rpc_pipe_client *cli2, POLICY_HND *hnd2 )
2550 {
2551         PRINTER_INFO_CTR ctr1, ctr2;
2552         WERROR werror;
2553         TALLOC_CTX *mem_ctx = talloc_init("compare_printer");
2554
2555         printf("Retrieving printer propertiesfor %s...", cli1->cli->desthost);
2556         werror = rpccli_spoolss_getprinter( cli1, mem_ctx, hnd1, 2, &ctr1);
2557         if ( !W_ERROR_IS_OK(werror) ) {
2558                 printf("failed (%s)\n", dos_errstr(werror));
2559                 talloc_destroy(mem_ctx);
2560                 return False;
2561         }
2562         printf("ok\n");
2563
2564         printf("Retrieving printer properties for %s...", cli2->cli->desthost);
2565         werror = rpccli_spoolss_getprinter( cli2, mem_ctx, hnd2, 2, &ctr2);
2566         if ( !W_ERROR_IS_OK(werror) ) {
2567                 printf("failed (%s)\n", dos_errstr(werror));
2568                 talloc_destroy(mem_ctx);
2569                 return False;
2570         }
2571         printf("ok\n");
2572
2573         talloc_destroy(mem_ctx);
2574
2575         return True;
2576 }
2577
2578 /****************************************************************************
2579 ****************************************************************************/
2580
2581 static bool compare_printer_secdesc( struct rpc_pipe_client *cli1, POLICY_HND *hnd1,
2582                                      struct rpc_pipe_client *cli2, POLICY_HND *hnd2 )
2583 {
2584         PRINTER_INFO_CTR ctr1, ctr2;
2585         WERROR werror;
2586         TALLOC_CTX *mem_ctx = talloc_init("compare_printer_secdesc");
2587         SEC_DESC *sd1, *sd2;
2588         bool result = True;
2589
2590
2591         printf("Retreiving printer security for %s...", cli1->cli->desthost);
2592         werror = rpccli_spoolss_getprinter( cli1, mem_ctx, hnd1, 3, &ctr1);
2593         if ( !W_ERROR_IS_OK(werror) ) {
2594                 printf("failed (%s)\n", dos_errstr(werror));
2595                 result = False;
2596                 goto done;
2597         }
2598         printf("ok\n");
2599
2600         printf("Retrieving printer security for %s...", cli2->cli->desthost);
2601         werror = rpccli_spoolss_getprinter( cli2, mem_ctx, hnd2, 3, &ctr2);
2602         if ( !W_ERROR_IS_OK(werror) ) {
2603                 printf("failed (%s)\n", dos_errstr(werror));
2604                 result = False;
2605                 goto done;
2606         }
2607         printf("ok\n");
2608         
2609
2610         printf("++ ");
2611
2612         if ( (ctr1.printers_3 != ctr2.printers_3) && (!ctr1.printers_3 || !ctr2.printers_3) ) {
2613                 printf("NULL PRINTER_INFO_3!\n");
2614                 result = False;
2615                 goto done;
2616         }
2617         
2618         sd1 = ctr1.printers_3->secdesc;
2619         sd2 = ctr2.printers_3->secdesc;
2620         
2621         if ( (sd1 != sd2) && ( !sd1 || !sd2 ) ) {
2622                 printf("NULL secdesc!\n");
2623                 result = False;
2624                 goto done;
2625         }
2626         
2627         if (!sec_desc_equal( sd1, sd2 ) ) {
2628                 printf("Security Descriptors *not* equal!\n");
2629                 result = False;
2630                 goto done;
2631         }
2632         
2633         printf("Security descriptors match\n");
2634         
2635 done:
2636         talloc_destroy(mem_ctx);
2637         return result;
2638 }
2639
2640
2641 /****************************************************************************
2642 ****************************************************************************/
2643
2644 static WERROR cmd_spoolss_printercmp(struct rpc_pipe_client *cli, 
2645                                      TALLOC_CTX *mem_ctx, int argc, 
2646                                      const char **argv)
2647 {
2648         fstring printername, servername1, servername2;
2649         char *printername_path = NULL;
2650         struct cli_state *cli_server1 = cli->cli;
2651         struct cli_state *cli_server2 = NULL;
2652         struct rpc_pipe_client *cli2 = NULL;
2653         POLICY_HND hPrinter1, hPrinter2;
2654         NTSTATUS nt_status;
2655         WERROR werror;
2656
2657         if ( argc != 3 )  {
2658                 printf("Usage: %s <printer> <server>\n", argv[0]);
2659                 return WERR_OK;
2660         }
2661
2662         fstrcpy( printername, argv[1] );
2663
2664         fstr_sprintf( servername1, cli->cli->desthost );
2665         fstrcpy( servername2, argv[2] );
2666         strupper_m( servername1 );
2667         strupper_m( servername2 );
2668
2669         /* first get the connection to the remote server */
2670
2671         nt_status = cli_full_connection(&cli_server2, global_myname(), servername2, 
2672                                         NULL, 0,
2673                                         "IPC$", "IPC",
2674                                         get_cmdline_auth_info_username(),
2675                                         lp_workgroup(),
2676                                         get_cmdline_auth_info_password(),
2677                                         get_cmdline_auth_info_use_kerberos() ? CLI_FULL_CONNECTION_USE_KERBEROS : 0,
2678                                         get_cmdline_auth_info_signing_state(), NULL);
2679
2680         if ( !NT_STATUS_IS_OK(nt_status) )
2681                 return WERR_GENERAL_FAILURE;
2682
2683         cli2 = cli_rpc_pipe_open_noauth(cli_server2, PI_SPOOLSS, &nt_status);
2684         if (!cli2) {
2685                 printf("failed to open spoolss pipe on server %s (%s)\n",
2686                         servername2, nt_errstr(nt_status));
2687                 return WERR_GENERAL_FAILURE;
2688         }
2689
2690         /* now open up both printers */
2691
2692         printername_path = talloc_asprintf(mem_ctx,
2693                                 "\\\\%s\\%s",
2694                                 servername1,
2695                                 printername);
2696         if (!printername_path) {
2697                 return WERR_NOMEM;
2698         }
2699         printf("Opening %s...", printername_path);
2700         werror = rpccli_spoolss_open_printer_ex( cli, mem_ctx, printername_path, 
2701                 "", PRINTER_ALL_ACCESS, servername1, cli_server1->user_name, &hPrinter1);
2702         if ( !W_ERROR_IS_OK(werror) ) {
2703                 printf("failed (%s)\n", dos_errstr(werror));
2704                 goto done;
2705         }
2706         printf("ok\n");
2707
2708         printername_path = talloc_asprintf(mem_ctx,
2709                                         "\\\\%s\\%s",
2710                                         servername2,
2711                                         printername);
2712         if (!printername_path) {
2713                 return WERR_NOMEM;
2714         }
2715         printf("Opening %s...", printername_path);
2716         werror = rpccli_spoolss_open_printer_ex( cli2, mem_ctx, printername_path,  
2717                 "", PRINTER_ALL_ACCESS, servername2, cli_server2->user_name, &hPrinter2 );
2718         if ( !W_ERROR_IS_OK(werror) ) {
2719                  printf("failed (%s)\n", dos_errstr(werror));
2720                 goto done;
2721         }
2722         printf("ok\n");
2723
2724         compare_printer( cli, &hPrinter1, cli2, &hPrinter2 );
2725         compare_printer_secdesc( cli, &hPrinter1, cli2, &hPrinter2 );
2726 #if 0
2727         compare_printerdata( cli_server1, &hPrinter1, cli_server2, &hPrinter2 );
2728 #endif
2729
2730
2731 done:
2732         /* cleanup */
2733
2734         printf("Closing printers...");
2735         rpccli_spoolss_close_printer( cli, mem_ctx, &hPrinter1 );
2736         rpccli_spoolss_close_printer( cli2, mem_ctx, &hPrinter2 );
2737         printf("ok\n");
2738
2739         /* close the second remote connection */
2740
2741         cli_shutdown( cli_server2 );
2742         return WERR_OK;
2743 }
2744
2745 /* List of commands exported by this module */
2746 struct cmd_set spoolss_commands[] = {
2747
2748         { "SPOOLSS"  },
2749
2750         { "adddriver",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_addprinterdriver,   PI_SPOOLSS, NULL, "Add a print driver",                  "" },
2751         { "addprinter",         RPC_RTYPE_WERROR, NULL, cmd_spoolss_addprinterex,       PI_SPOOLSS, NULL, "Add a printer",                       "" },
2752         { "deldriver",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_deletedriver,       PI_SPOOLSS, NULL, "Delete a printer driver",             "" },
2753         { "deldriverex",        RPC_RTYPE_WERROR, NULL, cmd_spoolss_deletedriverex,     PI_SPOOLSS, NULL, "Delete a printer driver with files",  "" },
2754         { "enumdata",           RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_data,          PI_SPOOLSS, NULL, "Enumerate printer data",              "" },
2755         { "enumdataex",         RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_data_ex,       PI_SPOOLSS, NULL, "Enumerate printer data for a key",    "" },
2756         { "enumkey",            RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_printerkey,    PI_SPOOLSS, NULL, "Enumerate printer keys",              "" },
2757         { "enumjobs",           RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_jobs,          PI_SPOOLSS, NULL, "Enumerate print jobs",                "" },
2758         { "enumports",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_ports,         PI_SPOOLSS, NULL, "Enumerate printer ports",             "" },
2759         { "enumdrivers",        RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_drivers,       PI_SPOOLSS, NULL, "Enumerate installed printer drivers", "" },
2760         { "enumprinters",       RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_printers,      PI_SPOOLSS, NULL, "Enumerate printers",                  "" },
2761         { "getdata",            RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprinterdata,     PI_SPOOLSS, NULL, "Get print driver data",               "" },
2762         { "getdataex",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprinterdataex,   PI_SPOOLSS, NULL, "Get printer driver data with keyname", ""},
2763         { "getdriver",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_getdriver,          PI_SPOOLSS, NULL, "Get print driver information",        "" },
2764         { "getdriverdir",       RPC_RTYPE_WERROR, NULL, cmd_spoolss_getdriverdir,       PI_SPOOLSS, NULL, "Get print driver upload directory",   "" },
2765         { "getprinter",         RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprinter,         PI_SPOOLSS, NULL, "Get printer info",                    "" },
2766         { "openprinter",        RPC_RTYPE_WERROR, NULL, cmd_spoolss_open_printer_ex,    PI_SPOOLSS, NULL, "Open printer handle",                 "" },
2767         { "setdriver",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_setdriver,          PI_SPOOLSS, NULL, "Set printer driver",                  "" },
2768         { "getprintprocdir",    RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprintprocdir,    PI_SPOOLSS, NULL, "Get print processor directory",       "" },
2769         { "addform",            RPC_RTYPE_WERROR, NULL, cmd_spoolss_addform,            PI_SPOOLSS, NULL, "Add form",                            "" },
2770         { "setform",            RPC_RTYPE_WERROR, NULL, cmd_spoolss_setform,            PI_SPOOLSS, NULL, "Set form",                            "" },
2771         { "getform",            RPC_RTYPE_WERROR, NULL, cmd_spoolss_getform,            PI_SPOOLSS, NULL, "Get form",                            "" },
2772         { "deleteform",         RPC_RTYPE_WERROR, NULL, cmd_spoolss_deleteform,         PI_SPOOLSS, NULL, "Delete form",                         "" },
2773         { "enumforms",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_forms,         PI_SPOOLSS, NULL, "Enumerate forms",                     "" },
2774         { "setprinter",         RPC_RTYPE_WERROR, NULL, cmd_spoolss_setprinter,         PI_SPOOLSS, NULL, "Set printer comment",                 "" },
2775         { "setprintername",     RPC_RTYPE_WERROR, NULL, cmd_spoolss_setprintername,     PI_SPOOLSS, NULL, "Set printername",                 "" },
2776         { "setprinterdata",     RPC_RTYPE_WERROR, NULL, cmd_spoolss_setprinterdata,     PI_SPOOLSS, NULL, "Set REG_SZ printer data",             "" },
2777         { "rffpcnex",           RPC_RTYPE_WERROR, NULL, cmd_spoolss_rffpcnex,           PI_SPOOLSS, NULL, "Rffpcnex test", "" },
2778         { "printercmp",         RPC_RTYPE_WERROR, NULL, cmd_spoolss_printercmp,         PI_SPOOLSS, NULL, "Printer comparison test", "" },
2779
2780         { NULL }
2781 };