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