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