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