More work on AddPrinterDriver() and AddPrinterEx() client RPC's
[samba.git] / source / rpcclient / cmd_spoolss.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    NT Domain Authentication SMB / MSRPC client
5    Copyright (C) Andrew Tridgell              1994-2000
6    Copyright (C) Luke Kenneth Casson Leighton 1996-2000
7    Copyright (C) Jean-Francois Micouleau      1999-2000
8    Copyright (C) Gerald Carter                     2000
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 "nterr.h"
27 #include "rpc_parse.h"
28 #include "rpc_client.h"
29 #include "rpcclient.h"
30
31 extern int DEBUGLEVEL;
32
33 #define DEBUG_TESTING
34
35 extern FILE* out_hnd;
36
37 extern struct user_creds *usr_creds;
38
39 /****************************************************************************
40 function to do the mapping between the long architecture name and
41 the short one.
42 ****************************************************************************/
43 static BOOL get_short_archi(char *short_archi, char *long_archi)
44 {
45         struct table {
46                 char *long_archi;
47                 char *short_archi;
48         };
49
50         struct table archi_table[]=
51         {
52                 {"Windows 4.0",          "WIN40"    },
53                 {"Windows NT x86",       "W32X86"   },
54                 {"Windows NT R4000",     "W32MIPS"  },
55                 {"Windows NT Alpha_AXP", "W32ALPHA" },
56                 {"Windows NT PowerPC",   "W32PPC"   },
57                 {NULL,                   ""         }
58         };
59
60         int i=-1;
61
62         DEBUG(107,("Getting architecture dependant directory\n"));
63         do {
64                 i++;
65         } while ( (archi_table[i].long_archi!=NULL ) &&
66                   StrCaseCmp(long_archi, archi_table[i].long_archi) );
67
68         if (archi_table[i].long_archi==NULL) {
69                 DEBUGADD(107,("Unknown architecture [%s] !\n", long_archi));
70                 return FALSE;
71         }
72
73         StrnCpy (short_archi, archi_table[i].short_archi, strlen(archi_table[i].short_archi));
74
75         DEBUGADD(108,("index: [%d]\n", i));
76         DEBUGADD(108,("long architecture: [%s]\n", long_archi));
77         DEBUGADD(108,("short architecture: [%s]\n", short_archi));
78
79         return TRUE;
80 }
81
82 /****************************************************************************
83 nt spoolss query
84 ****************************************************************************/
85 uint32 cmd_spoolss_enum_printers(struct client_info *info, int argc, char *argv[])
86 {
87         PRINTER_INFO_CTR ctr;
88         
89         uint32 flags;
90         uint32 level = 1;
91
92         fstring srv_name;
93         fstrcpy(srv_name, "\\\\");
94         fstrcat(srv_name, info->dest_host);
95         strupper(srv_name);
96         
97         flags=PRINTER_ENUM_LOCAL;
98
99         if (msrpc_spoolss_enum_printers(srv_name, flags, level, ctr))
100                 DEBUG(5,("cmd_spoolss_enum_printer: query succeeded\n"));
101         else
102                 report(out_hnd, "FAILED\n");
103                 
104         flags=PRINTER_ENUM_NAME;
105
106         if (msrpc_spoolss_enum_printers(srv_name, flags, level, ctr))
107                 DEBUG(5,("cmd_spoolss_enum_printer: query succeeded\n"));
108         else
109                 report(out_hnd, "FAILED\n");
110
111         flags=PRINTER_ENUM_SHARED|PRINTER_ENUM_NAME;
112
113         if (msrpc_spoolss_enum_printers(srv_name, flags, level, ctr))
114                 DEBUG(5,("cmd_spoolss_enum_printer: query succeeded\n"));
115         else
116                 report(out_hnd, "FAILED\n");
117                 
118         flags=PRINTER_ENUM_CONNECTIONS;
119
120         if (msrpc_spoolss_enum_printers(srv_name, flags, level, ctr))
121                 DEBUG(5,("cmd_spoolss_enum_printer: query succeeded\n"));
122         else
123                 report(out_hnd, "FAILED\n");
124                 
125         flags=PRINTER_ENUM_NETWORK;
126
127         if (msrpc_spoolss_enum_printers(srv_name, flags, level, ctr))
128                 DEBUG(5,("cmd_spoolss_enum_printer: query succeeded\n"));
129         else
130                 report(out_hnd, "FAILED\n");
131                 
132         flags=PRINTER_ENUM_REMOTE;
133
134         if (msrpc_spoolss_enum_printers(srv_name, flags, level, ctr))
135                 DEBUG(5,("cmd_spoolss_enum_printer: query succeeded\n"));
136         else
137                 report(out_hnd, "FAILED\n");
138                 
139         return NT_STATUS_NOPROBLEMO;
140 }
141
142 /****************************************************************************
143 nt spoolss query
144 ****************************************************************************/
145 uint32 cmd_spoolss_enum_ports(struct client_info *info, int argc, char *argv[])
146 {
147         PORT_INFO_CTR ctr;
148         uint32 level;
149         fstring srv_name;
150         
151         if (argc < 1)
152         {
153                 report (out_hnd, "spoolenumports <level>\n");
154                 return NT_STATUS_INVALID_PARAMETER;
155         }
156
157                 
158         fstrcpy(srv_name, "\\\\");
159         fstrcat(srv_name, info->dest_host);
160         strupper(srv_name);
161         
162         level = atoi(argv[1]);
163         
164         if (msrpc_spoolss_enum_ports(srv_name, level, &ctr))
165                 DEBUG(5,("cmd_spoolss_enum_printer: query succeeded\n"));
166         else
167                 report(out_hnd, "FAILED\n");
168                 
169         return NT_STATUS_NOPROBLEMO;
170 }
171
172 /****************************************************************************
173 nt spoolss query
174 ****************************************************************************/
175 uint32 cmd_spoolss_enum_printerdata(struct client_info *info, int argc, char *argv[])
176 {
177         fstring srv_name;
178         fstring station;
179         char *printer_name;
180
181         if (argc < 1) {
182                 report(out_hnd, "spoolenumdata <printer name>\n");
183                 return NT_STATUS_INVALID_PARAMETER;
184         }
185
186         printer_name = argv[1];
187
188         fstrcpy(station, "\\\\");
189         fstrcat(station, info->myhostname);
190         strupper(station);
191
192         fstrcpy(srv_name, "\\\\");
193         fstrcat(srv_name, info->dest_host);
194         strupper(srv_name);
195
196         if (!strnequal("\\\\", printer_name, 2))
197         {
198                 fstrcat(srv_name, "\\");
199                 fstrcat(srv_name, printer_name);
200                 printer_name = srv_name;
201         }
202
203         DEBUG(0,("spoolenumdata - printer: %s station: %s user: %s\n", printer_name, station, usr_creds->ntc.user_name));
204
205         if (msrpc_spoolss_enum_printerdata( printer_name, station,
206                                 usr_creds->ntc.user_name))
207         {
208                 DEBUG(0,("cmd_spoolss_enum_printerdata: query succeeded\n"));
209                 return NT_STATUS_NOPROBLEMO;
210         }
211         report(out_hnd, "FAILED\n");
212         return NT_STATUS_UNSUCCESSFUL;
213 }
214
215 /****************************************************************************
216 nt spoolss query
217 ****************************************************************************/
218 uint32 cmd_spoolss_getprinter(struct client_info *info, int argc, char *argv[])
219 {
220         PRINTER_INFO_CTR ctr;
221         fstring srv_name;
222         fstring station;
223         char *printer_name;
224         uint32 level;
225
226         if (argc < 1) {
227                 report(out_hnd, "spoolgetprinter <printer name>\n");
228                 return NT_STATUS_INVALID_PARAMETER;
229         }
230
231         printer_name = argv[1];
232
233         fstrcpy(station, "\\\\");
234         fstrcat(station, info->myhostname);
235         strupper(station);
236
237         fstrcpy(srv_name, "\\\\");
238         fstrcat(srv_name, info->dest_host);
239         strupper(srv_name);
240
241         if (!strnequal("\\\\", printer_name, 2))
242         {
243                 fstrcat(srv_name, "\\");
244                 fstrcat(srv_name, printer_name);
245                 printer_name = srv_name;
246         }
247
248         if (argc < 3)
249                 level=2;
250         else
251                 level = atoi(argv[2]);
252
253         if (msrpc_spoolss_getprinter(printer_name, level, station, "Administrator", ctr))
254                 DEBUG(5,("cmd_spoolss_getprinter: query succeeded\n"));
255         else
256                 report(out_hnd, "FAILED\n");
257
258         return NT_STATUS_NOPROBLEMO;
259 }
260
261
262 static void display_spool_job_info_ctr( const char* printer_name,
263                                 const char* station,
264                                 uint32 level,
265                                 uint32 num, void *const *const ctr)
266 {
267         display_job_info_ctr(out_hnd, ACTION_HEADER   , level, num, ctr);
268         display_job_info_ctr(out_hnd, ACTION_ENUMERATE, level, num, ctr);
269         display_job_info_ctr(out_hnd, ACTION_FOOTER   , level, num, ctr);
270 }
271
272 /****************************************************************************
273 nt spoolss query
274 ****************************************************************************/
275 uint32 cmd_spoolss_enum_jobs(struct client_info *info, int argc, char *argv[])
276 {
277         fstring srv_name;
278         fstring station;
279         char *printer_name;
280
281         void **ctr = NULL;
282         uint32 level = 1;
283
284         if (argc < 1) {
285                 report(out_hnd, "spooljobs <printer name>\n");
286                 return NT_STATUS_INVALID_PARAMETER;
287         }
288
289         printer_name = argv[1];
290
291         fstrcpy(station, "\\\\");
292         fstrcat(station, info->myhostname);
293         strupper(station);
294
295         fstrcpy(srv_name, "\\\\");
296         fstrcat(srv_name, info->dest_host);
297         strupper(srv_name);
298
299         if (!strnequal("\\\\", printer_name, 2))
300         {
301                 fstrcat(srv_name, "\\");
302                 fstrcat(srv_name, printer_name);
303                 printer_name = srv_name;
304         }
305
306         DEBUG(4,("spoolopen - printer: %s station: %s user: %s\n", printer_name, 
307                   station, usr_creds->ntc.user_name));
308
309         if (msrpc_spoolss_enum_jobs( printer_name, station,
310                                 usr_creds->ntc.user_name,
311                                 level, &ctr, display_spool_job_info_ctr))
312         {
313                 DEBUG(5,("cmd_spoolss_enum_jobs: query succeeded\n"));
314                 return NT_STATUS_NOPROBLEMO;
315         }
316         report(out_hnd, "FAILED\n");
317         return NT_STATUS_UNSUCCESSFUL;
318 }
319
320 /****************************************************************************
321 nt spoolss query
322 ****************************************************************************/
323 uint32 cmd_spoolss_open_printer_ex(struct client_info *info, int argc, char *argv[])
324 {
325         fstring srv_name;
326         fstring station;
327         char *printer_name;
328         POLICY_HND hnd;
329
330         BOOL res = True;
331
332         if (argc < 1)
333         {
334                 report(out_hnd, "spoolopen <printer name>\n");
335                 return NT_STATUS_INVALID_PARAMETER;
336         }
337
338         printer_name = argv[1];
339
340         fstrcpy(station, "\\\\");
341         fstrcat(station, info->myhostname);
342         strupper(station);
343
344         fstrcpy(srv_name, "\\\\");
345         fstrcat(srv_name, info->dest_host);
346         strupper(srv_name);
347
348         if (!strnequal("\\\\", printer_name, 2))
349         {
350                 fstrcat(srv_name, "\\");
351                 fstrcat(srv_name, printer_name);
352                 printer_name = srv_name;
353         }
354
355         DEBUG(4,("spoolopen - printer: %s server: %s user: %s\n",
356                 printer_name, station, usr_creds->ntc.user_name));
357
358         res = res ? spoolss_open_printer_ex( printer_name, "", PRINTER_ALL_ACCESS,
359                                 station, "Administrator", &hnd) : False;
360
361         res = res ? spoolss_closeprinter(&hnd) : False;
362
363         if (res)
364         {
365                 DEBUG(5,("cmd_spoolss_open_printer_ex: query succeeded\n"));
366                 report(out_hnd, "OK\n");
367                 return NT_STATUS_NOPROBLEMO;
368         }
369         DEBUG(5,("cmd_spoolss_open_printer_ex: query failed\n"));
370         return NT_STATUS_UNSUCCESSFUL;
371 }
372
373 /****************************************************************************
374 nt spoolss query
375 ****************************************************************************/
376 uint32 cmd_spoolss_getprinterdata(struct client_info *info, int argc, char *argv[])
377 {
378         fstring srv_name;
379         fstring station;
380         char *printer_name;
381         char *value_name;
382
383         NEW_BUFFER ctr;
384         uint32 status;
385         uint32 type = 1;
386
387         if (argc < 2) {
388                 report(out_hnd, "spoolgetdata <printer name> <value name>\n");
389                 return NT_STATUS_INVALID_PARAMETER;
390         }
391
392         printer_name = argv[1];
393         value_name = argv[2];
394
395         fstrcpy(station, "\\\\");
396         fstrcat(station, info->myhostname);
397         strupper(station);
398
399         fstrcpy(srv_name, "\\\\");
400         fstrcat(srv_name, info->dest_host);
401         strupper(srv_name);
402
403         if (!strnequal("\\\\", printer_name, 2))
404         {
405                 fstrcat(srv_name, "\\");
406                 fstrcat(srv_name, printer_name);
407                 printer_name = srv_name;
408         }
409
410         DEBUG(4,("spoolgetdata - printer: %s station: %s value: %s\n",
411                                 printer_name, station, value_name));
412
413         status = msrpc_spoolss_getprinterdata( printer_name, station,
414                                 /* "Administrateur", */
415                                 usr_creds->ntc.user_name,
416                                 value_name, &type,
417                                 &ctr, NULL);
418
419         if (status == NT_STATUS_NOPROBLEMO)
420         {
421                 DEBUG(5,("cmd_spoolss_getprinterdata: query succeeded\n"));
422         }
423         else
424         {
425                 report(out_hnd, "FAILED\n");
426         }
427
428         return status;
429 }
430
431 /****************************************************************************
432 nt spoolss query
433 ****************************************************************************/
434 uint32 cmd_spoolss_getprinterdriver(struct client_info *info, int argc, char *argv[])
435 {
436         PRINTER_DRIVER_CTR ctr;
437         fstring srv_name;
438         fstring station;
439         char *printer_name;
440         fstring environment;
441         uint32 level;
442
443         if (argc < 1) {
444                 report(out_hnd, "spoolgetprinterdriver <printer name>\n");
445                 return NT_STATUS_INVALID_PARAMETER;
446         }
447
448         printer_name = argv[1];
449
450         fstrcpy(station, "\\\\");
451         fstrcat(station, info->myhostname);
452         strupper(station);
453
454         fstrcpy(srv_name, "\\\\");
455         fstrcat(srv_name, info->dest_host);
456         strupper(srv_name);
457
458         if (!strnequal("\\\\", printer_name, 2))
459         {
460                 fstrcat(srv_name, "\\");
461                 fstrcat(srv_name, printer_name);
462                 printer_name = srv_name;
463         }
464
465         fstrcpy(environment, "Windows NT x86");
466         level=3;
467
468         if (msrpc_spoolss_getprinterdriver(printer_name, environment, level, station, "Administrator", ctr))
469                 DEBUG(5,("cmd_spoolss_getprinterdriver: query succeeded\n"));
470         else
471                 report(out_hnd, "FAILED\n");
472
473         return NT_STATUS_NOPROBLEMO;
474 }
475
476 /****************************************************************************
477 nt spoolss query
478 ****************************************************************************/
479 uint32 cmd_spoolss_enumprinterdrivers(struct client_info *info, int argc, char *argv[])
480 {
481         PRINTER_DRIVER_CTR ctr;
482         fstring srv_name;
483         fstring environment;
484         uint32 level;
485
486         fstrcpy(srv_name, "\\\\");
487         fstrcat(srv_name, info->dest_host);
488         strupper(srv_name);
489
490         fstrcpy(environment, "Windows NT x86");
491         level=3;
492
493         if (msrpc_spoolss_enumprinterdrivers(srv_name, environment, level, ctr))
494                 DEBUG(5,("cmd_spoolss_enumprinterdrivers: query succeeded\n"));
495         else
496                 report(out_hnd, "FAILED\n");
497
498         return NT_STATUS_NOPROBLEMO;
499 }
500
501 /****************************************************************************
502 nt spoolss query
503 ****************************************************************************/
504 uint32 cmd_spoolss_getprinterdriverdir(struct client_info *info, int argc, char *argv[])
505 {
506         DRIVER_DIRECTORY_CTR ctr;
507         int i;
508
509         uint32 level = 1;
510
511         fstring srv_name;
512         fstring env;
513
514         fstrcpy(srv_name, "\\\\");
515         fstrcat(srv_name, info->dest_host);
516         strupper(srv_name);
517
518         if (argc < 1) {
519                 report(out_hnd, "spoolgetprinterdriverdir <arch>\n");
520                 return NT_STATUS_NOPROBLEMO;
521         }
522
523         fstrcpy(env, argv[1]);
524
525         for (i=2; i<=argc; i++) {
526                 fstrcat(env, " ");
527                 fstrcat(env, argv[i]);
528         }
529
530         if (msrpc_spoolss_getprinterdriverdir(srv_name, env, level, ctr))
531                 DEBUG(5,("cmd_spoolss_getprinterdriverdir: query succeeded\n"));
532         else
533                 report(out_hnd, "FAILED\n");
534
535         return NT_STATUS_NOPROBLEMO;
536 }
537
538 /********************************************************************************
539  send an AddPrinterEx() request
540 ********************************************************************************/
541 uint32 cmd_spoolss_addprinterex(struct client_info *info, int argc, char *argv[])
542 {
543         fstring         srv_name, 
544                         printer_name, 
545                         driver_name,
546                         port_name;
547         POLICY_HND hnd;
548         PRINTER_INFO_2  print_info_2;
549         PORT_INFO_1     *port_info_1 = NULL;
550         NEW_BUFFER      buffer;
551         uint32          status,
552                         needed,
553                         returned;
554         uint32          i;
555         fstring         srv_port_name;
556         BOOL            valid_port = False;
557         TALLOC_CTX      *mem_ctx = NULL;
558
559         fstrcpy(srv_name, "\\\\");
560         fstrcat(srv_name, info->dest_host);
561         strupper(srv_name);
562
563         /* check (and copy) the command line arguments */
564         if (argc < 3) {
565                 report(out_hnd, "spooladdprinterex <name> <driver> <port>\n");
566                 return NT_STATUS_INVALID_PARAMETER;
567         }
568         else
569         {
570                 fstrcpy(printer_name, argv[1]);
571                 fstrcpy(driver_name, argv[2]);
572                 fstrcpy(port_name, argv[3]);
573         }
574         
575         /* Verify that the specified port is ok; spoolss_enum_ports() should 
576            be a level 1 since all we need is the name */
577         if ((mem_ctx=talloc_init()) == NULL)
578         {
579                 DEBUG(0, ("cmd_spoolss_addprinterex: talloc_init() failed!\n"));
580                 return NT_STATUS_INVALID_PARAMETER;
581         }
582         init_buffer (&buffer, 0, mem_ctx);
583         
584         /* send a NULL buffer first */
585         status=spoolss_enum_ports(srv_name, 1, &buffer, 0, 
586                                      &needed, &returned);
587         
588         /* send the right amount of space this time */
589         if (status==ERROR_INSUFFICIENT_BUFFER) {
590                 init_buffer(&buffer, needed, mem_ctx);
591                 status=spoolss_enum_ports(srv_name, 1, &buffer, 
592                                           needed, &needed, &returned);
593                                           
594                 /* if the call succeeded, then decode the buffer into 
595                    an PRINTER_INFO_1 structre */
596                 if (status == NT_STATUS_NO_PROBLEMO)
597                 {
598                         decode_port_info_1(&buffer, returned, &port_info_1);
599                 }
600                 else
601                 {
602                         report (out_hnd, "cmd_spoolss_addprinterex: FAILED to enumerate ports\n");
603                         return NT_STATUS_NOPROBLEMO;
604                 }
605         }
606         
607         /*
608          * now we have an array of port names and we can interate
609          * through it to verify port_name before actually attempting 
610          * to add the printer on the server.
611          */
612         for (i=0; i<returned; i++)
613         {
614                 /* compare port_info_1[i].port_name to the port_name specified */
615                 unistr_to_ascii(srv_port_name, port_info_1[i].port_name.buffer, 
616                                 sizeof(srv_port_name)-1);
617                 if (strequal(srv_port_name, port_name))
618                 {
619                         valid_port = True;
620                         break;
621                 }
622         }
623         if (!valid_port)
624         {
625                 report (out_hnd, "cmd_spoolss_addprinterex: Invalid port specified!\n");
626                 return NT_STATUS_NOPROBLEMO;
627         }
628         
629         /*
630          * Need to build the PRINTER_INFO_2 struct here.
631          * I think it would be better only to deal with a PRINTER_INFO_2
632          * and the abstract the creation of a SPOOL_PRINTER_INFO_LEVEL_2
633          * from that rather than dealing with the struct passed directly 
634          * on the wire.  We don't need the extra *_ptr fields, etc... 
635          * here anyways.  --jerry
636          */
637         ZERO_STRUCTP(&print_info_2);
638         /* init_unistr( &print_info_2.servername,       srv_name); */
639         init_unistr( &print_info_2.printername, printer_name);
640         /* init_unistr( &print_info_2.sharename,        share_name); */
641         init_unistr( &print_info_2.portname,    port_name);
642         init_unistr( &print_info_2.drivername,  driver_name);
643         init_unistr( &print_info_2.comment,     "Created by rpcclient");
644         /* init_unistr( &print_info_2.location, "");
645         init_unistr( &print_info_2.sepfile,     ""); */
646         init_unistr( &print_info_2.printprocessor, "winprint");
647         init_unistr( &print_info_2.datatype,    "RAW");
648         /* init_unistr( &print_info_2.parameters,       ""); */
649         print_info_2.devmode = NULL;
650         print_info_2.secdesc = NULL;
651         print_info_2.attributes         = 0;
652         print_info_2.priority           = 0;
653         print_info_2.defaultpriority    = 0;
654         print_info_2.starttime          = 0;
655         print_info_2.untiltime          = 0;
656         print_info_2.status             = 0;
657         print_info_2.cjobs              = 0;
658         print_info_2.averageppm         = 0;
659
660
661         /* if successful, spoolss_addprinterex() should return True and hnd 
662            should be a valid handle to an open printer */
663         if (spoolss_addprinterex(&hnd, srv_name, &print_info_2))
664         {
665                 DEBUG(0,("cmd_spoolss_addprinterex: [%s] added successfully.\n", printer_name));
666                 if (!spoolss_closeprinter( &hnd ))
667                 {
668                         report (out_hnd, "cmd_spoolss_addprinterex: spoolss_closeprinter FAILED!\n");
669                 }
670         }
671         else
672         {
673                 report (out_hnd, "cmd_spoolss_addprinterex: spoolss_addprinterex FAILED!\n");
674         }
675
676         
677         return NT_STATUS_NOPROBLEMO;
678 }
679         
680 /********************************************************************************
681  send an AddPrinterDriver() request
682 ********************************************************************************/
683 uint32 cmd_spoolss_addprinterdriver(struct client_info *info, int argc, char *argv[])
684 {
685         PRINTER_DRIVER_CTR      driver_info;
686         DRIVER_INFO_3           info3;
687         fstring                 arch;
688         fstring                 srv_name;
689         uint32                  result = NT_STATUS_NO_PROBLEMO;
690         
691         /* parse the command arguements */
692         if (argc < 2)
693         {
694                 report (out_hnd, "spooladdprinterdriver <arch>\\\n");
695                 report (out_hnd, "\t<Long Printer Name>:<Driver File Name>:<Data File Name>:\\\n");
696                 report (out_hnd, "\t<Config File Name>:<Help File Name>:<Language Monitor Name>:\\\n");
697                 report (out_hnd, "\t<Default Data Type>:<Comma Separated list of Files>\n");
698
699                 return NT_STATUS_INVALID_PARAMETER;
700         }
701         else
702         {
703                 ZERO_STRUCT(info3);
704                 
705                 /* get the enviorment for the driver */
706                 if (!get_short_archi(arch, argv[1]))
707                 {
708                         report (out_hnd, "Unknown architechture [%s]\n", argv[1]);
709                         return NT_STATUS_INVALID_PARAMETER;
710                         
711                 }
712                 else
713                 {
714                         set_drv_info_3_env(&info3, arch);
715                 }
716                 
717                 /* fill in the other struct members */
718                 if (!init_drv_info_3_members(&info3, argv[2]))
719                 {
720                         report (out_hnd, "Invalid parameter list.\n");
721                         return NT_STATUS_INVALID_PARAMETER;
722                 }
723         }
724         
725         /* get the server name */
726         fstrcpy(srv_name, "\\\\");
727         fstrcat(srv_name, info->dest_host);
728         strupper(srv_name);
729         
730         /* call AddPrinterDriver() woth an info level 3 */
731         driver_info.info3 = &info3;
732         if ((result=spoolss_addprinterdriver(srv_name, 3, &driver_info)) != NT_STATUS_NO_PROBLEMO)
733         {
734                 report( out_hnd, "spoolss_addprinterdriver: Add Printer failed [%d]\n",
735                         result);
736         }
737         
738         free_drv_info_3(&info3);
739         
740         return result;
741 }       
742
743 /*******************************************************************************
744  set the version and environment fields of a DRIVER_INFO_3 struct
745  ******************************************************************************/
746 void set_drv_info_3_env (DRIVER_INFO_3 *info, const char *arch)
747 {
748         if (strcmp(arch, "WIN40") == 0)
749         {
750                 info->version = 0;
751                 init_unistr(&info->architecture, "Windows 4.0");
752         }
753         else if (strcmp(arch, "W32X86") == 0)
754         {
755                 info->version = 2;
756                 init_unistr(&info->architecture, "Windows NT x86");
757         }
758         else if (strcmp(arch, "W32MIPS") == 0)
759         {
760                 info->version = 2;
761                 init_unistr(&info->architecture, "Windows NT R4000");
762         }
763         else if (strcmp(arch, "W32ALPHA") == 0)
764         {
765                 info->version = 2;
766                 init_unistr(&info->architecture, "Windows NT Alpha_AXP");
767         }
768         else if (strcmp(arch, "W32PPC") == 0)
769         {
770                 info->version = 2;
771                 init_unistr(&info->architecture, "Windows NT PowerPC");
772         }
773         else
774         {
775                 DEBUG(0, ("set_drv_info_3_env: Unknown arch [%s]\n", arch));
776         }
777         
778         return;
779 }
780
781 /**************************************************************************
782  wrapper for strtok to get the next parameter from a delimited list.
783  Needed to handle the empty parameter string denoted by "NULL"
784  *************************************************************************/
785 static char* get_driver_3_param (char* str, char* delim, UNISTR* dest)
786 {
787         char    *ptr;
788
789         /* get the next token */
790         ptr = strtok(str, delim);
791
792         /* a string of 'NULL' is used to represent an empty
793            parameter because two consecutive delimiters
794            will not return an empty string.  See man strtok(3)
795            for details */
796         if (StrCaseCmp(ptr, "NULL") == 0)
797                 ptr = NULL;
798
799         if (dest != NULL)
800                 init_unistr(dest, ptr); 
801
802         return ptr;
803 }
804
805 /********************************************************************************
806  fill in the members of a DRIVER_INFO_3 struct using a character 
807  string in the form of
808          <Long Printer Name>:<Driver File Name>:<Data File Name>:\
809              <Config File Name>:<Help File Name>:<Language Monitor Name>:\
810              <Default Data Type>:<Comma Separated list of Files> 
811  *******************************************************************************/
812 BOOL init_drv_info_3_members (DRIVER_INFO_3 *info, char *args)
813 {
814         char    *str, *str2;
815         uint32  len, i;
816         
817         /* fill in the UNISTR fields */
818         str = get_driver_3_param (args, ":", &info->name);
819         str = get_driver_3_param (NULL, ":", &info->driverpath);
820         str = get_driver_3_param (NULL, ":", &info->datafile);
821         str = get_driver_3_param (NULL, ":", &info->configfile);
822         str = get_driver_3_param (NULL, ":", &info->helpfile);
823         str = get_driver_3_param (NULL, ":", &info->monitorname);
824         str = get_driver_3_param (NULL, ":", &info->defaultdatatype);
825
826         /* <Comma Separated List of Dependent Files> */
827         str2 = get_driver_3_param (NULL, ":", NULL); /* save the beginning of the string */
828         str = str2;                     
829
830         /* begin to strip out each filename */
831         str = strtok(str, ",");         
832         len = 0;
833         while (str != NULL)
834         {
835                 /* keep a cumlative count of the str lengths */
836                 len += strlen(str)+1;
837                 str = strtok(NULL, ",");
838         }
839
840         /* allocate the space; add one extra slot for a terminating NULL.
841            Each filename is NULL terminated and the end contains a double
842            NULL */
843         if ((info->dependentfiles=(uint16*)malloc((len+1)*sizeof(uint16))) == NULL)
844         {
845                 DEBUG(0,("init_drv_info_3_members: Unable to malloc memory for dependenfiles\n"));
846                 return False;
847         }
848         for (i=0; i<len; i++)
849         {
850                 info->dependentfiles[i] = (uint16)str2[i];
851         }
852         info->dependentfiles[len+1] = '\0';
853
854         return True;
855 }
856
857 /*****************************************************************************
858  free any dynamically allocated members
859  ****************************************************************************/
860 void free_drv_info_3 (DRIVER_INFO_3 *info)
861 {
862         if (info->dependentfiles != NULL)
863         {
864                 free(info->dependentfiles);
865                 info->dependentfiles = NULL;
866         }
867         
868         return;
869 }
870
871
872