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