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