1 /***************************************************************************
2  * LPRng - An Extended Print Spooler System
3  *
4  * Copyright 1988-2003, Patrick Powell, San Diego, CA
5  *     papowell@lprng.com
6  * See LICENSE for conditions of use.
7  *
8  ***************************************************************************/
9 
10 #include "lp.h"
11 
12 #include "accounting.h"
13 #include "errorcodes.h"
14 #include "fileopen.h"
15 #include "getqueue.h"
16 #include "user_auth.h"
17 #include "linksupport.h"
18 #include "sendjob.h"
19 #include "sendauth.h"
20 
21 /**** ENDINCLUDE ****/
22 
23 
24 /***************************************************************************
25  * Commentary:
26  * The protocol used to send a job to a remote RemoteHost_DYN consists of the
27  * following:
28  *
29  * Client                                   Server
30  * \2RemotePrinter_DYNname\n - receive a job
31  *                                          \0  (ack)
32  * \2count controlfilename\n
33  * <count bytes>
34  * \0
35  *                                          \0
36  * \3count datafilename\n
37  * <count bytes>
38  * \0
39  *                                          \0
40  * \3count datafilename\n
41  * <count bytes>
42  * \0
43  *                                          \0
44  * <close connection>
45  *
46  * 1. In order to abort the job transfer,  client sends \1
47  * 2. Anything but a 0 ACK is an error indication
48  *
49  * NB: some spoolers require that the data files be sent first.
50  * The same transfer protocol is followed, but the data files are
51  * send first,  followed by the control file.
52  *
53  * The Send_job() routine will try to transfer a control file
54  * to the remote RemoteHost_DYN.  It does so using the following algorithm.
55  *
56  * 1.  makes a connection (connection timeout)
57  * 2.  sends the \2RemotePrinter_DYN and gets ACK (transfer timeout)
58  * 3.  sends the control file (transfer timeout)
59  * 4.  sends the data files (transfer timeout)
60  *
61  * int Send_job(
62  * 	struct jobfile *job,	- control file
63  * 	int connect_timeout_len,	- timeout on making connection
64  * 	int connect_interval,	- interval between retries
65  * 	int max_connect_interval - maximum connection interval
66  * 	int transfer_timeout    - maximum time to send
67  *
68  * 	RETURNS: 0 if successful, non-zero if not
69  **************************************************************************/
70 
71 static int Send_control( int *sock, struct job *job, struct job *logjob, int transfer_timeout,
72 	int block_fd );
73 static int Send_data_files( int *sock, struct job *job, struct job *logjob,
74 	int transfer_timeout, int block_fd, char *final_filter );
75 
Send_job(struct job * job,struct job * logjob,int connect_timeout_len,int connect_interval,int max_connect_interval,int transfer_timeout,char * final_filter)76 int Send_job( struct job *job, struct job *logjob,
77 	int connect_timeout_len, int connect_interval, int max_connect_interval,
78 	int transfer_timeout, char *final_filter )
79 {
80 	int sock = -1;		/* socket to use */
81 	char *id = 0, *s;
82 	char *real_host = 0, *save_host = 0;
83 	int status = 0, err, errcount = 0, n, len;
84 	char msg[SMALLBUFFER];
85 	char error[LARGEBUFFER], errmsg[SMALLBUFFER];
86 	const struct security *security = 0;
87 	struct line_list info;
88 
89 	/* fix up the control file */
90 	Init_line_list(&info);
91 	if(DEBUGL1)Dump_job("Send_job- starting",job);
92 	Errorcode = 0;
93 	error[0] = 0;
94 
95 
96 	Set_str_value(&job->info,ERROR,0);
97 	Set_flag_value(&job->info,ERROR_TIME,0);
98 	/* send job to the LPD server for the RemotePrinter_DYN */
99 
100 	id = Find_str_value( &job->info,IDENTIFIER);
101 	if( id == 0 ) id = Find_str_value( &job->info,XXCFTRANSFERNAME);
102 	DEBUG3("Send_job: '%s'->%s@%s,connect(timeout %d,interval %d)",
103 		id, RemotePrinter_DYN, RemoteHost_DYN,
104 			connect_timeout_len, connect_interval );
105 
106 	/* determine authentication type to use */
107 	security = Fix_send_auth(0,&info,job, error, sizeof(error) );
108 	if( error[0] ){
109 		status = JFAIL;
110 		Set_str_value(&job->info,ERROR,error);
111 		Set_nz_flag_value(&job->info,ERROR_TIME,time(0));
112 		error[0] = 0;
113 		goto error;
114 	}
115 	if( final_filter && (security || Send_block_format_DYN) ){
116 		status = JABORT;
117 		Set_str_value(&job->info,ERROR,
118 			"Cannot have user filter with secure or block format transfer");
119 		Set_nz_flag_value(&job->info,ERROR_TIME,time(0));
120 		goto error;
121 	}
122 
123 	setstatus(logjob,
124 	"sending job '%s' to %s@%s",
125 		id, RemotePrinter_DYN, RemoteHost_DYN );
126 
127  retry_connect:
128 	error[0] = 0;
129 	Set_str_value(&job->info,ERROR,0);
130 	Set_flag_value(&job->info,ERROR_TIME,0);
131 	setstatus(logjob, "connecting to '%s', attempt %d",
132 		RemoteHost_DYN, errcount+1 );
133 	if( (Is_server || errcount) && Network_connect_grace_DYN > 0 ){
134 		plp_sleep( Network_connect_grace_DYN );
135 	}
136 
137 	errno = 0;
138 
139 	errmsg[0] = 0;
140 	sock = Link_open_list( RemoteHost_DYN,
141 		&real_host, connect_timeout_len, 0, Unix_socket_path_DYN, errmsg, sizeof(errmsg) );
142 	err = errno;
143 
144 	DEBUG4("Send_job: socket %d", sock );
145 	if( sock < 0 ){
146 		++errcount;
147 		status = LINK_OPEN_FAIL;
148 		msg[0] = 0;
149 		if( !Is_server ){
150 			plp_snprintf( msg, sizeof(msg),
151 			"\nMake sure the remote host supports the LPD protocol");
152 			if( geteuid() && getuid() ){
153 				int v = safestrlen(msg);
154 				plp_snprintf( msg+v, sizeof(msg)-v,
155 				"\nand accepts connections from this host and from non-privileged (>1023) ports");
156 			}
157 		}
158 		plp_snprintf( error, sizeof(error)-2,
159 			"cannot open connection to %s - %s%s", RemoteHost_DYN,
160 				errmsg[0]?errmsg:(err?Errormsg(err):"bad or missing hostname?"), msg );
161 		if( Is_server && Retry_NOLINK_DYN ){
162 			if( connect_interval > 0 ){
163 				n = (connect_interval * (1 << (errcount - 1)));
164 				if( max_connect_interval && n > max_connect_interval ){
165 					n = max_connect_interval;
166 				}
167 				if( n > 0 ){
168 					setstatus(logjob,
169 					_("sleeping %d secs before retry, starting sleep"),n );
170 					plp_sleep( n );
171 				}
172 			}
173 			goto retry_connect;
174 		}
175 		setstatus(logjob, "%s", error);
176 		goto error;
177 	}
178 	save_host = safestrdup(RemoteHost_DYN,__FILE__,__LINE__);
179 	Set_DYN(&RemoteHost_DYN, real_host );
180 	if( real_host ) free( real_host );
181 	setstatus(logjob, "connected to '%s'", RemoteHost_DYN );
182 
183 	if( security && security->client_connect ){
184 		status = security->client_connect( job, &sock,
185 			transfer_timeout,
186 			error, sizeof(error),
187 			security, &info );
188 		if( status ) goto error;
189 	}
190 	if( security && security->client_send ){
191 		status = Send_auth_transfer( &sock, transfer_timeout,
192 			job, logjob, error, sizeof(error)-1, 0, security, &info );
193 	} else if( Send_block_format_DYN ){
194 		status = Send_block( &sock, job, logjob, transfer_timeout );
195 	} else {
196 		status = Send_normal( &sock, job, logjob, transfer_timeout, 0, final_filter );
197 	}
198 	DEBUG2("Send_job: after sending, status %d, error '%s'",
199 		status, error );
200 	if( status ) goto error;
201 
202 	setstatus(logjob, "done job '%s' transfer to %s@%s",
203 		id, RemotePrinter_DYN, RemoteHost_DYN );
204 
205  error:
206 
207 	if( sock >= 0 ) sock = Shutdown_or_close(sock);
208 	if( status ){
209 		if( (s = Find_str_value(&job->info,ERROR )) ){
210 			setstatus(logjob, "job '%s' transfer to %s@%s failed\n  %s",
211 				id, RemotePrinter_DYN, RemoteHost_DYN, s );
212 			Set_nz_flag_value(&job->info,ERROR_TIME,time(0));
213 		}
214 		DEBUG2("Send_job: sock is %d", sock);
215 		if( sock >= 0 ){
216 			len = 0;
217 			msg[0] = 0;
218 			n = 0;
219 			while( len < (int)sizeof(msg)-1
220 				&& (n = Read_fd_len_timeout(Send_job_rw_timeout_DYN,
221 					sock,msg+len,sizeof(msg)-len-1)) > 0 ){
222 				msg[len+n] = 0;
223 				DEBUG2("Send_job: read %d, '%s'", n, msg);
224 				while( (s = safestrchr(msg,'\n')) ){
225 					*s++ = 0;
226 					setstatus(logjob, "error msg: '%s'", msg );
227 					memmove(msg,s,safestrlen(s)+1);
228 				}
229 				len = safestrlen(msg);
230 			}
231 			DEBUG2("Send_job: read %d, '%s'", n, msg);
232 			if( len ) setstatus(logjob, "error msg: '%s'", msg );
233 		}
234 	}
235 	if( sock >= 0 ) close(sock); sock = -1;
236 	if( save_host ){
237 		Set_DYN(&RemoteHost_DYN,save_host);
238 		free(save_host); save_host = 0;
239 	}
240 	Free_line_list(&info);
241 	return( status );
242 }
243 
244 /***************************************************************************
245  * int Send_normal(
246  * 	int sock,					- socket to use
247  * 	struct job *job, struct job *logjob,	- control file
248  * 	int transfer_timeout,		- transfer timeout
249  * 	)						- acknowlegement status
250  *
251  *  1. send the \2RemotePrinter_DYN\n string to the remote RemoteHost_DYN, wait for an ACK
252  *
253  *  2. if control file first, send the control file:
254  *         send \3count cfname\n
255  *         get back <0> ack
256  *         send 'count' file bytes
257  *         send <0> term
258  *         get back <0> ack
259  *  3. for each data file
260  *         send the \4count dfname\n
261  *             Note: count is 0 if file is filter
262  *         get back <0> ack
263  *         send 'count' file bytes
264  *             Close socket and finish if filter
265  *         send <0> term
266  *         get back <0> ack
267  *   4. If control file last, send the control file as in step 2.
268  *
269  *
270  * If the block_fd parameter is non-zero, we write out the
271  * control and data information to a file instead.
272  *
273  ***************************************************************************/
274 
Send_normal(int * sock,struct job * job,struct job * logjob,int transfer_timeout,int block_fd,char * final_filter)275 int Send_normal( int *sock, struct job *job, struct job *logjob,
276 	int transfer_timeout, int block_fd, char *final_filter )
277 {
278 	char status = 0, *id, *transfername;
279 	char line[SMALLBUFFER];
280 	char error[SMALLBUFFER];
281 	int ack;
282 
283 	DEBUG3("Send_normal: send_data_first %d, sock %d, block_fd %d",
284 		Send_data_first_DYN, *sock, block_fd );
285 
286 	id = Find_str_value(&job->info,IDENTIFIER);
287 	transfername = Find_str_value(&job->info,XXCFTRANSFERNAME);
288 
289 	if( !block_fd ){
290 		setstatus(logjob, "requesting printer %s@%s",
291 			RemotePrinter_DYN, RemoteHost_DYN );
292 		plp_snprintf( line, sizeof(line), "%c%s\n",
293 			REQ_RECV, RemotePrinter_DYN );
294 		ack = 0;
295 		if( (status = Link_send( RemoteHost_DYN, sock, transfer_timeout,
296 			line, safestrlen(line), &ack ) )){
297 			char *v;
298 			if( (v = safestrchr(line,'\n')) ) *v = 0;
299 			if( ack ){
300 				plp_snprintf(error,sizeof(error),
301 					"error '%s' with ack '%s'\n  sending str '%s' to %s@%s",
302 					Link_err_str(status), Ack_err_str(ack), line,
303 					RemotePrinter_DYN, RemoteHost_DYN );
304 			} else {
305 				plp_snprintf(error,sizeof(error),
306 					"error '%s'\n  sending str '%s' to %s@%s",
307 					Link_err_str(status), line,
308 					RemotePrinter_DYN, RemoteHost_DYN );
309 			}
310 			Set_str_value(&job->info,ERROR,error);
311 			Set_nz_flag_value(&job->info,ERROR_TIME,time(0));
312 			return(status);
313 		}
314 	}
315 
316 	if( !block_fd && Send_data_first_DYN ){
317 		status = Send_data_files( sock, job, logjob, transfer_timeout, block_fd, final_filter );
318 		if( !status ) status = Send_control(
319 			sock, job, logjob, transfer_timeout, block_fd );
320 	} else {
321 		status = Send_control( sock, job, logjob, transfer_timeout, block_fd );
322 		if( !status ) status = Send_data_files(
323 			sock, job, logjob, transfer_timeout, block_fd, final_filter );
324 	}
325 	return(status);
326 }
327 
Send_control(int * sock,struct job * job,struct job * logjob,int transfer_timeout,int block_fd)328 static int Send_control( int *sock, struct job *job, struct job *logjob, int transfer_timeout,
329 	int block_fd )
330 {
331 	char msg[SMALLBUFFER];
332 	char error[SMALLBUFFER];
333 	int status = 0, size, ack, err;
334 	char *cf = 0, *transfername = 0, *s;
335 	/*
336 	 * get the total length of the control file
337 	 */
338 
339 	if( !(cf = Find_str_value(&job->info,CF_OUT_IMAGE)) ){
340 		Errorcode = JABORT;
341 		fatal(LOG_ERR, "Send_control: LOGIC ERROR! missing CF_OUT_IMAGE");
342 	}
343 	size = safestrlen(cf);
344 	transfername = Find_str_value(&job->info,XXCFTRANSFERNAME);
345 
346 	DEBUG3( "Send_control: '%s' is %d bytes, sock %d, block_fd %d, cf '%s'",
347 		transfername, size, *sock, block_fd, cf );
348 	if( !block_fd ){
349 		setstatus(logjob, "sending control file '%s' to %s@%s",
350 		transfername, RemotePrinter_DYN, RemoteHost_DYN );
351 	}
352 
353 	ack = 0;
354 	errno = 0;
355 	error[0] = 0;
356 	plp_snprintf( msg, sizeof(msg), "%c%d %s\n",
357 		CONTROL_FILE, size, transfername);
358 	if( !block_fd ){
359 		if( (status = Link_send( RemoteHost_DYN, sock, transfer_timeout,
360 			msg, safestrlen(msg), &ack )) ){
361 			if( (s = safestrchr(msg,'\n')) ) *s = 0;
362 			if( ack ){
363 				plp_snprintf(error,sizeof(error),
364 				"error '%s' with ack '%s'\n  sending str '%s' to %s@%s",
365 				Link_err_str(status), Ack_err_str(ack), msg,
366 				RemotePrinter_DYN, RemoteHost_DYN );
367 			} else {
368 				plp_snprintf(error,sizeof(error),
369 				"error '%s'\n  sending str '%s' to %s@%s",
370 				Link_err_str(status), msg, RemotePrinter_DYN, RemoteHost_DYN );
371 			}
372 			Set_str_value(&job->info,ERROR,error);
373 			Set_nz_flag_value(&job->info,ERROR_TIME,time(0));
374 			status = JFAIL;
375 			goto error;
376 		}
377 	} else {
378 		if( Write_fd_str( block_fd, msg ) < 0 ){
379 			goto write_error;
380 		}
381 	}
382 
383 	/*
384 	 * send the control file
385 	 */
386 	errno = 0;
387 	if( block_fd == 0 ){
388 		/* we include the 0 at the end */
389 		ack = 0;
390 		if( (status = Link_send( RemoteHost_DYN, sock, transfer_timeout,
391 			cf,size+1,&ack )) ){
392 			if( ack ){
393 				plp_snprintf(error,sizeof(error),
394 				"error '%s' with ack '%s'\n  sending control file '%s' to %s@%s",
395 				Link_err_str(status), Ack_err_str(ack), transfername,
396 				RemotePrinter_DYN, RemoteHost_DYN );
397 			} else {
398 				plp_snprintf(error,sizeof(error),
399 					"error '%s'\n  sending control file '%s' to %s@%s",
400 					Link_err_str(status), transfername,
401 					RemotePrinter_DYN, RemoteHost_DYN );
402 			}
403 			Set_str_value(&job->info,ERROR,error);
404 			Set_nz_flag_value(&job->info,ERROR_TIME,time(0));
405 			status = JFAIL;
406 			goto error;
407 		}
408 		DEBUG3( "Send_control: control file '%s' sent", transfername );
409 		setstatus(logjob, "completed sending '%s' to %s@%s",
410 			transfername, RemotePrinter_DYN, RemoteHost_DYN );
411 	} else {
412 		if( Write_fd_str( block_fd, cf ) < 0 ){
413 			goto write_error;
414 		}
415 	}
416 	status = 0;
417 	goto error;
418 
419  write_error:
420 	err = errno;
421 	plp_snprintf(error,sizeof(error),
422 		"job '%s' write to temporary file failed '%s'",
423 		transfername, Errormsg( err ) );
424 	Set_str_value(&job->info,ERROR,error);
425 	Set_nz_flag_value(&job->info,ERROR_TIME,time(0));
426 	status = JFAIL;
427  error:
428 	return(status);
429 }
430 
431 
Send_data_files(int * sock,struct job * job,struct job * logjob,int transfer_timeout,int block_fd,char * final_filter)432 static int Send_data_files( int *sock, struct job *job, struct job *logjob,
433 	int transfer_timeout, int block_fd, char *final_filter )
434 {
435 	int count, fd, err, status = 0, ack;
436 	double size;
437 	struct line_list *lp;
438 	const char *openname, *transfername, *id;
439 	char *s;
440 	char msg[SMALLBUFFER];
441 	char error[SMALLBUFFER];
442 	struct stat statb;
443 
444 	DEBUG3( "Send_data_files: data file count '%d'", job->datafiles.count );
445 	id = Find_str_value(&job->info,IDENTIFIER);
446 	if( id == 0 ) id = Find_str_value(&job->info,XXCFTRANSFERNAME);
447 	for( count = 0; count < job->datafiles.count; ++count ){
448 		lp = (void *)job->datafiles.list[count];
449 		if(DEBUGL3)Dump_line_list("Send_data_files - entries",lp);
450 		transfername = Find_str_value(lp,DFTRANSFERNAME);
451 		openname = Find_str_value(lp,OPENNAME);
452 		if( !openname ) openname = transfername;
453 		DEBUG3("Send_data_files: opening file '%s', transfername '%s'",
454 			openname, transfername );
455 
456 		/*
457 		 * open file as user; we should be running as user
458 		 */
459 		size = 0;
460 		if( !strcmp(openname,"-") ){
461 			openname = "(STDIN)";
462 			fd = 0;
463 			size = 0;
464 		} else {
465 			fd = Checkread( openname, &statb );
466 			if( fd < 0 ){
467 				status = JFAILNORETRY;
468 				plp_snprintf(error,sizeof(error),
469 					"cannot open '%s' - '%s'", openname, Errormsg(errno) );
470 				Set_str_value(&job->info,ERROR,error);
471 				Set_nz_flag_value(&job->info,ERROR_TIME,time(0));
472 				goto error;
473 			}
474 			if( statb.st_size == 0 ){
475 				plp_snprintf(error,sizeof(error),
476 				"zero length file '%s'", transfername );
477 				status = JABORT;
478 				Set_str_value(&job->info,ERROR,error);
479 				Set_nz_flag_value(&job->info,ERROR_TIME,time(0));
480 				goto error;
481 			}
482 			size = statb.st_size;
483 		}
484 		if( count == job->datafiles.count -1 && final_filter ){
485 			size = 0;
486 		}
487 
488 		DEBUG3( "Send_data_files: openname '%s', fd %d, size %0.0f",
489 			openname, fd, size );
490 		/*
491 		 * send the data file name line
492 		 */
493 		plp_snprintf( msg, sizeof(msg), "%c%0.0f %s\n",
494 				DATA_FILE, size, transfername );
495 		if( block_fd == 0 ){
496 			setstatus(logjob, "sending data file '%s' to %s@%s", transfername,
497 				RemotePrinter_DYN, RemoteHost_DYN );
498 			DEBUG3("Send_data_files: data file msg '%s'", msg );
499 			errno = 0;
500 			if( (status = Link_send( RemoteHost_DYN, sock, transfer_timeout,
501 				msg, safestrlen(msg), &ack )) ){
502 				if( (s = safestrchr(msg,'\n')) ) *s = 0;
503 				if( ack ){
504 					plp_snprintf(error,sizeof(error),
505 					"error '%s' with ack '%s'\n  sending str '%s' to %s@%s",
506 					Link_err_str(status), Ack_err_str(ack), msg,
507 					RemotePrinter_DYN, RemoteHost_DYN );
508 				} else {
509 					plp_snprintf(error,sizeof(error),
510 					"error '%s'\n  sending str '%s' to %s@%s",
511 					Link_err_str(status), msg, RemotePrinter_DYN, RemoteHost_DYN );
512 				}
513 				Set_str_value(&job->info,ERROR,error);
514 				Set_nz_flag_value(&job->info,ERROR_TIME,time(0));
515 				goto error;
516 			}
517 
518 			/*
519 			 * send the data files content
520 			 */
521 			DEBUG3("Send_data_files: transfering '%s', fd %d", openname, fd );
522 			ack = 0;
523 			if( count == job->datafiles.count-1 && final_filter ){
524 				status = Filter_file( transfer_timeout, fd, *sock, "UserFilter",
525 					final_filter, Filter_options_DYN, job, 0, 1 );
526 				DEBUG3("Send_data_files: final_filter '%s' status %d", final_filter, status );
527 				close(fd); fd = 0;
528 			} else {
529 				status = Link_copy( RemoteHost_DYN, sock, 0, transfer_timeout,
530 						openname, fd, size );
531 			}
532 			/* special case - cannot read error code from other end */
533 			if( fd == 0 ){
534 				close(*sock);
535 				*sock = -1;
536 			}
537 			if( status
538 				|| ( fd !=0 && (status = Link_send( RemoteHost_DYN,sock,
539 					transfer_timeout,"",1,&ack )) ) ){
540 				if( ack ){
541 					plp_snprintf(error,sizeof(error),
542 					"error '%s' with ack '%s'\n  sending data file '%s' to %s@%s",
543 					Link_err_str(status), Ack_err_str(ack), transfername,
544 					RemotePrinter_DYN, RemoteHost_DYN );
545 				} else {
546 					plp_snprintf(error,sizeof(error),
547 					"error '%s'\n  sending data file '%s' to %s@%s",
548 					Link_err_str(status), transfername,
549 					RemotePrinter_DYN, RemoteHost_DYN );
550 				}
551 				Set_str_value(&job->info,ERROR,error);
552 				Set_nz_flag_value(&job->info,ERROR_TIME,time(0));
553 				goto error;
554 			}
555 			setstatus(logjob, "completed sending '%s' to %s@%s",
556 				transfername, RemotePrinter_DYN, RemoteHost_DYN );
557 		} else {
558 			double total;
559 			int len;
560 
561 			if( Write_fd_str( block_fd, msg ) < 0 ){
562 				goto write_error;
563 			}
564 			/* now we need to read the file and transfer it */
565 			total = 0;
566 			while( total < size && (len = Read_fd_len_timeout(Send_job_rw_timeout_DYN,
567 					fd, msg, sizeof(msg))) > 0 ){
568 				if( write( block_fd, msg, len ) < 0 ){
569 					goto write_error;
570 				}
571 				total += len;
572 			}
573 			if( total != size ){
574 				plp_snprintf(error,sizeof(error),
575 					"job '%s' did not copy all of '%s'",
576 					id, transfername );
577 				status = JFAIL;
578 				Set_str_value(&job->info,ERROR,error);
579 				Set_nz_flag_value(&job->info,ERROR_TIME,time(0));
580 				goto error;
581 			}
582 		}
583 		close(fd); fd = -1;
584 	}
585 	goto error;
586 
587  write_error:
588 	err = errno;
589 	plp_snprintf(error,sizeof(error),
590 		"job '%s' write to temporary file failed '%s'",
591 		id, Errormsg( err ) );
592 	Set_str_value(&job->info,ERROR,error);
593 	Set_nz_flag_value(&job->info,ERROR_TIME,time(0));
594 	status = JFAIL;
595 
596  error:
597 	return(status);
598 }
599 
600 /***************************************************************************
601  * int Send_block(
602  * 	char *RemoteHost_DYN,				- RemoteHost_DYN name
603  * 	char *RemotePrinter_DYN,			- RemotePrinter_DYN name
604  * 	char *dpathname *dpath  - spool directory pathname
605  * 	int *sock,					- socket to use
606  * 	struct job *job, struct job *logjob,	- control file
607  * 	int transfer_timeout,		- transfer timeout
608  * 	)						- acknowlegement status
609  *
610  *  1. Get a temporary file
611  *  2. Generate the compressed data files - this has the format
612  *       \3count cfname\n
613  *       [count control file bytes]
614  *       \4count dfname\n
615  *       [count data file bytes]
616  *
617  *  3. send the \6RemotePrinter_DYN size\n
618  *     string to the remote RemoteHost_DYN, wait for an ACK
619  *
620  *  4. send the compressed data files
621  *       wait for an ACK
622  *
623  ***************************************************************************/
624 
Send_block(int * sock,struct job * job,struct job * logjob,int transfer_timeout)625 int Send_block( int *sock, struct job *job, struct job *logjob, int transfer_timeout )
626 {
627 	int tempfd;			/* temp file for data transfer */
628 	char msg[SMALLBUFFER];	/* buffer */
629 	char error[SMALLBUFFER];	/* buffer */
630 	struct stat statb;
631 	double size;				/* ACME! The best... */
632 	int status = 0;				/* job status */
633 	int ack;
634 	char *id, *transfername, *tempfile;
635 
636 	error[0] = 0;
637 	id = Find_str_value(&job->info,IDENTIFIER);
638 	transfername = Find_str_value(&job->info,XXCFTRANSFERNAME);
639 	if( id == 0 ) id = transfername;
640 
641 	tempfd = Make_temp_fd( &tempfile );
642 	DEBUG1("Send_block: sending '%s' to '%s'", id, tempfile );
643 
644 	status = Send_normal( &tempfd, job, logjob, transfer_timeout, tempfd, 0 );
645 
646 	DEBUG1("Send_block: sendnormal of '%s' returned '%s'", id, Server_status(status) );
647 	if( status ) return( status );
648 
649 	/* rewind the file */
650 	if( lseek( tempfd, 0, SEEK_SET ) == -1 ){
651 		Errorcode = JFAIL;
652 		logerr_die(LOG_INFO, "Send_files: lseek tempfd failed" );
653 	}
654 	/* now we have the copy, we need to send the control message */
655 	if( fstat( tempfd, &statb ) ){
656 		Errorcode = JFAIL;
657 		logerr_die(LOG_INFO, "Send_files: fstat tempfd failed" );
658 	}
659 	size = statb.st_size;
660 
661 	/* now we know the size */
662 	DEBUG3("Send_block: size %0.0f", size );
663 	setstatus(logjob, "sending job '%s' to %s@%s, block transfer",
664 		id, RemotePrinter_DYN, RemoteHost_DYN );
665 	plp_snprintf( msg, sizeof(msg), "%c%s %0.0f\n",
666 		REQ_BLOCK, RemotePrinter_DYN, size );
667 	DEBUG3("Send_block: sending '%s'", msg );
668 	status = Link_send( RemoteHost_DYN, sock, transfer_timeout,
669 		msg, safestrlen(msg), &ack );
670 	DEBUG3("Send_block: status '%s'", Link_err_str(status) );
671 	if( status ){
672 		char *v;
673 		if( (v = safestrchr(msg,'\n')) ) *v = 0;
674 		if( ack ){
675 			plp_snprintf(error,sizeof(error),
676 			"error '%s' with ack '%s'\n  sending str '%s' to %s@%s",
677 			Link_err_str(status), Ack_err_str(ack), msg,
678 			RemotePrinter_DYN, RemoteHost_DYN );
679 		} else {
680 			plp_snprintf(error,sizeof(error),
681 			"error '%s'\n  sending str '%s' to %s@%s",
682 			Link_err_str(status), msg, RemotePrinter_DYN, RemoteHost_DYN );
683 		}
684 		Set_str_value(&job->info,ERROR,error);
685 		Set_nz_flag_value(&job->info,ERROR_TIME,time(0));
686 		return(status);
687 	}
688 
689 	/* now we send the data file, followed by a 0 */
690 	DEBUG3("Send_block: sending data" );
691 	ack = 0;
692 	status = Link_copy( RemoteHost_DYN, sock, 0, transfer_timeout,
693 		transfername, tempfd, size );
694 	DEBUG3("Send_block: status '%s'", Link_err_str(status) );
695 	if( status == 0 ){
696 		status = Link_send( RemoteHost_DYN,sock,transfer_timeout,"",1,&ack );
697 		DEBUG3("Send_block: ack status '%s'", Link_err_str(status) );
698 	}
699 	if( status ){
700 		char *v;
701 		if( (v = safestrchr(msg,'\n')) ) *v = 0;
702 		if( ack ){
703 			plp_snprintf(error,sizeof(error),
704 				"error '%s' with ack '%s'\n  sending block file '%s' to %s@%s",
705 				Link_err_str(status), Ack_err_str(ack), id,
706 				RemotePrinter_DYN, RemoteHost_DYN );
707 		} else {
708 			plp_snprintf(error,sizeof(error),
709 				"error '%s'\n  sending block file '%s' to %s@%s",
710 				Link_err_str(status), id, RemotePrinter_DYN, RemoteHost_DYN );
711 		}
712 		Set_str_value(&job->info,ERROR,error);
713 		Set_nz_flag_value(&job->info,ERROR_TIME,time(0));
714 		return(status);
715 	} else {
716 		setstatus(logjob, "completed sending '%s' to %s@%s",
717 			id, RemotePrinter_DYN, RemoteHost_DYN );
718 	}
719 	close( tempfd ); tempfd = -1;
720 	return( status );
721 }
722 
723