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