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