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