Another item off my long-term todo list:
[kai/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
317         if (argc > 2) 
318         {
319                 printf("Usage: %s [level]\n", argv[0]);
320                 return NT_STATUS_OK;
321         }
322
323         if (argc == 2) {
324                 info_level = atoi(argv[1]);
325         }
326
327         /* Enumerate printers  -- Should we enumerate types other 
328            than PRINTER_ENUM_LOCAL?  Maybe accept as a parameter?  --jerry */
329
330         ZERO_STRUCT(ctr);
331
332         result = cli_spoolss_enum_printers(
333                 cli, mem_ctx, 0, &needed, PRINTER_ENUM_LOCAL, 
334                 info_level, &num_printers, &ctr);
335
336         if (W_ERROR_V(result) == ERRinsufficientbuffer)
337                 result = cli_spoolss_enum_printers(
338                         cli, mem_ctx, needed, NULL, PRINTER_ENUM_LOCAL, 
339                         info_level, &num_printers, &ctr);
340
341         if (W_ERROR_IS_OK(result)) {
342
343                 if (!num_printers) {
344                         printf ("No printers returned.\n");
345                         goto done;
346                 }
347         
348                 for (i = 0; i < num_printers; i++) {
349                         switch(info_level) {
350                         case 0:
351                                 display_print_info_0(&ctr.printers_0[i]);
352                                 break;
353                         case 1:
354                                 display_print_info_1(&ctr.printers_1[i]);
355                                 break;
356                         case 2:
357                                 display_print_info_2(&ctr.printers_2[i]);
358                                 break;
359                         case 3:
360                                 display_print_info_3(&ctr.printers_3[i]);
361                                 break;
362                         default:
363                                 printf("unknown info level %d\n", info_level);
364                                 goto done;
365                         }
366                 }
367         }
368         done:
369
370         return W_ERROR_IS_OK(result) ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
371 }
372
373 /****************************************************************************
374 port info level 1 display function
375 ****************************************************************************/
376 static void display_port_info_1(PORT_INFO_1 *i1)
377 {
378         fstring buffer;
379         
380         rpcstr_pull(buffer, i1->port_name.buffer, sizeof(buffer), -1, STR_TERMINATE);
381         printf("\tPort Name:\t[%s]\n", buffer);
382 }
383
384 /****************************************************************************
385 port info level 2 display function
386 ****************************************************************************/
387 static void display_port_info_2(PORT_INFO_2 *i2)
388 {
389         fstring buffer;
390         
391         rpcstr_pull(buffer, i2->port_name.buffer, sizeof(buffer), -1, STR_TERMINATE);
392         printf("\tPort Name:\t[%s]\n", buffer);
393         rpcstr_pull(buffer, i2->monitor_name.buffer, sizeof(buffer), -1, STR_TERMINATE);
394
395         printf("\tMonitor Name:\t[%s]\n", buffer);
396         rpcstr_pull(buffer, i2->description.buffer, sizeof(buffer), -1, STR_TERMINATE);
397
398         printf("\tDescription:\t[%s]\n", buffer);
399         printf("\tPort Type:\t[%d]\n", i2->port_type);
400         printf("\tReserved:\t[%d]\n", i2->reserved);
401         printf("\n");
402 }
403
404 /* Enumerate ports */
405
406 static NTSTATUS cmd_spoolss_enum_ports(struct cli_state *cli, 
407                                        TALLOC_CTX *mem_ctx, int argc, 
408                                        char **argv)
409 {
410         WERROR                  result;
411         uint32                  needed, info_level = 1;
412         PORT_INFO_CTR           ctr;
413         int                     returned;
414         
415         if (argc > 2) {
416                 printf("Usage: %s [level]\n", argv[0]);
417                 return NT_STATUS_OK;
418         }
419         
420         if (argc == 2)
421                 info_level = atoi(argv[1]);
422
423         /* Enumerate ports */
424
425         ZERO_STRUCT(ctr);
426
427         result = cli_spoolss_enum_ports(cli, mem_ctx, 0, &needed, info_level, 
428                                         &returned, &ctr);
429
430         if (W_ERROR_V(result) == ERRinsufficientbuffer)
431                 result = cli_spoolss_enum_ports(cli, mem_ctx, needed, NULL,
432                                                 info_level, &returned, &ctr);
433
434         if (W_ERROR_IS_OK(result)) {
435                 int i;
436
437                 for (i = 0; i < returned; i++) {
438                         switch (info_level) {
439                         case 1:
440                                 display_port_info_1(&ctr.port.info_1[i]);
441                                 break;
442                         case 2:
443                                 display_port_info_2(&ctr.port.info_2[i]);
444                                 break;
445                         default:
446                                 printf("unknown info level %d\n", info_level);
447                                 break;
448                         }
449                 }
450         }
451         
452         return W_ERROR_IS_OK(result) ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
453 }
454
455 /***********************************************************************
456  * Set printer comment - use a level2 set.
457  */
458 static NTSTATUS cmd_spoolss_setprinter(struct cli_state *cli,
459                                        TALLOC_CTX *mem_ctx,
460                                        int argc, char **argv)
461 {
462         POLICY_HND      pol;
463         WERROR          result;
464         uint32          needed;
465         uint32          info_level = 2;
466         BOOL            opened_hnd = False;
467         PRINTER_INFO_CTR ctr;
468         fstring         printername,
469                         servername,
470                         user,
471                         comment;
472
473         if (argc == 1 || argc > 3) {
474                 printf("Usage: %s printername comment\n", argv[0]);
475
476                 return NT_STATUS_OK;
477         }
478
479         /* Open a printer handle */
480         if (argc == 3) {
481                 fstrcpy(comment, argv[2]);
482         }
483
484         slprintf (servername, sizeof(fstring)-1, "\\\\%s", cli->desthost);
485         strupper (servername);
486         fstrcpy (printername, argv[1]);
487         fstrcpy  (user, cli->user_name);
488
489         /* get a printer handle */
490         result = cli_spoolss_open_printer_ex(cli, mem_ctx, printername, "", 
491                                 MAXIMUM_ALLOWED_ACCESS, servername,
492                                 user, &pol);
493                                 
494         if (!W_ERROR_IS_OK(result))
495                 goto done;
496
497         opened_hnd = True;
498
499         /* Get printer info */
500         result = cli_spoolss_getprinter(cli, mem_ctx, 0, &needed, &pol, info_level, &ctr);
501
502         if (W_ERROR_V(result) == ERRinsufficientbuffer)
503                 result = cli_spoolss_getprinter(cli, mem_ctx, needed, NULL, &pol, info_level, &ctr);
504
505         if (!W_ERROR_IS_OK(result))
506                 goto done;
507
508
509         /* Modify the comment. */
510         init_unistr(&ctr.printers_2->comment, comment);
511         ctr.printers_2->devmode = NULL;
512         ctr.printers_2->secdesc = NULL;
513
514         result = cli_spoolss_setprinter(cli, mem_ctx, &pol, info_level, &ctr, 0);
515         if (W_ERROR_IS_OK(result))
516                 printf("Success in setting comment.\n");
517
518  done:
519         if (opened_hnd)
520                 cli_spoolss_close_printer(cli, mem_ctx, &pol);
521
522         return W_ERROR_IS_OK(result) ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
523 }
524
525 /***********************************************************************
526  * Get printer information
527  */
528 static NTSTATUS cmd_spoolss_getprinter(struct cli_state *cli,
529                                        TALLOC_CTX *mem_ctx,
530                                        int argc, char **argv)
531 {
532         POLICY_HND      pol;
533         WERROR          result;
534         uint32          info_level = 1;
535         BOOL            opened_hnd = False;
536         PRINTER_INFO_CTR ctr;
537         fstring         printername,
538                         servername,
539                         user;
540         uint32 needed;
541
542         if (argc == 1 || argc > 3) {
543                 printf("Usage: %s <printername> [level]\n", argv[0]);
544                 return NT_STATUS_OK;
545         }
546
547         /* Open a printer handle */
548         if (argc == 3) {
549                 info_level = atoi(argv[2]);
550         }
551
552         slprintf (servername, sizeof(fstring)-1, "\\\\%s", cli->desthost);
553         strupper (servername);
554         slprintf (printername, sizeof(fstring)-1, "%s\\%s", servername, argv[1]);
555         fstrcpy  (user, cli->user_name);
556         
557         /* get a printer handle */
558
559         result = cli_spoolss_open_printer_ex(cli, mem_ctx, printername, 
560                                              "", MAXIMUM_ALLOWED_ACCESS, 
561                                              servername, user, &pol);
562
563         if (!W_ERROR_IS_OK(result))
564                 goto done;
565  
566         opened_hnd = True;
567
568         /* Get printer info */
569
570         result = cli_spoolss_getprinter(cli, mem_ctx, 0, &needed,
571                                         &pol, info_level, &ctr);
572
573         if (W_ERROR_V(result) == ERRinsufficientbuffer)
574                 result = cli_spoolss_getprinter(
575                         cli, mem_ctx, needed, NULL, &pol, info_level, &ctr);
576
577         if (!W_ERROR_IS_OK(result))
578                 goto done;
579
580         /* Display printer info */
581
582         switch (info_level) {
583         case 0: 
584                 display_print_info_0(ctr.printers_0);
585                 break;
586         case 1:
587                 display_print_info_1(ctr.printers_1);
588                 break;
589         case 2:
590                 display_print_info_2(ctr.printers_2);
591                 break;
592         case 3:
593                 display_print_info_3(ctr.printers_3);
594                 break;
595         default:
596                 printf("unknown info level %d\n", info_level);
597                 break;
598         }
599
600  done: 
601         if (opened_hnd) 
602                 cli_spoolss_close_printer(cli, mem_ctx, &pol);
603
604         return W_ERROR_IS_OK(result) ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
605 }
606
607 /****************************************************************************
608 printer info level 0 display function
609 ****************************************************************************/
610 static void display_print_driver_1(DRIVER_INFO_1 *i1)
611 {
612         fstring name;
613         if (i1 == NULL)
614                 return;
615
616         rpcstr_pull(name, i1->name.buffer, sizeof(name), -1, STR_TERMINATE);
617
618         printf ("Printer Driver Info 1:\n");
619         printf ("\tDriver Name: [%s]\n\n", name);
620         
621         return;
622 }
623
624 /****************************************************************************
625 printer info level 1 display function
626 ****************************************************************************/
627 static void display_print_driver_2(DRIVER_INFO_2 *i1)
628 {
629         fstring name;
630         fstring architecture;
631         fstring driverpath;
632         fstring datafile;
633         fstring configfile;
634         if (i1 == NULL)
635                 return;
636
637         rpcstr_pull(name, i1->name.buffer, sizeof(name), -1, STR_TERMINATE);
638         rpcstr_pull(architecture, i1->architecture.buffer, sizeof(architecture), -1, STR_TERMINATE);
639         rpcstr_pull(driverpath, i1->driverpath.buffer, sizeof(driverpath), -1, STR_TERMINATE);
640         rpcstr_pull(datafile, i1->datafile.buffer, sizeof(datafile), -1, STR_TERMINATE);
641         rpcstr_pull(configfile, i1->configfile.buffer, sizeof(configfile), -1, STR_TERMINATE);
642
643         printf ("Printer Driver Info 2:\n");
644         printf ("\tVersion: [%x]\n", i1->version);
645         printf ("\tDriver Name: [%s]\n", name);
646         printf ("\tArchitecture: [%s]\n", architecture);
647         printf ("\tDriver Path: [%s]\n", driverpath);
648         printf ("\tDatafile: [%s]\n", datafile);
649         printf ("\tConfigfile: [%s]\n\n", configfile);
650
651         return;
652 }
653
654 /****************************************************************************
655 printer info level 2 display function
656 ****************************************************************************/
657 static void display_print_driver_3(DRIVER_INFO_3 *i1)
658 {
659         fstring name;
660         fstring architecture;
661         fstring driverpath;
662         fstring datafile;
663         fstring configfile;
664         fstring helpfile;
665         fstring dependentfiles;
666         fstring monitorname;
667         fstring defaultdatatype;
668         
669         int length=0;
670         BOOL valid = True;
671         
672         if (i1 == NULL)
673                 return;
674
675         rpcstr_pull(name, i1->name.buffer, sizeof(name), -1, STR_TERMINATE);
676         rpcstr_pull(architecture, i1->architecture.buffer, sizeof(architecture), -1, STR_TERMINATE);
677         rpcstr_pull(driverpath, i1->driverpath.buffer, sizeof(driverpath), -1, STR_TERMINATE);
678         rpcstr_pull(datafile, i1->datafile.buffer, sizeof(datafile), -1, STR_TERMINATE);
679         rpcstr_pull(configfile, i1->configfile.buffer, sizeof(configfile), -1, STR_TERMINATE);
680         rpcstr_pull(helpfile, i1->helpfile.buffer, sizeof(helpfile), -1, STR_TERMINATE);
681         rpcstr_pull(monitorname, i1->monitorname.buffer, sizeof(monitorname), -1, STR_TERMINATE);
682         rpcstr_pull(defaultdatatype, i1->defaultdatatype.buffer, sizeof(defaultdatatype), -1, STR_TERMINATE);
683
684         printf ("Printer Driver Info 3:\n");
685         printf ("\tVersion: [%x]\n", i1->version);
686         printf ("\tDriver Name: [%s]\n",name);
687         printf ("\tArchitecture: [%s]\n", architecture);
688         printf ("\tDriver Path: [%s]\n", driverpath);
689         printf ("\tDatafile: [%s]\n", datafile);
690         printf ("\tConfigfile: [%s]\n", configfile);
691         printf ("\tHelpfile: [%s]\n\n", helpfile);
692
693         while (valid)
694         {
695                 rpcstr_pull(dependentfiles, i1->dependentfiles+length, sizeof(dependentfiles), -1, STR_TERMINATE);
696                 
697                 length+=strlen(dependentfiles)+1;
698                 
699                 if (strlen(dependentfiles) > 0)
700                 {
701                         printf ("\tDependentfiles: [%s]\n", dependentfiles);
702                 }
703                 else
704                 {
705                         valid = False;
706                 }
707         }
708         
709         printf ("\n");
710
711         printf ("\tMonitorname: [%s]\n", monitorname);
712         printf ("\tDefaultdatatype: [%s]\n\n", defaultdatatype);
713
714         return; 
715 }
716
717 /***********************************************************************
718  * Get printer information
719  */
720 static NTSTATUS cmd_spoolss_getdriver(struct cli_state *cli, 
721                                       TALLOC_CTX *mem_ctx,
722                                       int argc, char **argv)
723 {
724         POLICY_HND      pol;
725         WERROR          werror;
726         NTSTATUS        result;
727         uint32          info_level = 3;
728         BOOL            opened_hnd = False;
729         PRINTER_DRIVER_CTR      ctr;
730         fstring         printername, 
731                         servername, 
732                         user;
733         uint32          i;
734
735         if ((argc == 1) || (argc > 3)) 
736         {
737                 printf("Usage: %s <printername> [level]\n", argv[0]);
738                 return NT_STATUS_OK;
739         }
740
741         /* get the arguments need to open the printer handle */
742         slprintf (servername, sizeof(fstring)-1, "\\\\%s", cli->desthost);
743         strupper (servername);
744         fstrcpy  (user, cli->user_name);
745         fstrcpy  (printername, argv[1]);
746         if (argc == 3)
747                 info_level = atoi(argv[2]);
748
749         /* Open a printer handle */
750
751         werror = cli_spoolss_open_printer_ex(cli, mem_ctx, printername, "", 
752                                              PRINTER_ACCESS_USE,
753                                              servername, user, &pol);
754
755         result = W_ERROR_IS_OK(werror) ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
756
757         if (!NT_STATUS_IS_OK(result)) {
758                 printf("Error opening printer handle for %s!\n", printername);
759                 return result;
760         }
761
762         opened_hnd = True;
763
764         /* loop through and print driver info level for each architecture */
765
766         for (i=0; archi_table[i].long_archi!=NULL; i++) {
767                 uint32 needed;
768
769                 werror = cli_spoolss_getprinterdriver(
770                         cli, mem_ctx, 0, &needed, &pol, info_level, 
771                         archi_table[i].long_archi, &ctr);
772
773                 if (W_ERROR_V(werror) == ERRinsufficientbuffer)
774                         werror = cli_spoolss_getprinterdriver(
775                                 cli, mem_ctx, needed, NULL, &pol, info_level, 
776                                 archi_table[i].long_archi, &ctr);
777
778                 if (!W_ERROR_IS_OK(werror))
779                         continue;
780                         
781                 printf ("\n[%s]\n", archi_table[i].long_archi);
782
783                 switch (info_level) {
784                 case 1:
785                         display_print_driver_1 (ctr.info1);
786                         break;
787                 case 2:
788                         display_print_driver_2 (ctr.info2);
789                         break;
790                 case 3:
791                         display_print_driver_3 (ctr.info3);
792                         break;
793                 default:
794                         printf("unknown info level %d\n", info_level);
795                         break;
796                 }
797         }
798         
799         /* Cleanup */
800
801         if (opened_hnd)
802                 cli_spoolss_close_printer (cli, mem_ctx, &pol);
803         
804         return W_ERROR_IS_OK(result) ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
805 }
806
807 /***********************************************************************
808  * Get printer information
809  */
810 static NTSTATUS cmd_spoolss_enum_drivers(struct cli_state *cli, 
811                                          TALLOC_CTX *mem_ctx,
812                                          int argc, char **argv)
813 {
814         WERROR werror;
815         uint32          info_level = 1;
816         PRINTER_DRIVER_CTR      ctr;
817         uint32          i, j,
818                         returned;
819
820         if (argc > 2) 
821         {
822                 printf("Usage: enumdrivers [level]\n");
823                 return NT_STATUS_OK;
824         }
825
826         if (argc == 2)
827                 info_level = atoi(argv[1]);
828
829
830         /* loop through and print driver info level for each architecture */
831         for (i=0; archi_table[i].long_archi!=NULL; i++) 
832         {
833                 uint32 needed;
834
835                 werror = cli_spoolss_enumprinterdrivers(
836                         cli, mem_ctx, 0, &needed, info_level, 
837                         archi_table[i].long_archi, &returned, &ctr);
838
839                 if (W_ERROR_V(werror) == ERRinsufficientbuffer)
840                         werror = cli_spoolss_enumprinterdrivers(
841                                 cli, mem_ctx, needed, NULL, info_level, 
842                                 archi_table[i].long_archi, &returned, &ctr);
843
844                 if (returned == 0)
845                         continue;
846                         
847                 if (!W_ERROR_IS_OK(werror)) {
848                         printf ("Error getting driver for environment [%s] - %d\n",
849                                 archi_table[i].long_archi, W_ERROR_V(werror));
850                         continue;
851                 }
852                 
853                 printf ("\n[%s]\n", archi_table[i].long_archi);
854                 switch (info_level) 
855                 {
856                         
857                 case 1:
858                         for (j=0; j < returned; j++) {
859                                 display_print_driver_1 (&(ctr.info1[j]));
860                         }
861                         break;
862                 case 2:
863                         for (j=0; j < returned; j++) {
864                                 display_print_driver_2 (&(ctr.info2[j]));
865                         }
866                         break;
867                 case 3:
868                         for (j=0; j < returned; j++) {
869                                 display_print_driver_3 (&(ctr.info3[j]));
870                         }
871                         break;
872                 default:
873                         printf("unknown info level %d\n", info_level);
874                         break;
875                 }
876         }
877         
878         return W_ERROR_IS_OK(werror) ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
879 }
880
881 /****************************************************************************
882 printer info level 1 display function
883 ****************************************************************************/
884 static void display_printdriverdir_1(DRIVER_DIRECTORY_1 *i1)
885 {
886         fstring name;
887         if (i1 == NULL)
888                 return;
889  
890         rpcstr_pull(name, i1->name.buffer, sizeof(name), -1, STR_TERMINATE);
891  
892         printf ("\tDirectory Name:[%s]\n", name);
893 }
894
895 /***********************************************************************
896  * Get printer driver directory information
897  */
898 static NTSTATUS cmd_spoolss_getdriverdir(struct cli_state *cli, 
899                                          TALLOC_CTX *mem_ctx,
900                                          int argc, char **argv)
901 {
902         WERROR result;
903         fstring                 env;
904         DRIVER_DIRECTORY_CTR    ctr;
905         uint32 needed;
906
907         if (argc > 2) {
908                 printf("Usage: %s [environment]\n", argv[0]);
909                 return NT_STATUS_OK;
910         }
911
912         /* Get the arguments need to open the printer handle */
913
914         if (argc == 2)
915                 fstrcpy (env, argv[1]);
916         else
917                 fstrcpy (env, "Windows NT x86");
918
919         /* Get the directory.  Only use Info level 1 */
920
921         result = cli_spoolss_getprinterdriverdir(
922                 cli, mem_ctx, 0, &needed, 1, env, &ctr);
923
924         if (W_ERROR_V(result) == ERRinsufficientbuffer)
925                 result = cli_spoolss_getprinterdriverdir(
926                         cli, mem_ctx, needed, NULL, 1, env, &ctr);
927
928         if (W_ERROR_IS_OK(result))
929                 display_printdriverdir_1(ctr.info1);
930
931         return W_ERROR_IS_OK(result) ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
932 }
933
934 /*******************************************************************************
935  set the version and environment fields of a DRIVER_INFO_3 struct
936  ******************************************************************************/
937 void set_drv_info_3_env (DRIVER_INFO_3 *info, const char *arch)
938 {
939
940         int i;
941         
942         for (i=0; archi_table[i].long_archi != NULL; i++) 
943         {
944                 if (strcmp(arch, archi_table[i].short_archi) == 0)
945                 {
946                         info->version = archi_table[i].version;
947                         init_unistr (&info->architecture, archi_table[i].long_archi);
948                         break;
949                 }
950         }
951         
952         if (archi_table[i].long_archi == NULL)
953         {
954                 DEBUG(0, ("set_drv_info_3_env: Unknown arch [%s]\n", arch));
955         }
956         
957         return;
958 }
959
960
961 /**************************************************************************
962  wrapper for strtok to get the next parameter from a delimited list.
963  Needed to handle the empty parameter string denoted by "NULL"
964  *************************************************************************/
965 static char* get_driver_3_param (char* str, char* delim, UNISTR* dest)
966 {
967         char    *ptr;
968
969         /* get the next token */
970         ptr = strtok(str, delim);
971
972         /* a string of 'NULL' is used to represent an empty
973            parameter because two consecutive delimiters
974            will not return an empty string.  See man strtok(3)
975            for details */
976         if (StrCaseCmp(ptr, "NULL") == 0)
977                 ptr = NULL;
978
979         if (dest != NULL)
980                 init_unistr(dest, ptr); 
981
982         return ptr;
983 }
984
985 /********************************************************************************
986  fill in the members of a DRIVER_INFO_3 struct using a character 
987  string in the form of
988          <Long Printer Name>:<Driver File Name>:<Data File Name>:\
989              <Config File Name>:<Help File Name>:<Language Monitor Name>:\
990              <Default Data Type>:<Comma Separated list of Files> 
991  *******************************************************************************/
992 static BOOL init_drv_info_3_members (
993         TALLOC_CTX *mem_ctx, 
994         DRIVER_INFO_3 *info, 
995         char *args
996 )
997 {
998         char    *str, *str2;
999         uint32  len, i;
1000         
1001         /* fill in the UNISTR fields */
1002         str = get_driver_3_param (args, ":", &info->name);
1003         str = get_driver_3_param (NULL, ":", &info->driverpath);
1004         str = get_driver_3_param (NULL, ":", &info->datafile);
1005         str = get_driver_3_param (NULL, ":", &info->configfile);
1006         str = get_driver_3_param (NULL, ":", &info->helpfile);
1007         str = get_driver_3_param (NULL, ":", &info->monitorname);
1008         str = get_driver_3_param (NULL, ":", &info->defaultdatatype);
1009
1010         /* <Comma Separated List of Dependent Files> */
1011         str2 = get_driver_3_param (NULL, ":", NULL); /* save the beginning of the string */
1012         str = str2;                     
1013
1014         /* begin to strip out each filename */
1015         str = strtok(str, ",");         
1016         len = 0;
1017         while (str != NULL)
1018         {
1019                 /* keep a cumlative count of the str lengths */
1020                 len += strlen(str)+1;
1021                 str = strtok(NULL, ",");
1022         }
1023
1024         /* allocate the space; add one extra slot for a terminating NULL.
1025            Each filename is NULL terminated and the end contains a double
1026            NULL */
1027         if ((info->dependentfiles=(uint16*)talloc(mem_ctx, (len+1)*sizeof(uint16))) == NULL)
1028         {
1029                 DEBUG(0,("init_drv_info_3_members: Unable to malloc memory for dependenfiles\n"));
1030                 return False;
1031         }
1032         for (i=0; i<len; i++)
1033         {
1034                 info->dependentfiles[i] = SSVAL(&info->dependentfiles[i], 0, str2[i]);
1035         }
1036         info->dependentfiles[len] = '\0';
1037
1038         return True;
1039 }
1040
1041
1042 static NTSTATUS cmd_spoolss_addprinterdriver(struct cli_state *cli, 
1043                                              TALLOC_CTX *mem_ctx,
1044                                              int argc, char **argv)
1045 {
1046         WERROR result;
1047         uint32                  level = 3;
1048         PRINTER_DRIVER_CTR      ctr;
1049         DRIVER_INFO_3           info3;
1050         fstring                 arch;
1051         fstring                 driver_name;
1052
1053         /* parse the command arguements */
1054         if (argc != 3)
1055         {
1056                 printf ("Usage: %s <Environment>\\\n", argv[0]);
1057                 printf ("\t<Long Printer Name>:<Driver File Name>:<Data File Name>:\\\n");
1058                 printf ("\t<Config File Name>:<Help File Name>:<Language Monitor Name>:\\\n");
1059                 printf ("\t<Default Data Type>:<Comma Separated list of Files>\n");
1060
1061                 return NT_STATUS_OK;
1062         }
1063                 
1064         /* Fill in the DRIVER_INFO_3 struct */
1065         ZERO_STRUCT(info3);
1066         if (!get_short_archi(arch, argv[1]))
1067         {
1068                 printf ("Error Unknown architechture [%s]\n", argv[1]);
1069                 return NT_STATUS_INVALID_PARAMETER;
1070         }
1071         else
1072                 set_drv_info_3_env(&info3, arch);
1073
1074         if (!init_drv_info_3_members(mem_ctx, &info3, argv[2]))
1075         {
1076                 printf ("Error Invalid parameter list - %s.\n", argv[2]);
1077                 return NT_STATUS_INVALID_PARAMETER;
1078         }
1079
1080
1081         ctr.info3 = &info3;
1082         result = cli_spoolss_addprinterdriver (cli, mem_ctx, level, &ctr);
1083
1084         if (W_ERROR_IS_OK(result)) {
1085                 rpcstr_pull(driver_name, info3.name.buffer, 
1086                             sizeof(driver_name), -1, STR_TERMINATE);
1087                 printf ("Printer Driver %s successfully installed.\n",
1088                         driver_name);
1089         }
1090
1091         return W_ERROR_IS_OK(result) ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
1092 }
1093
1094
1095 static NTSTATUS cmd_spoolss_addprinterex(struct cli_state *cli, 
1096                                          TALLOC_CTX *mem_ctx,
1097                                          int argc, char **argv)
1098 {
1099         WERROR result;
1100         uint32                  level = 2;
1101         PRINTER_INFO_CTR        ctr;
1102         PRINTER_INFO_2          info2;
1103         fstring                 servername;
1104         
1105         /* parse the command arguements */
1106         if (argc != 5)
1107         {
1108                 printf ("Usage: %s <name> <shared name> <driver> <port>\n", argv[0]);
1109                 return NT_STATUS_OK;
1110         }
1111         
1112         slprintf (servername, sizeof(fstring)-1, "\\\\%s", cli->desthost);
1113         strupper (servername);
1114
1115         /* Fill in the DRIVER_INFO_3 struct */
1116         ZERO_STRUCT(info2);
1117 #if 0   /* JERRY */
1118         init_unistr( &info2.servername,         servername);
1119 #endif
1120         init_unistr( &info2.printername,        argv[1]);
1121         init_unistr( &info2.sharename,          argv[2]);
1122         init_unistr( &info2.drivername,         argv[3]);
1123         init_unistr( &info2.portname,           argv[4]);
1124         init_unistr( &info2.comment,            "Created by rpcclient");
1125         init_unistr( &info2.printprocessor,     "winprint");
1126         init_unistr( &info2.datatype,           "RAW");
1127         info2.devmode =         NULL;
1128         info2.secdesc =         NULL;
1129         info2.attributes        = PRINTER_ATTRIBUTE_SHARED;
1130         info2.priority          = 0;
1131         info2.defaultpriority   = 0;
1132         info2.starttime         = 0;
1133         info2.untiltime         = 0;
1134         
1135         /* These three fields must not be used by AddPrinter() 
1136            as defined in the MS Platform SDK documentation..  
1137            --jerry
1138         info2.status            = 0;
1139         info2.cjobs             = 0;
1140         info2.averageppm        = 0;
1141         */
1142
1143         ctr.printers_2 = &info2;
1144         result = cli_spoolss_addprinterex (cli, mem_ctx, level, &ctr);
1145
1146         if (W_ERROR_IS_OK(result))
1147                 printf ("Printer %s successfully installed.\n", argv[1]);
1148
1149         return W_ERROR_IS_OK(result) ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
1150 }
1151
1152 static NTSTATUS cmd_spoolss_setdriver(struct cli_state *cli, 
1153                                       TALLOC_CTX *mem_ctx,
1154                                       int argc, char **argv)
1155 {
1156         POLICY_HND              pol;
1157         WERROR                  result;
1158         uint32                  level = 2;
1159         BOOL                    opened_hnd = False;
1160         PRINTER_INFO_CTR        ctr;
1161         PRINTER_INFO_2          info2;
1162         fstring                 servername,
1163                                 printername,
1164                                 user;
1165         uint32 needed;
1166         
1167         /* parse the command arguements */
1168         if (argc != 3)
1169         {
1170                 printf ("Usage: %s <printer> <driver>\n", argv[0]);
1171                 return NT_STATUS_OK;
1172         }
1173
1174         slprintf (servername, sizeof(fstring)-1, "\\\\%s", cli->desthost);
1175         strupper (servername);
1176         slprintf (printername, sizeof(fstring)-1, "%s\\%s", servername, argv[1]);
1177         fstrcpy  (user, cli->user_name);
1178
1179         /* Get a printer handle */
1180
1181         result = cli_spoolss_open_printer_ex(cli, mem_ctx, printername, "", 
1182                                              MAXIMUM_ALLOWED_ACCESS,
1183                                              servername, user, &pol);
1184
1185         if (!W_ERROR_IS_OK(result))
1186                 goto done;
1187
1188         opened_hnd = True;
1189
1190         /* Get printer info */
1191
1192         ZERO_STRUCT (info2);
1193         ctr.printers_2 = &info2;
1194
1195         result = cli_spoolss_getprinter(cli, mem_ctx, 0, &needed,
1196                                         &pol, level, &ctr);
1197
1198         if (W_ERROR_V(result) == ERRinsufficientbuffer)
1199                 result = cli_spoolss_getprinter(
1200                         cli, mem_ctx, needed, NULL, &pol, level, &ctr);
1201
1202         if (!W_ERROR_IS_OK(result)) {
1203                 printf ("Unable to retrieve printer information!\n");
1204                 goto done;
1205         }
1206
1207         /* Set the printer driver */
1208
1209         init_unistr(&ctr.printers_2->drivername, argv[2]);
1210
1211         result = cli_spoolss_setprinter(cli, mem_ctx, &pol, level, &ctr, 0);
1212
1213         if (!W_ERROR_IS_OK(result)) {
1214                 printf("SetPrinter call failed!\n");
1215                 goto done;;
1216         }
1217
1218         printf("Succesfully set %s to driver %s.\n", argv[1], argv[2]);
1219
1220 done:
1221         /* Cleanup */
1222
1223         if (opened_hnd)
1224                 cli_spoolss_close_printer(cli, mem_ctx, &pol);
1225
1226         return W_ERROR_IS_OK(result) ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
1227 }
1228
1229
1230 static NTSTATUS cmd_spoolss_deletedriver(struct cli_state *cli, 
1231                                          TALLOC_CTX *mem_ctx,
1232                                          int argc, char **argv)
1233 {
1234         WERROR result;
1235         fstring                 servername;
1236         int                     i;
1237         
1238         /* parse the command arguements */
1239         if (argc != 2)
1240         {
1241                 printf ("Usage: %s <driver>\n", argv[0]);
1242                 return NT_STATUS_OK;
1243         }
1244
1245         slprintf (servername, sizeof(fstring)-1, "\\\\%s", cli->desthost);
1246         strupper (servername);
1247
1248         /* delete the driver for all architectures */
1249         for (i=0; archi_table[i].long_archi; i++)
1250         {
1251                 /* make the call to remove the driver */
1252                 result = cli_spoolss_deleteprinterdriver(
1253                         cli, mem_ctx, archi_table[i].long_archi, argv[1]);
1254
1255                 if (!W_ERROR_IS_OK(result)) {
1256                         printf ("Failed to remove driver %s for arch [%s] - error 0x%x!\n", 
1257                                 argv[1], archi_table[i].long_archi, 
1258                                 W_ERROR_V(result));
1259                 } else
1260                         printf ("Driver %s removed for arch [%s].\n", argv[1], 
1261                                 archi_table[i].long_archi);
1262         }
1263                 
1264         return W_ERROR_IS_OK(result) ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
1265 }
1266
1267 static NTSTATUS cmd_spoolss_getprintprocdir(struct cli_state *cli, 
1268                                             TALLOC_CTX *mem_ctx,
1269                                             int argc, char **argv)
1270 {
1271         WERROR result;
1272         char *servername = NULL, *environment = NULL;
1273         fstring procdir;
1274         uint32 needed;
1275         
1276         /* parse the command arguements */
1277         if (argc > 2) {
1278                 printf ("Usage: %s [environment]\n", argv[0]);
1279                 return NT_STATUS_OK;
1280         }
1281
1282         if (asprintf(&servername, "\\\\%s", cli->desthost) < 0)
1283                 return NT_STATUS_NO_MEMORY;
1284         strupper(servername);
1285
1286         if (asprintf(&environment, "%s", (argc == 2) ? argv[1] : 
1287                      PRINTER_DRIVER_ARCHITECTURE) < 0) {
1288                 SAFE_FREE(servername);
1289                 return NT_STATUS_NO_MEMORY;
1290         }
1291
1292         result = cli_spoolss_getprintprocessordirectory(
1293                 cli, mem_ctx, 0, &needed, servername, environment, procdir);
1294
1295         if (W_ERROR_V(result) == ERRinsufficientbuffer)
1296                 result = cli_spoolss_getprintprocessordirectory(
1297                         cli, mem_ctx, needed, NULL, servername, environment, 
1298                         procdir);
1299
1300         if (W_ERROR_IS_OK(result))
1301                 printf("%s\n", procdir);
1302
1303         SAFE_FREE(servername);
1304         SAFE_FREE(environment);
1305
1306         return W_ERROR_IS_OK(result) ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
1307 }
1308
1309 /* Add a form */
1310
1311 static NTSTATUS cmd_spoolss_addform(struct cli_state *cli, TALLOC_CTX *mem_ctx,
1312                                     int argc, char **argv)
1313 {
1314         POLICY_HND handle;
1315         WERROR werror;
1316         char *servername = NULL, *printername = NULL;
1317         FORM form;
1318         BOOL got_handle = False;
1319         
1320         /* Parse the command arguements */
1321
1322         if (argc != 3) {
1323                 printf ("Usage: %s <printer> <formname>\n", argv[0]);
1324                 return NT_STATUS_OK;
1325         }
1326         
1327         /* Get a printer handle */
1328
1329         asprintf(&servername, "\\\\%s", cli->desthost);
1330         strupper(servername);
1331         asprintf(&printername, "%s\\%s", servername, argv[1]);
1332
1333         werror = cli_spoolss_open_printer_ex(cli, mem_ctx, printername, "", 
1334                                              MAXIMUM_ALLOWED_ACCESS, 
1335                                              servername, cli->user_name, &handle);
1336
1337         if (!W_ERROR_IS_OK(werror))
1338                 goto done;
1339
1340         got_handle = True;
1341
1342         /* Dummy up some values for the form data */
1343
1344         form.flags = FORM_USER;
1345         form.size_x = form.size_y = 100;
1346         form.left = 0;
1347         form.top = 10;
1348         form.right = 20;
1349         form.bottom = 30;
1350
1351         init_unistr2(&form.name, argv[2], strlen(argv[2]) + 1);
1352
1353         /* Add the form */
1354
1355
1356         werror = cli_spoolss_addform(cli, mem_ctx, &handle, 1, &form);
1357
1358  done:
1359         if (got_handle)
1360                 cli_spoolss_close_printer(cli, mem_ctx, &handle);
1361
1362         SAFE_FREE(servername);
1363         SAFE_FREE(printername);
1364
1365         return W_ERROR_IS_OK(werror) ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
1366 }
1367
1368 /* Set a form */
1369
1370 static NTSTATUS cmd_spoolss_setform(struct cli_state *cli, TALLOC_CTX *mem_ctx,
1371                                     int argc, char **argv)
1372 {
1373         POLICY_HND handle;
1374         WERROR werror;
1375         char *servername = NULL, *printername = NULL;
1376         FORM form;
1377         BOOL got_handle = False;
1378         
1379         /* Parse the command arguements */
1380
1381         if (argc != 3) {
1382                 printf ("Usage: %s <printer> <formname>\n", argv[0]);
1383                 return NT_STATUS_OK;
1384         }
1385         
1386         /* Get a printer handle */
1387
1388         asprintf(&servername, "\\\\%s", cli->desthost);
1389         strupper(servername);
1390         asprintf(&printername, "%s\\%s", servername, argv[1]);
1391
1392         werror = cli_spoolss_open_printer_ex(
1393                 cli, mem_ctx, printername, "", MAXIMUM_ALLOWED_ACCESS, 
1394                 servername, cli->user_name, &handle);
1395
1396         if (!W_ERROR_IS_OK(werror))
1397                 goto done;
1398
1399         got_handle = True;
1400
1401         /* Dummy up some values for the form data */
1402
1403         form.flags = FORM_PRINTER;
1404         form.size_x = form.size_y = 100;
1405         form.left = 0;
1406         form.top = 1000;
1407         form.right = 2000;
1408         form.bottom = 3000;
1409
1410         init_unistr2(&form.name, argv[2], strlen(argv[2]) + 1);
1411
1412         /* Set the form */
1413
1414         werror = cli_spoolss_setform(cli, mem_ctx, &handle, 1, argv[2], &form);
1415
1416  done:
1417         if (got_handle)
1418                 cli_spoolss_close_printer(cli, mem_ctx, &handle);
1419
1420         SAFE_FREE(servername);
1421         SAFE_FREE(printername);
1422
1423         return W_ERROR_IS_OK(werror) ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
1424 }
1425
1426 /* Get a form */
1427
1428 static NTSTATUS cmd_spoolss_getform(struct cli_state *cli, TALLOC_CTX *mem_ctx,
1429                                     int argc, char **argv)
1430 {
1431         POLICY_HND handle;
1432         WERROR werror;
1433         char *servername = NULL, *printername = NULL;
1434         FORM_1 form;
1435         BOOL got_handle = False;
1436         uint32 needed;
1437         
1438         /* Parse the command arguements */
1439
1440         if (argc != 3) {
1441                 printf ("Usage: %s <printer> <formname>\n", argv[0]);
1442                 return NT_STATUS_OK;
1443         }
1444         
1445         /* Get a printer handle */
1446
1447         asprintf(&servername, "\\\\%s", cli->desthost);
1448         strupper(servername);
1449         asprintf(&printername, "%s\\%s", servername, argv[1]);
1450
1451         werror = cli_spoolss_open_printer_ex(
1452                 cli, mem_ctx, printername, "", MAXIMUM_ALLOWED_ACCESS, 
1453                 servername, cli->user_name, &handle);
1454
1455         if (!W_ERROR_IS_OK(werror))
1456                 goto done;
1457
1458         got_handle = True;
1459
1460         /* Set the form */
1461
1462         werror = cli_spoolss_getform(cli, mem_ctx, 0, &needed,
1463                                      &handle, argv[2], 1, &form);
1464
1465         if (W_ERROR_V(werror) == ERRinsufficientbuffer)
1466                 werror = cli_spoolss_getform(cli, mem_ctx, needed, NULL,
1467                                              &handle, argv[2], 1, &form);
1468
1469         if (!W_ERROR_IS_OK(werror))
1470                 goto done;
1471
1472         printf("width: %d\n", form.width);
1473         printf("length: %d\n", form.length);
1474         printf("left: %d\n", form.left);
1475         printf("top: %d\n", form.top);
1476         printf("right: %d\n", form.right);
1477         printf("bottom: %d\n", form.bottom);
1478
1479  done:
1480         if (got_handle)
1481                 cli_spoolss_close_printer(cli, mem_ctx, &handle);
1482
1483         SAFE_FREE(servername);
1484         SAFE_FREE(printername);
1485
1486         return W_ERROR_IS_OK(werror) ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
1487 }
1488
1489 /* Delete a form */
1490
1491 static NTSTATUS cmd_spoolss_deleteform(struct cli_state *cli, 
1492                                        TALLOC_CTX *mem_ctx, int argc, 
1493                                        char **argv)
1494 {
1495         POLICY_HND handle;
1496         WERROR werror;
1497         char *servername = NULL, *printername = NULL;
1498         BOOL got_handle = False;
1499         
1500         /* Parse the command arguements */
1501
1502         if (argc != 3) {
1503                 printf ("Usage: %s <printer> <formname>\n", argv[0]);
1504                 return NT_STATUS_OK;
1505         }
1506         
1507         /* Get a printer handle */
1508
1509         asprintf(&servername, "\\\\%s", cli->desthost);
1510         strupper(servername);
1511         asprintf(&printername, "%s\\%s", servername, argv[1]);
1512
1513         werror = cli_spoolss_open_printer_ex(
1514                 cli, mem_ctx, printername, "", MAXIMUM_ALLOWED_ACCESS, 
1515                 servername, cli->user_name, &handle);
1516
1517         if (!W_ERROR_IS_OK(werror))
1518                 goto done;
1519
1520         got_handle = True;
1521
1522         /* Delete the form */
1523
1524         werror = cli_spoolss_deleteform(cli, mem_ctx, &handle, argv[2]);
1525
1526  done:
1527         if (got_handle)
1528                 cli_spoolss_close_printer(cli, mem_ctx, &handle);
1529
1530         SAFE_FREE(servername);
1531         SAFE_FREE(printername);
1532
1533         return W_ERROR_IS_OK(werror) ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
1534 }
1535
1536 /* Enumerate forms */
1537
1538 static NTSTATUS cmd_spoolss_enum_forms(struct cli_state *cli, 
1539                                        TALLOC_CTX *mem_ctx, int argc, 
1540                                        char **argv)
1541 {
1542         POLICY_HND handle;
1543         WERROR werror;
1544         char *servername = NULL, *printername = NULL;
1545         BOOL got_handle = False;
1546         uint32 needed, num_forms, level = 1, i;
1547         FORM_1 *forms;
1548         
1549         /* Parse the command arguements */
1550
1551         if (argc != 2) {
1552                 printf ("Usage: %s <printer>\n", argv[0]);
1553                 return NT_STATUS_OK;
1554         }
1555         
1556         /* Get a printer handle */
1557
1558         asprintf(&servername, "\\\\%s", cli->desthost);
1559         strupper(servername);
1560         asprintf(&printername, "%s\\%s", servername, argv[1]);
1561
1562         werror = cli_spoolss_open_printer_ex(
1563                 cli, mem_ctx, printername, "", MAXIMUM_ALLOWED_ACCESS, 
1564                 servername, cli->user_name, &handle);
1565
1566         if (!W_ERROR_IS_OK(werror))
1567                 goto done;
1568
1569         got_handle = True;
1570
1571         /* Enumerate forms */
1572
1573         werror = cli_spoolss_enumforms(
1574                 cli, mem_ctx, 0, &needed, &handle, level, &num_forms, &forms);
1575
1576         if (W_ERROR_V(werror) == ERRinsufficientbuffer)
1577                 werror = cli_spoolss_enumforms(
1578                         cli, mem_ctx, needed, NULL, &handle, level, 
1579                         &num_forms, &forms);
1580
1581         if (!W_ERROR_IS_OK(werror))
1582                 goto done;
1583
1584         /* Display output */
1585
1586         for (i = 0; i < num_forms; i++) {
1587                 fstring form_name;
1588
1589                 if (forms[i].name.buffer)
1590                         rpcstr_pull(form_name, forms[i].name.buffer,
1591                                     sizeof(form_name), -1, STR_TERMINATE);
1592
1593                 printf("%s\n", form_name);
1594         }
1595
1596  done:
1597         if (got_handle)
1598                 cli_spoolss_close_printer(cli, mem_ctx, &handle);
1599
1600         SAFE_FREE(servername);
1601         SAFE_FREE(printername);
1602
1603         return W_ERROR_IS_OK(werror) ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
1604 }
1605
1606 static NTSTATUS cmd_spoolss_setprinterdata(struct cli_state *cli,
1607                                             TALLOC_CTX *mem_ctx,
1608                                             int argc, char **argv)
1609 {
1610         WERROR result;
1611         uint32 needed;
1612         fstring servername, printername, user;
1613         POLICY_HND pol;
1614         BOOL opened_hnd = False;
1615         PRINTER_INFO_CTR ctr;
1616         PRINTER_INFO_0 *info = NULL;
1617
1618         /* parse the command arguements */
1619         if (argc != 4) {
1620                 printf ("Usage: %s <printer> <value> <data>\n", argv[0]);
1621                 return NT_STATUS_OK;
1622         }
1623
1624         slprintf (servername, sizeof(fstring)-1, "\\\\%s", cli->desthost);
1625         strupper (servername);
1626         slprintf (printername, sizeof(fstring)-1, "%s\\%s", servername, argv[1]);
1627         fstrcpy  (user, cli->user_name);
1628
1629         /* get a printer handle */
1630         result = cli_spoolss_open_printer_ex(cli, mem_ctx, printername, "",
1631                                              MAXIMUM_ALLOWED_ACCESS, servername, 
1632                                              user, &pol);
1633         if (!W_ERROR_IS_OK(result))
1634                 goto done;
1635
1636         opened_hnd = True;
1637
1638         result = cli_spoolss_getprinter(cli, mem_ctx, 0, &needed,
1639                                         &pol, 0, &ctr);
1640
1641         if (W_ERROR_V(result) == ERRinsufficientbuffer)
1642                 result = cli_spoolss_getprinter(cli, mem_ctx, needed, NULL, &pol, 0, &ctr);
1643
1644         if (!W_ERROR_IS_OK(result))
1645                 goto done;
1646                 
1647         printf("%s\n", timestring(True));
1648         printf("\tchange_id (before set)\t:[0x%x]\n", info->change_id);
1649
1650         /* Set the printer data */
1651         
1652         result = cli_spoolss_setprinterdata(
1653                 cli, mem_ctx, &pol, argv[2], REG_SZ, argv[3], 
1654                 strlen(argv[3]) + 1);
1655                 
1656         if (!W_ERROR_IS_OK(result)) {
1657                 printf ("Unable to set [%s=%s]!\n", argv[2], argv[3]);
1658                 goto done;
1659         }
1660         printf("\tSetPrinterData succeeded [%s: %s]\n", argv[2], argv[3]);
1661
1662         result = cli_spoolss_getprinter(cli, mem_ctx, 0, &needed, &pol, 0, &ctr);
1663
1664         if (W_ERROR_V(result) == ERRinsufficientbuffer)
1665                 result = cli_spoolss_getprinter(cli, mem_ctx, needed, NULL, &pol, 0, &ctr);
1666
1667         if (!W_ERROR_IS_OK(result))
1668                 goto done;
1669                 
1670         printf("%s\n", timestring(True));
1671         printf("\tchange_id (after set)\t:[0x%x]\n", info->change_id);
1672
1673 done:
1674         /* cleanup */
1675         if (opened_hnd)
1676                 cli_spoolss_close_printer(cli, mem_ctx, &pol);
1677
1678         return W_ERROR_IS_OK(result) ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
1679 }
1680
1681 static void display_job_info_1(JOB_INFO_1 *job)
1682 {
1683         fstring username = "", document = "", text_status = "";
1684
1685         if (job->username.buffer)
1686                 rpcstr_pull(username, job->username.buffer,
1687                            sizeof(username), -1, STR_TERMINATE);
1688
1689         if (job->document.buffer)
1690                 rpcstr_pull(document, job->document.buffer,
1691                            sizeof(document), -1, STR_TERMINATE);
1692
1693         if (job->text_status.buffer)
1694                 rpcstr_pull(text_status, job->text_status.buffer,
1695                            sizeof(text_status), -1, STR_TERMINATE);
1696
1697         printf("%d: jobid[%d]: %s %s %s %d/%d pages\n", job->position, job->jobid,
1698                username, document, text_status, job->pagesprinted,
1699                job->totalpages);
1700 }
1701
1702 static void display_job_info_2(JOB_INFO_2 *job)
1703 {
1704         fstring username = "", document = "", text_status = "";
1705
1706         if (job->username.buffer)
1707                 rpcstr_pull(username, job->username.buffer,
1708                            sizeof(username), -1, STR_TERMINATE);
1709
1710         if (job->document.buffer)
1711                 rpcstr_pull(document, job->document.buffer,
1712                            sizeof(document), -1, STR_TERMINATE);
1713
1714         if (job->text_status.buffer)
1715                 rpcstr_pull(text_status, job->text_status.buffer,
1716                            sizeof(text_status), -1, STR_TERMINATE);
1717
1718         printf("%d: jobid[%d]: %s %s %s %d/%d pages, %d bytes\n", job->position, job->jobid,
1719                username, document, text_status, job->pagesprinted,
1720                job->totalpages, job->size);
1721 }
1722
1723 /* Enumerate jobs */
1724
1725 static NTSTATUS cmd_spoolss_enum_jobs(struct cli_state *cli, 
1726                                       TALLOC_CTX *mem_ctx, int argc, 
1727                                       char **argv)
1728 {
1729         WERROR result;
1730         uint32 needed, level = 1, num_jobs, i;
1731         BOOL got_hnd = False;
1732         pstring printername;
1733         fstring servername, user;
1734         POLICY_HND hnd;
1735         JOB_INFO_CTR ctr;
1736         
1737         if (argc < 2 || argc > 3) {
1738                 printf("Usage: %s printername [level]\n", argv[0]);
1739                 return NT_STATUS_OK;
1740         }
1741         
1742         if (argc == 3)
1743                 level = atoi(argv[2]);
1744
1745         /* Open printer handle */
1746
1747         slprintf(servername, sizeof(fstring)-1, "\\\\%s", cli->desthost);
1748         strupper(servername);
1749         fstrcpy(user, cli->user_name);
1750         fstrcpy(printername, argv[1]);
1751         slprintf(printername, sizeof(pstring)-1, "\\\\%s\\", cli->desthost);
1752         strupper(printername);
1753         pstrcat(printername, argv[1]);
1754
1755         result = cli_spoolss_open_printer_ex(cli, mem_ctx, printername, 
1756                                              "", MAXIMUM_ALLOWED_ACCESS, 
1757                                              servername, user, &hnd);
1758
1759         if (!W_ERROR_IS_OK(result))
1760                 goto done;
1761  
1762         got_hnd = True;
1763
1764         /* Enumerate ports */
1765
1766         result = cli_spoolss_enumjobs(
1767                 cli, mem_ctx, 0, &needed, &hnd, level, 0, 1000,
1768                 &num_jobs, &ctr);
1769
1770         if (W_ERROR_V(result) == ERRinsufficientbuffer)
1771                 result = cli_spoolss_enumjobs(
1772                         cli, mem_ctx, needed, NULL, &hnd, level, 0,
1773                         1000, &num_jobs, &ctr);
1774
1775         if (!W_ERROR_IS_OK(result))
1776                 goto done;
1777
1778         for (i = 0; i < num_jobs; i++) {
1779                 switch(level) {
1780                 case 1:
1781                         display_job_info_1(ctr.job.job_info_1[i]);
1782                         break;
1783                 case 2:
1784                         display_job_info_2(ctr.job.job_info_2[i]);
1785                         break;
1786                 default:
1787                         d_printf("unknown info level %d\n", level);
1788                         break;
1789                 }
1790         }
1791         
1792 done:
1793         if (got_hnd)
1794                 cli_spoolss_close_printer(cli, mem_ctx, &hnd);
1795
1796         return W_ERROR_IS_OK(result) ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
1797 }
1798
1799 /* List of commands exported by this module */
1800 struct cmd_set spoolss_commands[] = {
1801
1802         { "SPOOLSS"  },
1803
1804         { "adddriver",          cmd_spoolss_addprinterdriver,   PIPE_SPOOLSS, "Add a print driver",                  "" },
1805         { "addprinter",         cmd_spoolss_addprinterex,       PIPE_SPOOLSS, "Add a printer",                       "" },
1806         { "deldriver",          cmd_spoolss_deletedriver,       PIPE_SPOOLSS, "Delete a printer driver",             "" },
1807         { "enumdata",           cmd_spoolss_not_implemented,    PIPE_SPOOLSS, "Enumerate printer data (*)",          "" },
1808         { "enumjobs",           cmd_spoolss_enum_jobs,          PIPE_SPOOLSS, "Enumerate print jobs",                "" },
1809         { "enumports",          cmd_spoolss_enum_ports,         PIPE_SPOOLSS, "Enumerate printer ports",             "" },
1810         { "enumdrivers",        cmd_spoolss_enum_drivers,       PIPE_SPOOLSS, "Enumerate installed printer drivers", "" },
1811         { "enumprinters",       cmd_spoolss_enum_printers,      PIPE_SPOOLSS, "Enumerate printers",                  "" },
1812         { "getdata",            cmd_spoolss_not_implemented,    PIPE_SPOOLSS, "Get print driver data (*)",           "" },
1813         { "getdriver",          cmd_spoolss_getdriver,          PIPE_SPOOLSS, "Get print driver information",        "" },
1814         { "getdriverdir",       cmd_spoolss_getdriverdir,       PIPE_SPOOLSS, "Get print driver upload directory",   "" },
1815         { "getprinter",         cmd_spoolss_getprinter,         PIPE_SPOOLSS, "Get printer info",                    "" },
1816         { "getprintprocdir",    cmd_spoolss_getprintprocdir,    PIPE_SPOOLSS, "Get print processor directory",       "" },
1817         { "openprinter",        cmd_spoolss_open_printer_ex,    PIPE_SPOOLSS, "Open printer handle",                 "" },
1818         { "setdriver",          cmd_spoolss_setdriver,          PIPE_SPOOLSS, "Set printer driver",                  "" },
1819         { "getprintprocdir",    cmd_spoolss_getprintprocdir,    PIPE_SPOOLSS, "Get print processor directory",       "" },
1820         { "addform",            cmd_spoolss_addform,            PIPE_SPOOLSS, "Add form",                            "" },
1821         { "setform",            cmd_spoolss_setform,            PIPE_SPOOLSS, "Set form",                            "" },
1822         { "getform",            cmd_spoolss_getform,            PIPE_SPOOLSS, "Get form",                            "" },
1823         { "deleteform",         cmd_spoolss_deleteform,         PIPE_SPOOLSS, "Delete form",                         "" },
1824         { "enumforms",          cmd_spoolss_enum_forms,         PIPE_SPOOLSS, "Enumerate forms",                     "" },
1825         { "setprinter",         cmd_spoolss_setprinter,         PIPE_SPOOLSS, "Set printer comment",                 "" },
1826         { "setprinterdata",     cmd_spoolss_setprinterdata,     PIPE_SPOOLSS, "Set REG_SZ printer data",             "" },
1827
1828         { NULL }
1829 };