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