pidl:NDR/Client.pm: use dcerpc_binding_handl_call_params* if a dcerpc pipe is used
[metze/samba/wip.git] / pidl / lib / Parse / Pidl / Samba4 / NDR / Client.pm
1 ###################################################
2 # client calls generator
3 # Copyright tridge@samba.org 2003
4 # Copyright jelmer@samba.org 2005-2006
5 # released under the GNU GPL
6
7 package Parse::Pidl::Samba4::NDR::Client;
8
9 use Exporter;
10 @ISA = qw(Exporter);
11 @EXPORT_OK = qw(Parse);
12
13 use Parse::Pidl qw(fatal warning error);
14 use Parse::Pidl::Util qw(has_property ParseExpr genpad);
15 use Parse::Pidl::NDR qw(ContainsPipe);
16 use Parse::Pidl::Typelist qw(mapTypeName);
17 use Parse::Pidl::Samba4 qw(choose_header is_intree DeclLong);
18 use Parse::Pidl::Samba4::Header qw(GenerateFunctionInEnv GenerateFunctionOutEnv);
19
20 use vars qw($VERSION);
21 $VERSION = '0.01';
22
23 use strict;
24
25 sub indent($) { my ($self) = @_; $self->{tabs}.="\t"; }
26 sub deindent($) { my ($self) = @_; $self->{tabs} = substr($self->{tabs}, 1); }
27 sub pidl($$) { my ($self,$txt) = @_; $self->{res} .= $txt ? "$self->{tabs}$txt\n" : "\n"; }
28 sub pidl_hdr($$) { my ($self, $txt) = @_; $self->{res_hdr} .= "$txt\n"; }
29 sub pidl_both($$) { my ($self, $txt) = @_; $self->{hdr} .= "$txt\n"; $self->{res_hdr} .= "$txt\n"; }
30 sub fn_declare($$) { my ($self,$n) = @_; $self->pidl($n); $self->pidl_hdr("$n;"); }
31
32 sub new($)
33 {
34         my ($class) = shift;
35         my $self = { res => "", res_hdr => "", tabs => "" };
36         bless($self, $class);
37 }
38
39 sub ParseFunctionHasPipes($$)
40 {
41         my ($self, $fn) = @_;
42
43         foreach my $e (@{$fn->{ELEMENTS}}) {
44                 return 1 if ContainsPipe($e, $e->{LEVELS}[0]);
45         }
46
47         return 0;
48 }
49
50 sub ParseFunction_r_State($$$$)
51 {
52         my ($self, $if, $fn, $name) = @_;
53         my $uname = uc $name;
54
55         my $in_pipes = 0;
56         foreach my $e (@{$fn->{ELEMENTS}}) {
57                 next unless grep(/in/, @{$e->{DIRECTION}});
58                 next unless ContainsPipe($e, $e->{LEVELS}[0]);
59                 $in_pipes++;
60         }
61         my $out_pipes = 0;
62         foreach my $e (@{$fn->{ELEMENTS}}) {
63                 next unless grep(/out/, @{$e->{DIRECTION}});
64                 next unless ContainsPipe($e, $e->{LEVELS}[0]);
65                 $out_pipes++;
66         }
67
68         $self->pidl("struct dcerpc_$name\_r_state {");
69         $self->indent;
70         if ($in_pipes > 0 or $out_pipes > 0) {
71                 $self->pidl("struct dcerpc_pipe_handle_connection *in_pipes[$in_pipes];") if ($in_pipes > 0);
72                 $self->pidl("struct dcerpc_pipe_handle_connection *out_pipes[$out_pipes];") if ($out_pipes > 0);
73                 $self->pidl("struct dcerpc_binding_handle_call_params params;");
74         }
75         $self->pidl("TALLOC_CTX *out_mem_ctx;");
76         $self->deindent;
77         $self->pidl("};");
78         $self->pidl("");
79         $self->pidl("static void dcerpc_$name\_r_done(struct tevent_req *subreq);");
80         $self->pidl("");
81 }
82
83 sub ParseFunction_r_Send($$$$)
84 {
85         my ($self, $if, $fn, $name) = @_;
86         my $uname = uc $name;
87
88         my $proto = "struct tevent_req *dcerpc_$name\_r_send(TALLOC_CTX *mem_ctx,\n";
89         $proto   .= "\tstruct tevent_context *ev,\n",
90         $proto   .= "\tstruct dcerpc_binding_handle *h,\n",
91         $proto   .= "\tstruct $name *r)";
92
93         $self->fn_declare($proto);
94
95         $self->pidl("{");
96         $self->indent;
97
98         $self->pidl("struct tevent_req *req;");
99         $self->pidl("struct dcerpc_$name\_r_state *state;");
100         $self->pidl("struct tevent_req *subreq;");
101         $self->pidl("");
102
103         $self->pidl("req = tevent_req_create(mem_ctx, &state,");
104         $self->pidl("\t\t\tstruct dcerpc_$name\_r_state);");
105         $self->pidl("if (req == NULL) {");
106         $self->indent;
107         $self->pidl("return NULL;");
108         $self->deindent;
109         $self->pidl("}");
110         $self->pidl("");
111
112         my $out_params = 0;
113         foreach my $e (@{$fn->{ELEMENTS}}) {
114                 next unless grep(/out/, @{$e->{DIRECTION}});
115                 next if ContainsPipe($e, $e->{LEVELS}[0]);
116                 $out_params++;
117
118         }
119
120         my $submem;
121         if ($out_params > 0) {
122                 $self->pidl("state->out_mem_ctx = talloc_new(state);");
123                 $self->pidl("if (tevent_req_nomem(state->out_mem_ctx, req)) {");
124                 $self->indent;
125                 $self->pidl("return tevent_req_post(req, ev);");
126                 $self->deindent;
127                 $self->pidl("}");
128                 $submem = "state->out_mem_ctx";
129         } else {
130                 $self->pidl("state->out_mem_ctx = NULL;");
131                 $submem = "state";
132         }
133         $self->pidl("");
134
135         my $in_pipes = 0;
136         foreach my $e (@{$fn->{ELEMENTS}}) {
137                 next unless grep(/in/, @{$e->{DIRECTION}});
138                 next unless ContainsPipe($e, $e->{LEVELS}[0]);
139                 $self->pidl("if (r->in.$e->{NAME} == NULL) {");
140                 $self->indent;
141                 $self->pidl("tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);");
142                 $self->pidl("return tevent_req_post(req, ev);");
143                 $self->deindent;
144                 $self->pidl("}");
145                 $self->pidl("state->in_pipes[$in_pipes] = r->in.".$e->{NAME}."->pc;");
146                 $in_pipes++;
147         }
148         my $out_pipes = 0;
149         foreach my $e (@{$fn->{ELEMENTS}}) {
150                 next unless grep(/out/, @{$e->{DIRECTION}});
151                 next unless ContainsPipe($e, $e->{LEVELS}[0]);
152                 $self->pidl("if (r->out.$e->{NAME} == NULL) {");
153                 $self->indent;
154                 $self->pidl("tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);");
155                 $self->pidl("return tevent_req_post(req, ev);");
156                 $self->deindent;
157                 $self->pidl("}");
158                 $self->pidl("state->out_pipes[$out_pipes] = r->out.".$e->{NAME}."->pc;");
159                 $out_pipes++;
160         }
161
162         if ($in_pipes > 0 or $out_pipes > 0) {
163                 $self->pidl("state->params.r_mem = $submem;");
164                 $self->pidl("state->params.r_ptr = r;");
165                 $self->pidl("state->params.in.num_pipes = $in_pipes;");
166                 if ($in_pipes > 0) {
167                         $self->pidl("state->params.in.pipes = state->in_pipes;");
168                 } else {
169                         $self->pidl("state->params.in.pipes = NULL;");
170                 }
171                 $self->pidl("state->params.out.num_pipes = $out_pipes;");
172                 if ($out_pipes > 0) {
173                         $self->pidl("state->params.out.pipes = state->out_pipes;");
174                 } else {
175                         $self->pidl("state->params.out.pipes = NULL;");
176                 }
177                 $self->pidl("");
178
179                 $self->pidl("subreq = dcerpc_binding_handle_call_params_send(state, ev, h,");
180                 $self->pidl("\t\tNULL, &ndr_table_$if->{NAME},");
181                 $self->pidl("\t\tNDR_$uname, &state->params);");
182         } else {
183                 $self->pidl("subreq = dcerpc_binding_handle_call_send(state, ev, h,");
184                 $self->pidl("\t\tNULL, &ndr_table_$if->{NAME},");
185                 $self->pidl("\t\tNDR_$uname, $submem, r);");
186         }
187         $self->pidl("if (tevent_req_nomem(subreq, req)) {");
188         $self->indent;
189         $self->pidl("return tevent_req_post(req, ev);");
190         $self->deindent;
191         $self->pidl("}");
192         $self->pidl("tevent_req_set_callback(subreq, dcerpc_$name\_r_done, req);");
193         $self->pidl("");
194
195         $self->pidl("return req;");
196         $self->deindent;
197         $self->pidl("}");
198         $self->pidl("");
199 }
200
201 sub ParseFunction_r_Done($$$$)
202 {
203         my ($self, $if, $fn, $name) = @_;
204         my $uname = uc $name;
205
206         my $proto = "static void dcerpc_$name\_r_done(struct tevent_req *subreq)";
207
208         my $in_pipes = 0;
209         foreach my $e (@{$fn->{ELEMENTS}}) {
210                 next unless grep(/in/, @{$e->{DIRECTION}});
211                 next unless ContainsPipe($e, $e->{LEVELS}[0]);
212                 $in_pipes++;
213         }
214         my $out_pipes = 0;
215         foreach my $e (@{$fn->{ELEMENTS}}) {
216                 next unless grep(/out/, @{$e->{DIRECTION}});
217                 next unless ContainsPipe($e, $e->{LEVELS}[0]);
218                 $out_pipes++;
219         }
220
221         $self->pidl("$proto");
222         $self->pidl("{");
223         $self->indent;
224
225         $self->pidl("struct tevent_req *req =");
226         $self->pidl("\ttevent_req_callback_data(subreq,");
227         $self->pidl("\tstruct tevent_req);");
228         $self->pidl("NTSTATUS status;");
229         $self->pidl("");
230
231         if ($in_pipes > 0 or $out_pipes > 0) {
232                 $self->pidl("status = dcerpc_binding_handle_call_params_recv(subreq);");
233         } else {
234                 $self->pidl("status = dcerpc_binding_handle_call_recv(subreq);");
235         }
236         $self->pidl("TALLOC_FREE(subreq);");
237         $self->pidl("if (tevent_req_nterror(req, status)) {");
238         $self->indent;
239         $self->pidl("return;");
240         $self->deindent;
241         $self->pidl("}");
242         $self->pidl("");
243
244         $self->pidl("tevent_req_done(req);");
245         $self->deindent;
246         $self->pidl("}");
247         $self->pidl("");
248 }
249
250 sub ParseFunction_r_Recv($$$$)
251 {
252         my ($self, $if, $fn, $name) = @_;
253         my $uname = uc $name;
254
255         my $proto = "NTSTATUS dcerpc_$name\_r_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx)";
256
257         $self->fn_declare($proto);
258
259         $self->pidl("{");
260         $self->indent;
261
262         $self->pidl("struct dcerpc_$name\_r_state *state =");
263         $self->pidl("\ttevent_req_data(req,");
264         $self->pidl("\tstruct dcerpc_$name\_r_state);");
265         $self->pidl("NTSTATUS status;");
266         $self->pidl("");
267
268         $self->pidl("if (tevent_req_is_nterror(req, &status)) {");
269         $self->indent;
270         $self->pidl("tevent_req_received(req);");
271         $self->pidl("return status;");
272         $self->deindent;
273         $self->pidl("}");
274         $self->pidl("");
275
276         $self->pidl("talloc_steal(mem_ctx, state->out_mem_ctx);");
277         $self->pidl("");
278
279         $self->pidl("tevent_req_received(req);");
280         $self->pidl("return NT_STATUS_OK;");
281         $self->deindent;
282         $self->pidl("}");
283         $self->pidl("");
284 }
285
286 sub ParseFunction_r_Sync($$$$)
287 {
288         my ($self, $if, $fn, $name) = @_;
289         my $uname = uc $name;
290
291         if ($self->ParseFunctionHasPipes($fn)) {
292                 $self->pidl_both("/*");
293                 $self->pidl_both(" * The following function is skipped because");
294                 $self->pidl_both(" * it uses pipes:");
295                 $self->pidl_both(" *");
296                 $self->pidl_both(" * dcerpc_$name\_r()");
297                 $self->pidl_both(" */");
298                 $self->pidl_both("");
299                 return;
300         }
301
302         my $proto = "NTSTATUS dcerpc_$name\_r(struct dcerpc_binding_handle *h, TALLOC_CTX *mem_ctx, struct $name *r)";
303
304         $self->fn_declare($proto);
305
306         $self->pidl("{");
307         $self->indent;
308         $self->pidl("NTSTATUS status;");
309         $self->pidl("");
310
311         $self->pidl("status = dcerpc_binding_handle_call(h,");
312         $self->pidl("\t\tNULL, &ndr_table_$if->{NAME},");
313         $self->pidl("\t\tNDR_$uname, mem_ctx, r);");
314         $self->pidl("");
315         $self->pidl("return status;");
316
317         $self->deindent;
318         $self->pidl("}");
319         $self->pidl("");
320 }
321
322 sub ElementDirection($)
323 {
324         my ($e) = @_;
325
326         return "[in,out]" if (has_property($e, "in") and has_property($e, "out"));
327         return "[in]" if (has_property($e, "in"));
328         return "[out]" if (has_property($e, "out"));
329         return "[in,out]";
330 }
331
332 sub HeaderProperties($$)
333 {
334         my($props,$ignores) = @_;
335         my $ret = "";
336
337         foreach my $d (sort(keys %{$props})) {
338                 next if (grep(/^$d$/, @$ignores));
339                 if($props->{$d} ne "1") {
340                         $ret.= "$d($props->{$d}),";
341                 } else {
342                         $ret.="$d,";
343                 }
344         }
345
346         if ($ret) {
347                 return "[" . substr($ret, 0, -1) . "]";
348         }
349 }
350
351 sub ParseCopyArgument($$$$$)
352 {
353         my ($self, $fn, $e, $r, $i) = @_;
354         my $l = $e->{LEVELS}[0];
355
356         if ($l->{TYPE} eq "ARRAY" and $l->{IS_FIXED} == 1) {
357                 $self->pidl("memcpy(${r}$e->{NAME}, ${i}$e->{NAME}, sizeof(${r}$e->{NAME}));");
358         } else {
359                 $self->pidl("${r}$e->{NAME} = ${i}$e->{NAME};");
360         }
361 }
362
363 sub ParseInvalidResponse($$)
364 {
365         my ($self, $type) = @_;
366
367         if ($type eq "sync") {
368                 $self->pidl("return NT_STATUS_INVALID_NETWORK_RESPONSE;");
369         } elsif ($type eq "async") {
370                 $self->pidl("tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);");
371                 $self->pidl("return;");
372         } else {
373                 die("ParseInvalidResponse($type)");
374         }
375 }
376
377 sub ParseOutputArgument($$$$$$)
378 {
379         my ($self, $fn, $e, $r, $o, $invalid_response_type) = @_;
380         my $level = 0;
381
382         if ($e->{LEVELS}[0]->{TYPE} ne "POINTER" and $e->{LEVELS}[0]->{TYPE} ne "ARRAY") {
383                 fatal($e->{ORIGINAL}, "[out] argument is not a pointer or array");
384                 return;
385         }
386
387         if ($e->{LEVELS}[0]->{TYPE} eq "POINTER") {
388                 $level = 1;
389                 if ($e->{LEVELS}[0]->{POINTER_TYPE} ne "ref") {
390                         $self->pidl("if ($o$e->{NAME} && ${r}out.$e->{NAME}) {");
391                         $self->indent;
392                 }
393         }
394
395         if ($e->{LEVELS}[$level]->{TYPE} eq "ARRAY") {
396                 # This is a call to GenerateFunctionInEnv intentionally.
397                 # Since the data is being copied into a user-provided data
398                 # structure, the user should be able to know the size beforehand
399                 # to allocate a structure of the right size.
400                 my $in_env = GenerateFunctionInEnv($fn, $r);
401                 my $out_env = GenerateFunctionOutEnv($fn, $r);
402                 my $l = $e->{LEVELS}[$level];
403
404                 my $in_var = undef;
405                 if (grep(/in/, @{$e->{DIRECTION}})) {
406                         $in_var = ParseExpr($e->{NAME}, $in_env, $e->{ORIGINAL});
407                 }
408                 my $out_var = ParseExpr($e->{NAME}, $out_env, $e->{ORIGINAL});
409
410                 my $in_size_is = undef;
411                 my $out_size_is = undef;
412                 my $out_length_is = undef;
413
414                 my $avail_len = undef;
415                 my $needed_len = undef;
416
417                 $self->pidl("{");
418                 $self->indent;
419                 my $copy_len_var = "_copy_len_$e->{NAME}";
420                 $self->pidl("size_t $copy_len_var;");
421
422                 if (not defined($l->{SIZE_IS})) {
423                         if (not $l->{IS_ZERO_TERMINATED}) {
424                                 fatal($e->{ORIGINAL}, "no size known for [out] array `$e->{NAME}'");
425                         }
426                         if (has_property($e, "charset")) {
427                                 $avail_len = "ndr_charset_length($in_var, CH_UNIX)";
428                                 $needed_len = "ndr_charset_length($out_var, CH_UNIX)";
429                         } else {
430                                 $avail_len = "ndr_string_length($in_var, sizeof(*$in_var))";
431                                 $needed_len = "ndr_string_length($out_var, sizeof(*$out_var))";
432                         }
433                         $in_size_is = "";
434                         $out_size_is = "";
435                         $out_length_is = "";
436                 } else {
437                         $in_size_is = ParseExpr($l->{SIZE_IS}, $in_env, $e->{ORIGINAL});
438                         $out_size_is = ParseExpr($l->{SIZE_IS}, $out_env, $e->{ORIGINAL});
439                         $out_length_is = $out_size_is;
440                         if (defined($l->{LENGTH_IS})) {
441                                 $out_length_is = ParseExpr($l->{LENGTH_IS}, $out_env, $e->{ORIGINAL});
442                         }
443                         if (has_property($e, "charset")) {
444                                 if (defined($in_var)) {
445                                         $avail_len = "ndr_charset_length($in_var, CH_UNIX)";
446                                 } else {
447                                         $avail_len = $out_length_is;
448                                 }
449                                 $needed_len = "ndr_charset_length($out_var, CH_UNIX)";
450                         }
451                 }
452
453                 if ($out_size_is ne $in_size_is) {
454                         $self->pidl("if (($out_size_is) > ($in_size_is)) {");
455                         $self->indent;
456                         $self->ParseInvalidResponse($invalid_response_type);
457                         $self->deindent;
458                         $self->pidl("}");
459                 }
460                 if ($out_length_is ne $out_size_is) {
461                         $self->pidl("if (($out_length_is) > ($out_size_is)) {");
462                         $self->indent;
463                         $self->ParseInvalidResponse($invalid_response_type);
464                         $self->deindent;
465                         $self->pidl("}");
466                 }
467                 if (defined($needed_len)) {
468                         $self->pidl("$copy_len_var = $needed_len;");
469                         $self->pidl("if ($copy_len_var > $avail_len) {");
470                         $self->indent;
471                         $self->ParseInvalidResponse($invalid_response_type);
472                         $self->deindent;
473                         $self->pidl("}");
474                 } else {
475                         $self->pidl("$copy_len_var = $out_length_is;");
476                 }
477
478                 my $dest_ptr = "$o$e->{NAME}";
479                 my $elem_size = "sizeof(*$dest_ptr)";
480                 $self->pidl("if ($dest_ptr != $out_var) {");
481                 $self->indent;
482                 if (has_property($e, "charset")) {
483                         $dest_ptr = "discard_const_p(uint8_t *, $dest_ptr)";
484                 }
485                 $self->pidl("memcpy($dest_ptr, $out_var, $copy_len_var * $elem_size);");
486                 $self->deindent;
487                 $self->pidl("}");
488
489                 $self->deindent;
490                 $self->pidl("}");
491         } else {
492                 $self->pidl("*$o$e->{NAME} = *${r}out.$e->{NAME};");
493         }
494
495         if ($e->{LEVELS}[0]->{TYPE} eq "POINTER") {
496                 if ($e->{LEVELS}[0]->{POINTER_TYPE} ne "ref") {
497                         $self->deindent;
498                         $self->pidl("}");
499                 }
500         }
501 }
502
503 sub ParseFunction_State($$$$)
504 {
505         my ($self, $if, $fn, $name) = @_;
506
507         my $state_str = "struct dcerpc_$name\_state";
508         my $done_fn = "dcerpc_$name\_done";
509
510         $self->pidl("$state_str {");
511         $self->indent;
512         $self->pidl("struct $name orig;");
513         $self->pidl("struct $name tmp;");
514         $self->pidl("TALLOC_CTX *out_mem_ctx;");
515         $self->deindent;
516         $self->pidl("};");
517         $self->pidl("");
518         $self->pidl("static void $done_fn(struct tevent_req *subreq);");
519         $self->pidl("");
520 }
521
522 sub ParseFunction_Send($$$$)
523 {
524         my ($self, $if, $fn, $name) = @_;
525
526         my $fn_args = "";
527         my $state_str = "struct dcerpc_$name\_state";
528         my $done_fn = "dcerpc_$name\_done";
529         my $out_mem_ctx = "dcerpc_$name\_out_memory";
530         my $fn_str = "struct tevent_req *dcerpc_$name\_send";
531         my $pad = genpad($fn_str);
532
533         $fn_args .= "TALLOC_CTX *mem_ctx";
534         $fn_args .= ",\n" . $pad . "struct tevent_context *ev";
535         $fn_args .= ",\n" . $pad . "struct dcerpc_binding_handle *h";
536
537         foreach (@{$fn->{ELEMENTS}}) {
538                 my $dir = ElementDirection($_);
539                 my $prop = HeaderProperties($_->{PROPERTIES}, ["in", "out"]);
540                 $fn_args .= ",\n" . $pad . DeclLong($_, "_") . " /* $dir $prop */";
541         }
542
543         $self->fn_declare("$fn_str($fn_args)");
544         $self->pidl("{");
545         $self->indent;
546         $self->pidl("struct tevent_req *req;");
547         $self->pidl("$state_str *state;");
548         $self->pidl("struct tevent_req *subreq;");
549         $self->pidl("");
550         $self->pidl("req = tevent_req_create(mem_ctx, &state,");
551         $self->pidl("\t\t\t$state_str);");
552         $self->pidl("if (req == NULL) {");
553         $self->indent;
554         $self->pidl("return NULL;");
555         $self->deindent;
556         $self->pidl("}");
557         $self->pidl("state->out_mem_ctx = NULL;");
558         $self->pidl("");
559
560         $self->pidl("/* In parameters */");
561         foreach my $e (@{$fn->{ELEMENTS}}) {
562                 next unless (grep(/in/, @{$e->{DIRECTION}}));
563
564                 $self->ParseCopyArgument($fn, $e, "state->orig.in.", "_");
565         }
566         $self->pidl("");
567
568         my $out_params = 0;
569         $self->pidl("/* Out parameters */");
570         foreach my $e (@{$fn->{ELEMENTS}}) {
571                 next unless grep(/out/, @{$e->{DIRECTION}});
572
573                 $self->ParseCopyArgument($fn, $e, "state->orig.out.", "_");
574
575                 next if ContainsPipe($e, $e->{LEVELS}[0]);
576
577                 $out_params++;
578         }
579         $self->pidl("");
580
581         if (defined($fn->{RETURN_TYPE})) {
582                 $self->pidl("/* Result */");
583                 $self->pidl("NDR_ZERO_STRUCT(state->orig.out.result);");
584                 $self->pidl("");
585         }
586
587         if ($out_params > 0) {
588                 $self->pidl("state->out_mem_ctx = talloc_named_const(state, 0,");
589                 $self->pidl("\t\t     \"$out_mem_ctx\");");
590                 $self->pidl("if (tevent_req_nomem(state->out_mem_ctx, req)) {");
591                 $self->indent;
592                 $self->pidl("return tevent_req_post(req, ev);");
593                 $self->deindent;
594                 $self->pidl("}");
595                 $self->pidl("");
596         }
597
598         $self->pidl("/* make a temporary copy, that we pass to the dispatch function */");
599         $self->pidl("state->tmp = state->orig;");
600         $self->pidl("");
601
602         $self->pidl("subreq = dcerpc_$name\_r_send(state, ev, h, &state->tmp);");
603         $self->pidl("if (tevent_req_nomem(subreq, req)) {");
604         $self->indent;
605         $self->pidl("return tevent_req_post(req, ev);");
606         $self->deindent;
607         $self->pidl("}");
608         $self->pidl("tevent_req_set_callback(subreq, $done_fn, req);");
609         $self->pidl("return req;");
610         $self->deindent;
611         $self->pidl("}");
612         $self->pidl("");
613 }
614
615 sub ParseFunction_Done($$$$)
616 {
617         my ($self, $if, $fn, $name) = @_;
618
619         my $state_str = "struct dcerpc_$name\_state";
620         my $done_fn = "dcerpc_$name\_done";
621
622         $self->pidl("static void $done_fn(struct tevent_req *subreq)");
623         $self->pidl("{");
624         $self->indent;
625         $self->pidl("struct tevent_req *req = tevent_req_callback_data(");
626         $self->pidl("\tsubreq, struct tevent_req);");
627         $self->pidl("$state_str *state = tevent_req_data(");
628         $self->pidl("\treq, $state_str);");
629         $self->pidl("NTSTATUS status;");
630         $self->pidl("TALLOC_CTX *mem_ctx;");
631         $self->pidl("");
632
633         $self->pidl("if (state->out_mem_ctx) {");
634         $self->indent;
635         $self->pidl("mem_ctx = state->out_mem_ctx;");
636         $self->deindent;
637         $self->pidl("} else {");
638         $self->indent;
639         $self->pidl("mem_ctx = state;");
640         $self->deindent;
641         $self->pidl("}");
642         $self->pidl("");
643
644         $self->pidl("status = dcerpc_$name\_r_recv(subreq, mem_ctx);");
645         $self->pidl("TALLOC_FREE(subreq);");
646         $self->pidl("if (tevent_req_nterror(req, status)) {");
647         $self->indent;
648         $self->pidl("return;");
649         $self->deindent;
650         $self->pidl("}");
651         $self->pidl("");
652
653         $self->pidl("/* Copy out parameters */");
654         foreach my $e (@{$fn->{ELEMENTS}}) {
655                 next if ContainsPipe($e, $e->{LEVELS}[0]);
656                 next unless (grep(/out/, @{$e->{DIRECTION}}));
657
658                 $self->ParseOutputArgument($fn, $e,
659                                            "state->tmp.",
660                                            "state->orig.out.",
661                                            "async");
662         }
663         $self->pidl("");
664
665         if (defined($fn->{RETURN_TYPE})) {
666                 $self->pidl("/* Copy result */");
667                 $self->pidl("state->orig.out.result = state->tmp.out.result;");
668                 $self->pidl("");
669         }
670
671         $self->pidl("/* Reset temporary structure */");
672         $self->pidl("NDR_ZERO_STRUCT(state->tmp);");
673         $self->pidl("");
674
675         $self->pidl("tevent_req_done(req);");
676         $self->deindent;
677         $self->pidl("}");
678         $self->pidl("");
679 }
680
681 sub ParseFunction_Recv($$$$)
682 {
683         my ($self, $if, $fn, $name) = @_;
684
685         my $fn_args = "";
686         my $state_str = "struct dcerpc_$name\_state";
687         my $fn_str = "NTSTATUS dcerpc_$name\_recv";
688         my $pad = genpad($fn_str);
689
690         $fn_args .= "struct tevent_req *req,\n" . $pad . "TALLOC_CTX *mem_ctx";
691
692         if (defined($fn->{RETURN_TYPE})) {
693                 $fn_args .= ",\n" . $pad . mapTypeName($fn->{RETURN_TYPE}). " *result";
694         }
695
696         $self->fn_declare("$fn_str($fn_args)");
697         $self->pidl("{");
698         $self->indent;
699         $self->pidl("$state_str *state = tevent_req_data(");
700         $self->pidl("\treq, $state_str);");
701         $self->pidl("NTSTATUS status;");
702         $self->pidl("");
703         $self->pidl("if (tevent_req_is_nterror(req, &status)) {");
704         $self->indent;
705         $self->pidl("tevent_req_received(req);");
706         $self->pidl("return status;");
707         $self->deindent;
708         $self->pidl("}");
709         $self->pidl("");
710
711         $self->pidl("/* Steal possible out parameters to the callers context */");
712         $self->pidl("talloc_steal(mem_ctx, state->out_mem_ctx);");
713         $self->pidl("");
714
715         if (defined($fn->{RETURN_TYPE})) {
716                 $self->pidl("/* Return result */");
717                 $self->pidl("*result = state->orig.out.result;");
718                 $self->pidl("");
719         }
720
721         $self->pidl("tevent_req_received(req);");
722         $self->pidl("return NT_STATUS_OK;");
723         $self->deindent;
724         $self->pidl("}");
725         $self->pidl("");
726 }
727
728 sub ParseFunction_Sync($$$$)
729 {
730         my ($self, $if, $fn, $name) = @_;
731
732         if ($self->ParseFunctionHasPipes($fn)) {
733                 $self->pidl_both("/*");
734                 $self->pidl_both(" * The following function is skipped because");
735                 $self->pidl_both(" * it uses pipes:");
736                 $self->pidl_both(" *");
737                 $self->pidl_both(" * dcerpc_$name()");
738                 $self->pidl_both(" */");
739                 $self->pidl_both("");
740                 return;
741         }
742
743         my $uname = uc $name;
744         my $fn_args = "";
745         my $fn_str = "NTSTATUS dcerpc_$name";
746         my $pad = genpad($fn_str);
747
748         $fn_args .= "struct dcerpc_binding_handle *h,\n" . $pad . "TALLOC_CTX *mem_ctx";
749
750         foreach (@{$fn->{ELEMENTS}}) {
751                 my $dir = ElementDirection($_);
752                 my $prop = HeaderProperties($_->{PROPERTIES}, ["in", "out"]);
753                 $fn_args .= ",\n" . $pad . DeclLong($_, "_") . " /* $dir $prop */";
754         }
755
756         if (defined($fn->{RETURN_TYPE})) {
757                 $fn_args .= ",\n" . $pad . mapTypeName($fn->{RETURN_TYPE}). " *result";
758         }
759
760         $self->fn_declare("$fn_str($fn_args)");
761         $self->pidl("{");
762         $self->indent;
763         $self->pidl("struct $name r;");
764         $self->pidl("NTSTATUS status;");
765         $self->pidl("");
766
767         $self->pidl("/* In parameters */");
768         foreach my $e (@{$fn->{ELEMENTS}}) {
769                 next unless (grep(/in/, @{$e->{DIRECTION}}));
770
771                 $self->ParseCopyArgument($fn, $e, "r.in.", "_");
772         }
773         $self->pidl("");
774
775         $self->pidl("/* Out parameters */");
776         foreach my $e (@{$fn->{ELEMENTS}}) {
777                 next unless grep(/out/, @{$e->{DIRECTION}});
778
779                 $self->ParseCopyArgument($fn, $e, "r.out.", "_");
780         }
781         $self->pidl("");
782
783         if (defined($fn->{RETURN_TYPE})) {
784                 $self->pidl("/* Result */");
785                 $self->pidl("NDR_ZERO_STRUCT(r.out.result);");
786                 $self->pidl("");
787         }
788
789         $self->pidl("status = dcerpc_$name\_r(h, mem_ctx, &r);");
790         $self->pidl("if (!NT_STATUS_IS_OK(status)) {");
791         $self->indent;
792         $self->pidl("return status;");
793         $self->deindent;
794         $self->pidl("}");
795         $self->pidl("");
796
797         $self->pidl("/* Return variables */");
798         foreach my $e (@{$fn->{ELEMENTS}}) {
799                 next if ContainsPipe($e, $e->{LEVELS}[0]);
800                 next unless (grep(/out/, @{$e->{DIRECTION}}));
801
802                 $self->ParseOutputArgument($fn, $e, "r.", "_", "sync");
803         }
804         $self->pidl("");
805
806         $self->pidl("/* Return result */");
807         if ($fn->{RETURN_TYPE}) {
808                 $self->pidl("*result = r.out.result;");
809         }
810         $self->pidl("");
811
812         $self->pidl("return NT_STATUS_OK;");
813
814         $self->deindent;
815         $self->pidl("}");
816         $self->pidl("");
817 }
818
819 #####################################################################
820 # parse a function
821 sub ParseFunction($$$)
822 {
823         my ($self, $if, $fn) = @_;
824
825         $self->ParseFunction_r_State($if, $fn, $fn->{NAME});
826         $self->ParseFunction_r_Send($if, $fn, $fn->{NAME});
827         $self->ParseFunction_r_Done($if, $fn, $fn->{NAME});
828         $self->ParseFunction_r_Recv($if, $fn, $fn->{NAME});
829         $self->ParseFunction_r_Sync($if, $fn, $fn->{NAME});
830
831         foreach my $e (@{$fn->{ELEMENTS}}) {
832                 next unless (grep(/out/, @{$e->{DIRECTION}}));
833
834                 my $reason = "is not a pointer or array";
835
836                 # TODO: make this fatal at NDR level
837                 if ($e->{LEVELS}[0]->{TYPE} eq "POINTER") {
838                         if ($e->{LEVELS}[1]->{TYPE} eq "DATA" and
839                             $e->{LEVELS}[1]->{DATA_TYPE} eq "string") {
840                                 $reason = "is a pointer to type 'string'";
841                         } elsif ($e->{LEVELS}[1]->{TYPE} eq "ARRAY" and
842                                  $e->{LEVELS}[1]->{IS_ZERO_TERMINATED}) {
843                                 next;
844                         } elsif ($e->{LEVELS}[1]->{TYPE} eq "ARRAY" and
845                                  not defined($e->{LEVELS}[1]->{SIZE_IS})) {
846                                 $reason = "is a pointer to an unsized array";
847                         } else {
848                                 next;
849                         }
850                 }
851                 if ($e->{LEVELS}[0]->{TYPE} eq "ARRAY") {
852                         if (not defined($e->{LEVELS}[0]->{SIZE_IS})) {
853                                 $reason = "is an unsized array";
854                         } else {
855                                 next;
856                         }
857                 }
858
859                 $self->pidl_both("/*");
860                 $self->pidl_both(" * The following functions are skipped because");
861                 $self->pidl_both(" * an [out] argument $e->{NAME} $reason:");
862                 $self->pidl_both(" *");
863                 $self->pidl_both(" * dcerpc_$fn->{NAME}_send()");
864                 $self->pidl_both(" * dcerpc_$fn->{NAME}_recv()");
865                 $self->pidl_both(" * dcerpc_$fn->{NAME}()");
866                 $self->pidl_both(" */");
867                 $self->pidl_both("");
868
869                 error($e->{ORIGINAL}, "$fn->{NAME}: [out] argument '$e->{NAME}' $reason, skip client functions");
870                 return;
871         }
872
873         $self->ParseFunction_State($if, $fn, $fn->{NAME});
874         $self->ParseFunction_Send($if, $fn, $fn->{NAME});
875         $self->ParseFunction_Done($if, $fn, $fn->{NAME});
876         $self->ParseFunction_Recv($if, $fn, $fn->{NAME});
877         $self->ParseFunction_Sync($if, $fn, $fn->{NAME});
878
879         $self->pidl_hdr("");
880 }
881
882 sub ParsePipeCreate($$$)
883 {
884         my ($self, $t, $cname) = @_;
885
886         $self->pidl_both("/* $t->{NAME} */");
887
888         $self->pidl_hdr("struct $t->{NAME};");
889         $self->pidl("struct $t->{NAME} {");
890         $self->indent;
891         $self->pidl("struct dcerpc_pipe_handle_connection *pc;");
892         $self->deindent;
893         $self->pidl("};");
894         $self->pidl("");
895
896         my $proto = "struct $t->{NAME} *dcerpc_$t->{NAME}\_create(TALLOC_CTX *mem_ctx)";
897
898         $self->pidl_hdr("$proto;");
899         $self->pidl("$proto");
900         $self->pidl("{");
901         $self->indent;
902
903         $self->pidl("struct $t->{NAME} *p;");
904         $self->pidl("");
905
906         $self->pidl("p = talloc_zero(mem_ctx, struct $t->{NAME});");
907         $self->pidl("if (p == NULL) {");
908         $self->indent;
909         $self->pidl("return NULL;");
910         $self->deindent;
911         $self->pidl("}");
912         $self->pidl("");
913
914         my $cname = "$t->{NAME}_chunk";
915
916         $self->pidl("/* the pipe is disconnected by default */");
917         $self->pidl("p->pc = dcerpc_pipe_handle_connection_create(p,");
918         $self->pidl("\t\t\t\"$cname\",");
919         $self->pidl("\t\t\tsizeof(struct $cname));");
920         $self->pidl("if (p->pc == NULL) {");
921         $self->indent;
922         $self->pidl("TALLOC_FREE(p);");
923         $self->pidl("return NULL;");
924         $self->deindent;
925         $self->pidl("}");
926         $self->pidl("");
927
928         $self->pidl("return p;");
929         $self->deindent;
930         $self->pidl("}");
931         $self->pidl("");
932 }
933
934 sub ParsePipeChunkPush_State($$$)
935 {
936         my ($self, $t, $cname) = @_;
937
938         my $state_str = "struct dcerpc_$cname\_push_state";
939         my $done_fn = "dcerpc_$cname\_push_done";
940
941         $self->pidl("$state_str {");
942         $self->indent;
943         $self->pidl("uint8_t dummy;");
944         $self->deindent;
945         $self->pidl("};");
946         $self->pidl("");
947
948         $self->pidl("static void $done_fn(struct tevent_req *subreq);");
949         $self->pidl("");
950 }
951
952 sub ParsePipeChunkPush_Send($$$)
953 {
954         my ($self, $t, $cname) = @_;
955
956         my $fn_args = "";
957         my $state_str = "struct dcerpc_$cname\_push_state";
958         my $done_fn = "dcerpc_$cname\_push_done";
959         my $fn_str = "struct tevent_req *dcerpc_$cname\_push_send";
960         my $pad = genpad($fn_str);
961
962         $fn_args .= "TALLOC_CTX *mem_ctx";
963         $fn_args .= ",\n" . $pad . "struct tevent_context *ev";
964         $fn_args .= ",\n" . $pad . "struct $t->{NAME} *p";
965         $fn_args .= ",\n" . $pad . "const struct $cname *chunk";
966
967         $self->fn_declare("$fn_str($fn_args)");
968         $self->pidl("{");
969         $self->indent;
970         $self->pidl("struct tevent_req *req;");
971         $self->pidl("$state_str *state;");
972         $self->pidl("struct tevent_req *subreq;");
973         $self->pidl("");
974
975         $self->pidl("req = tevent_req_create(mem_ctx, &state,");
976         $self->pidl("\t\t\t$state_str);");
977         $self->pidl("if (req == NULL) {");
978         $self->indent;
979         $self->pidl("return NULL;");
980         $self->deindent;
981         $self->pidl("}");
982         $self->pidl("");
983
984         $self->pidl("subreq = dcerpc_pipe_handle_push_send(state, ev,");
985         $self->pidl("\t\t\tp->pc, chunk);");
986         $self->pidl("if (tevent_req_nomem(subreq, req)) {");
987         $self->indent;
988         $self->pidl("return tevent_req_post(req, ev);");
989         $self->deindent;
990         $self->pidl("}");
991         $self->pidl("tevent_req_set_callback(subreq, $done_fn, req);");
992         $self->pidl("");
993
994         $self->pidl("return req;");
995         $self->deindent;
996         $self->pidl("}");
997         $self->pidl("");
998 }
999
1000 sub ParsePipeChunkPush_Done($$$)
1001 {
1002         my ($self, $t, $cname) = @_;
1003
1004         my $fn_args = "";
1005         my $state_str = "struct dcerpc_$cname\_push_state";
1006         my $fn_str = "static void dcerpc_$cname\_push_done";
1007         my $pad = genpad($fn_str);
1008
1009         $fn_args .= "struct tevent_req *subreq";
1010
1011         $self->pidl("$fn_str($fn_args)");
1012         $self->pidl("{");
1013         $self->indent;
1014         $self->pidl("struct tevent_req *req =");
1015         $self->pidl("\ttevent_req_callback_data(subreq,");
1016         $self->pidl("\tstruct tevent_req);");
1017         # unused
1018         #$self->pidl("$state_str *state =");
1019         #$self->pidl("\ttevent_req_data(req,");
1020         #$self->pidl("\t$state_str);");
1021         $self->pidl("NTSTATUS status;");
1022         $self->pidl("");
1023
1024         $self->pidl("status = dcerpc_pipe_handle_push_recv(subreq);");
1025         $self->pidl("TALLOC_FREE(subreq);");
1026         $self->pidl("if (tevent_req_nterror(req, status)) {");
1027         $self->indent;
1028         $self->pidl("return;");
1029         $self->deindent;
1030         $self->pidl("}");
1031         $self->pidl("");
1032
1033         $self->pidl("tevent_req_done(req);");
1034         $self->deindent;
1035         $self->pidl("}");
1036         $self->pidl("");
1037 }
1038
1039 sub ParsePipeChunkPush_Recv($$$)
1040 {
1041         my ($self, $t, $cname) = @_;
1042
1043         my $fn_args = "";
1044         my $state_str = "struct dcerpc_$cname\_push_state";
1045         my $fn_str = "NTSTATUS dcerpc_$cname\_push_recv";
1046         my $pad = genpad($fn_str);
1047
1048         $fn_args .= "struct tevent_req *req";
1049
1050         $self->fn_declare("$fn_str($fn_args)");
1051         $self->pidl("{");
1052         $self->indent;
1053         $self->pidl("$state_str *state =");
1054         $self->pidl("\ttevent_req_data(req,");
1055         $self->pidl("\t$state_str);");
1056         $self->pidl("NTSTATUS status;");
1057         $self->pidl("");
1058
1059         $self->pidl("if (tevent_req_is_nterror(req, &status)) {");
1060         $self->indent;
1061         $self->pidl("/*");
1062         $self->pidl(" * We want the tevent_req_data() protection,");
1063         $self->pidl(" * but don't need 'state', so just pretend we use it");
1064         $self->pidl(" * in order to avoid compiler warnings.");
1065         $self->pidl(" */");
1066         $self->pidl("state->dummy = 0;");
1067         $self->pidl("tevent_req_received(req);");
1068         $self->pidl("return status;");
1069         $self->deindent;
1070         $self->pidl("}");
1071         $self->pidl("");
1072
1073         $self->pidl("tevent_req_received(req);");
1074         $self->pidl("return NT_STATUS_OK;");
1075         $self->deindent;
1076         $self->pidl("}");
1077         $self->pidl("");
1078 }
1079
1080 sub ParsePipeChunkPull_State($$$)
1081 {
1082         my ($self, $t, $cname) = @_;
1083
1084         my $state_str = "struct dcerpc_$cname\_pull_state";
1085         my $done_fn = "dcerpc_$cname\_pull_done";
1086
1087         $self->pidl("$state_str {");
1088         $self->indent;
1089         $self->pidl("struct $cname *chunk;");
1090         $self->deindent;
1091         $self->pidl("};");
1092         $self->pidl("");
1093
1094         $self->pidl("static void $done_fn(struct tevent_req *subreq);");
1095         $self->pidl("");
1096 }
1097
1098 sub ParsePipeChunkPull_Send($$$)
1099 {
1100         my ($self, $t, $cname) = @_;
1101
1102         my $fn_args = "";
1103         my $state_str = "struct dcerpc_$cname\_pull_state";
1104         my $done_fn = "dcerpc_$cname\_pull_done";
1105         my $fn_str = "struct tevent_req *dcerpc_$cname\_pull_send";
1106         my $pad = genpad($fn_str);
1107
1108         $fn_args .= "TALLOC_CTX *mem_ctx";
1109         $fn_args .= ",\n" . $pad . "struct tevent_context *ev";
1110         $fn_args .= ",\n" . $pad . "struct $t->{NAME} *p";
1111
1112         $self->fn_declare("$fn_str($fn_args)");
1113         $self->pidl("{");
1114         $self->indent;
1115         $self->pidl("struct tevent_req *req;");
1116         $self->pidl("$state_str *state;");
1117         $self->pidl("struct tevent_req *subreq;");
1118         $self->pidl("");
1119
1120         $self->pidl("req = tevent_req_create(mem_ctx, &state,");
1121         $self->pidl("\t\t\t$state_str);");
1122         $self->pidl("if (req == NULL) {");
1123         $self->indent;
1124         $self->pidl("return NULL;");
1125         $self->deindent;
1126         $self->pidl("}");
1127
1128         $self->pidl("state->chunk = talloc_zero(state, struct $cname);");
1129         $self->pidl("if (tevent_req_nomem(state->chunk, req)) {");
1130         $self->indent;
1131         $self->pidl("return tevent_req_post(req, ev);");
1132         $self->deindent;
1133         $self->pidl("}");
1134         $self->pidl("");
1135
1136         $self->pidl("subreq = dcerpc_pipe_handle_pull_send(state, ev,");
1137         $self->pidl("\t\t\tp->pc, state->chunk, state->chunk);");
1138         $self->pidl("if (tevent_req_nomem(subreq, req)) {");
1139         $self->indent;
1140         $self->pidl("return tevent_req_post(req, ev);");
1141         $self->deindent;
1142         $self->pidl("}");
1143         $self->pidl("tevent_req_set_callback(subreq, $done_fn, req);");
1144         $self->pidl("");
1145
1146         $self->pidl("return req;");
1147         $self->deindent;
1148         $self->pidl("}");
1149         $self->pidl("");
1150 }
1151
1152 sub ParsePipeChunkPull_Done($$$)
1153 {
1154         my ($self, $t, $cname) = @_;
1155
1156         my $fn_args = "";
1157         my $state_str = "struct dcerpc_$cname\_pull_state";
1158         my $fn_str = "static void dcerpc_$cname\_pull_done";
1159         my $pad = genpad($fn_str);
1160
1161         $fn_args .= "struct tevent_req *subreq";
1162
1163         $self->pidl("$fn_str($fn_args)");
1164         $self->pidl("{");
1165         $self->indent;
1166         $self->pidl("struct tevent_req *req =");
1167         $self->pidl("\ttevent_req_callback_data(subreq,");
1168         $self->pidl("\tstruct tevent_req);");
1169         # unused
1170         #$self->pidl("$state_str *state =");
1171         #$self->pidl("\ttevent_req_data(req,");
1172         #$self->pidl("\t$state_str);");
1173         $self->pidl("NTSTATUS status;");
1174         $self->pidl("");
1175
1176         $self->pidl("status = dcerpc_pipe_handle_pull_recv(subreq);");
1177         $self->pidl("TALLOC_FREE(subreq);");
1178         $self->pidl("if (tevent_req_nterror(req, status)) {");
1179         $self->indent;
1180         $self->pidl("return;");
1181         $self->deindent;
1182         $self->pidl("}");
1183         $self->pidl("");
1184
1185         $self->pidl("tevent_req_done(req);");
1186         $self->deindent;
1187         $self->pidl("}");
1188         $self->pidl("");
1189 }
1190
1191 sub ParsePipeChunkPull_Recv($$$)
1192 {
1193         my ($self, $t, $cname) = @_;
1194
1195         my $fn_args = "";
1196         my $state_str = "struct dcerpc_$cname\_pull_state";
1197         my $fn_str = "NTSTATUS dcerpc_$cname\_pull_recv";
1198         my $pad = genpad($fn_str);
1199
1200         $fn_args .= "struct tevent_req *req";
1201         $fn_args .= ",\n" . $pad . "TALLOC_CTX *mem_ctx";
1202         $fn_args .= ",\n" . $pad . "struct $cname **chunk";
1203
1204         $self->fn_declare("$fn_str($fn_args)");
1205         $self->pidl("{");
1206         $self->indent;
1207         $self->pidl("$state_str *state =");
1208         $self->pidl("\ttevent_req_data(req,");
1209         $self->pidl("\t$state_str);");
1210         $self->pidl("NTSTATUS status;");
1211         $self->pidl("");
1212
1213         $self->pidl("if (tevent_req_is_nterror(req, &status)) {");
1214         $self->indent;
1215         $self->pidl("tevent_req_received(req);");
1216         $self->pidl("return status;");
1217         $self->deindent;
1218         $self->pidl("}");
1219         $self->pidl("");
1220
1221         $self->pidl("*chunk = talloc_move(mem_ctx, &state->chunk);");
1222         $self->pidl("");
1223
1224         $self->pidl("tevent_req_received(req);");
1225         $self->pidl("return NT_STATUS_OK;");
1226         $self->deindent;
1227         $self->pidl("}");
1228         $self->pidl("");
1229 }
1230
1231 sub ParsePipe($$)
1232 {
1233         my ($self, $t) = @_;
1234
1235         my $pipe = $t;
1236         $pipe = $t->{DATA} if ($t->{TYPE} eq "TYPEDEF");
1237         my $struct = $pipe->{DATA};
1238
1239         my $name = "$struct->{NAME}";
1240
1241         $self->ParsePipeCreate($t, $name);
1242
1243         $self->ParsePipeChunkPush_State($t, $name);
1244         $self->ParsePipeChunkPush_Send($t, $name);
1245         $self->ParsePipeChunkPush_Done($t, $name);
1246         $self->ParsePipeChunkPush_Recv($t, $name);
1247
1248         $self->ParsePipeChunkPull_State($t, $name);
1249         $self->ParsePipeChunkPull_Send($t, $name);
1250         $self->ParsePipeChunkPull_Done($t, $name);
1251         $self->ParsePipeChunkPull_Recv($t, $name);
1252         $self->pidl_both("");
1253 }
1254
1255 my %done;
1256
1257 #####################################################################
1258 # parse the interface definitions
1259 sub ParseInterface($$)
1260 {
1261         my ($self, $if) = @_;
1262         my $ifu = uc($if->{NAME});
1263
1264         $self->pidl_hdr("#ifndef _HEADER_RPC_$if->{NAME}");
1265         $self->pidl_hdr("#define _HEADER_RPC_$if->{NAME}");
1266         $self->pidl_hdr("");
1267
1268         if (defined $if->{PROPERTIES}->{uuid}) {
1269                 $self->pidl_hdr("extern const struct ndr_interface_table ndr_table_$if->{NAME};");
1270                 $self->pidl_hdr("");
1271         }
1272
1273         $self->pidl("/* $if->{NAME} - client functions generated by pidl */");
1274         $self->pidl("");
1275
1276         foreach my $t (reverse @{$if->{TYPES}}) {
1277                 next unless Parse::Pidl::Typelist::typeIs($t, "PIPE");
1278
1279                 $self->ParsePipe($t);
1280                 $done{$t->{NAME}} = 1;
1281         }
1282
1283         foreach my $fn (@{$if->{FUNCTIONS}}) {
1284                 next if defined($done{$fn->{NAME}});
1285                 next if has_property($fn, "noopnum");
1286                 next if has_property($fn, "todo");
1287                 $self->ParseFunction($if, $fn);
1288                 $done{$fn->{NAME}} = 1;
1289         }
1290
1291         $self->pidl_hdr("#endif /* _HEADER_RPC_$if->{NAME} */");
1292 }
1293
1294 sub Parse($$$$$$)
1295 {
1296         my($self,$ndr,$header,$ndr_header,$client_header) = @_;
1297
1298         $self->pidl("/* client functions auto-generated by pidl */");
1299         $self->pidl("");
1300         if (is_intree()) {
1301                 $self->pidl("#include \"includes.h\"");
1302         } else {
1303                 $self->pidl("#ifndef _GNU_SOURCE");
1304                 $self->pidl("#define _GNU_SOURCE");
1305                 $self->pidl("#endif");
1306                 $self->pidl("#include <stdio.h>");
1307                 $self->pidl("#include <stdbool.h>");
1308                 $self->pidl("#include <stdlib.h>");
1309                 $self->pidl("#include <stdint.h>");
1310                 $self->pidl("#include <stdarg.h>");
1311                 $self->pidl("#include <string.h>");
1312                 $self->pidl("#include <core/ntstatus.h>");
1313         }
1314         $self->pidl("#include <tevent.h>");
1315         $self->pidl(choose_header("lib/util/tevent_ntstatus.h", "util/tevent_ntstatus.h")."");
1316         $self->pidl("#include \"$ndr_header\"");
1317         $self->pidl("#include \"$client_header\"");
1318         $self->pidl("");
1319
1320         $self->pidl_hdr(choose_header("librpc/rpc/dcerpc.h", "dcerpc.h")."");
1321         $self->pidl_hdr("#include \"$header\"");
1322
1323         foreach my $x (@{$ndr}) {
1324                 ($x->{TYPE} eq "INTERFACE") && $self->ParseInterface($x);
1325         }
1326
1327         return ($self->{res},$self->{res_hdr});
1328 }
1329
1330 1;