29 |
#define obstack_chunk_free free |
#define obstack_chunk_free free |
30 |
#include <obstack.h> |
#include <obstack.h> |
31 |
|
|
32 |
static int transfer_command(void *, void *, MESSAGE *, char *); |
static int transfer_command(MESSAGE *, char *); |
33 |
static void process_command(void *, void *, MESSAGE *, char *, int); |
static int process_command(MESSAGE *, char *); |
34 |
static void transfer_header(void *, void *, LIST *); |
static void transfer_header(LIST *); |
35 |
static void transfer_body(void *, void *, MESSAGE *); |
static void transfer_body(MESSAGE *); |
36 |
static void process_data(void *, void *, MESSAGE *); |
static void process_data(MESSAGE *); |
37 |
|
|
38 |
|
|
39 |
/* Collect and send headers */ |
/* Collect and send headers */ |
86 |
} |
} |
87 |
|
|
88 |
static void |
static void |
89 |
collect_headers(void *sd_client, MESSAGE *msg) |
collect_headers(MESSAGE *msg) |
90 |
{ |
{ |
91 |
char buf[LINEBUFFER+1]; |
char buf[LINEBUFFER+1]; |
92 |
char *line = NULL; |
char *line = NULL; |
93 |
|
|
94 |
while (recvline(SERVER, sd_client, buf, LINEBUFFER)) { |
while (recvline(SERVER, remote_client, buf, sizeof(buf) - 1)) { |
95 |
remcrlf(buf); |
remcrlf(buf); |
96 |
if (isspace(buf[0])) { |
if (isspace(buf[0])) { |
97 |
if (!line) |
if (!line) |
182 |
#define ST_DONE 3 |
#define ST_DONE 3 |
183 |
|
|
184 |
static void |
static void |
185 |
collect_body(void *sd_client, MESSAGE *msg) |
collect_body(MESSAGE *msg) |
186 |
{ |
{ |
187 |
int nread; |
int nread; |
188 |
char buf[LINEBUFFER+1]; |
char buf[LINEBUFFER+1]; |
197 |
|
|
198 |
obstack_init (&stk); |
obstack_init (&stk); |
199 |
while (state != ST_DONE |
while (state != ST_DONE |
200 |
&& (nread = recvline(SERVER, sd_client, buf, LINEBUFFER))) { |
&& (nread = recvline(SERVER, remote_client, |
201 |
|
buf, sizeof(buf) - 1))) { |
202 |
if (strncmp(buf, "."CRLF, 3) == 0) /* EOM */ |
if (strncmp(buf, "."CRLF, 3) == 0) /* EOM */ |
203 |
break; |
break; |
204 |
|
|
273 |
*******************/ |
*******************/ |
274 |
|
|
275 |
void |
void |
276 |
smtp_session(void *sd_client, void *sd_server) |
smtp_session() |
277 |
{ |
{ |
278 |
char command[LINEBUFFER+1]; |
char command[LINEBUFFER+1]; |
279 |
MESSAGE msg; |
MESSAGE msg; |
283 |
*/ |
*/ |
284 |
|
|
285 |
info(VERBOSE, _("Transferring message(s)...")); |
info(VERBOSE, _("Transferring message(s)...")); |
286 |
get_response_smtp(CLIENT, sd_server, command, LINEBUFFER); |
get_response_smtp(CLIENT, remote_server, command, sizeof(command) - 1); |
287 |
|
|
288 |
if (strncmp(command, "220 ", 4) == 0 |
if (strncmp(command, "220 ", 4) == 0 |
289 |
&& strstr(command, version) == 0) { |
&& strstr(command, version) == 0) { |
291 |
char *banner_ptr = 0; |
char *banner_ptr = 0; |
292 |
char host[65]; |
char host[65]; |
293 |
char banner_backup[LINEBUFFER+1]; |
char banner_backup[LINEBUFFER+1]; |
294 |
|
|
295 |
safe_strcpy(banner_backup, command); |
safe_strcpy(banner_backup, command); |
296 |
|
|
297 |
if ((banner_ptr = strchr(banner_backup, ' '))) { |
if ((banner_ptr = strchr(banner_backup, ' '))) { |
303 |
banner_ptr++; |
banner_ptr++; |
304 |
} while (*banner_ptr != ' '); |
} while (*banner_ptr != ' '); |
305 |
banner_ptr++; |
banner_ptr++; |
306 |
snprintf(command, LINEBUFFER, |
snprintf(command, sizeof command, |
307 |
"220 %s (%s) %s", host, version, banner_ptr); |
"220 %s (%s) %s", host, version, banner_ptr); |
308 |
} |
} |
309 |
} |
} |
310 |
swrite(SERVER, sd_client, command); |
swrite(SERVER, remote_client, command); |
311 |
|
|
312 |
/* |
/* |
313 |
Then process the commands... |
Then process the commands... |
314 |
*/ |
*/ |
315 |
|
|
316 |
message_init(&msg); |
message_init(&msg); |
317 |
while (recvline(SERVER, sd_client, command, LINEBUFFER)) { |
while (recvline(SERVER, remote_client, command, sizeof(command) - 1)) { |
318 |
process_command(sd_client, sd_server, &msg, |
if (process_command(&msg, command)) |
319 |
command, LINEBUFFER); |
continue; |
320 |
|
|
|
sd_client = remote_client; |
|
|
sd_server = remote_server; |
|
|
|
|
321 |
if (topt & T_ERROR) |
if (topt & T_ERROR) |
322 |
break; |
break; |
323 |
if (strlen(command) == 0) |
|
324 |
continue; |
if (transfer_command(&msg, command) == 0) |
|
|
|
|
if (transfer_command(sd_client, sd_server, &msg, command) == 0) |
|
325 |
break; |
break; |
326 |
} |
} |
327 |
|
|
354 |
list_append(msg->commands, asc); |
list_append(msg->commands, asc); |
355 |
} |
} |
356 |
|
|
357 |
static void |
static int |
358 |
process_command(void *sd_client, void *sd_server, MESSAGE *msg, |
handle_starttls(char *command) |
|
char *command, int size) |
|
359 |
{ |
{ |
|
char buf[LINEBUFFER+1]; |
|
|
safe_strcpy(buf, command); /* make a back-up */ |
|
|
save_command(msg, buf); |
|
|
|
|
|
change_to_lower(buf); |
|
|
|
|
|
if (strncmp(buf, "starttls", 8) == 0) { |
|
|
|
|
360 |
#ifdef USE_SSL |
#ifdef USE_SSL |
361 |
if (topt & T_SSL_FINISHED) { |
if (topt & T_SSL_FINISHED) { |
362 |
if (topt & T_SSL_ONEWAY) |
if (topt & T_SSL_ONEWAY) |
363 |
swrite(SERVER, sd_client, "503 5.0.0 TLS (ONEWAY) already started"CRLF); |
swrite(SERVER, remote_client, |
364 |
else |
"503 5.0.0 TLS (ONEWAY) already started"CRLF); |
365 |
swrite(SERVER, sd_client, "503 5.0.0 TLS already started"CRLF); |
else |
366 |
strncpy(command, "", 1); |
swrite(SERVER, remote_client, |
367 |
return; |
"503 5.0.0 TLS already started"CRLF); |
368 |
} else if (!(topt & T_STARTTLS) || !(topt & T_SSL)) { |
return 1; |
369 |
swrite(SERVER, sd_client, "503 5.5.0 TLS not available"CRLF); |
} else if (!(topt & T_STARTTLS) || !(topt & T_SSL)) { |
370 |
strncpy(command, "", 1); |
swrite(SERVER, remote_client, "503 5.5.0 TLS not available"CRLF); |
371 |
return; |
return 1; |
372 |
} |
} |
373 |
|
|
374 |
/* |
/* |
375 |
Make the TLS/SSL connection with ESMTP server. |
Make the TLS/SSL connection with ESMTP server. |
376 |
*/ |
*/ |
377 |
|
|
378 |
info(NORMAL, _("Using the TLS/SSL encryption...")); |
info(NORMAL, _("Using the TLS/SSL encryption...")); |
379 |
|
|
380 |
if (!(topt & T_LOCAL_MTA)) { |
if (!(topt & T_LOCAL_MTA)) { |
381 |
char reply[LINEBUFFER+1]; |
char reply[LINEBUFFER+1]; |
382 |
swrite(CLIENT, sd_server, "STARTTLS"CRLF); |
swrite(CLIENT, remote_server, "STARTTLS"CRLF); |
383 |
get_response_smtp(CLIENT, sd_server, |
|
384 |
reply, LINEBUFFER); |
get_response_smtp(CLIENT, remote_server, reply, |
385 |
|
sizeof(reply) - 1); |
|
if (!isdigit((unsigned char)reply[0]) |
|
|
|| (unsigned char)reply[0] > '3') { |
|
|
remcrlf(reply); |
|
|
info(VERBOSE, _("WARNING: %s"), reply); |
|
|
anubis_error(HARD, _("STARTTLS command failed.")); |
|
|
return; |
|
|
} |
|
386 |
|
|
387 |
secure.client = start_ssl_client((int)sd_server); |
if (!isdigit((unsigned char)reply[0]) |
388 |
if (!secure.client || (topt & T_ERROR)) |
|| (unsigned char)reply[0] > '3') { |
389 |
return; |
remcrlf(reply); |
390 |
sd_server = remote_server = (void *)secure.client; |
info(VERBOSE, _("WARNING: %s"), reply); |
391 |
|
anubis_error(HARD, _("STARTTLS command failed.")); |
392 |
|
return 0; |
393 |
} |
} |
394 |
|
|
395 |
/* |
secure.client = start_ssl_client((int)remote_server); |
396 |
Make the TLS/SSL connection with SMTP client |
if (!secure.client || (topt & T_ERROR)) |
397 |
(client connected with the Tunnel). |
return 0; |
398 |
*/ |
remote_server = (void *)secure.client; |
399 |
|
} |
400 |
|
|
401 |
if (secure.cert == 0) |
/* |
402 |
secure.cert = allocbuf(DEFAULT_SSL_PEM, MAXPATHLEN); |
Make the TLS/SSL connection with SMTP client |
403 |
if (check_filename(secure.cert, NULL) == 0) |
(client connected with the Tunnel). |
404 |
return; |
*/ |
|
if (secure.key == 0) |
|
|
secure.key = allocbuf(secure.cert, MAXPATHLEN); |
|
|
else { |
|
|
if (check_filename(secure.key, NULL) == 0) |
|
|
return; |
|
|
} |
|
405 |
|
|
406 |
/* |
if (secure.cert == 0) |
407 |
Check file permissions. Ignore if a client hasn't |
secure.cert = allocbuf(DEFAULT_SSL_PEM, MAXPATHLEN); |
408 |
specified a private key or a certificate. |
if (check_filename(secure.cert, NULL) == 0) |
409 |
*/ |
return 0; |
410 |
|
if (secure.key == 0) |
411 |
|
secure.key = allocbuf(secure.cert, MAXPATHLEN); |
412 |
|
else if (check_filename(secure.key, NULL) == 0) |
413 |
|
return 0; |
414 |
|
|
415 |
|
/* |
416 |
|
Check file permissions. Ignore if a client hasn't |
417 |
|
specified a private key or a certificate. |
418 |
|
*/ |
419 |
|
|
420 |
if (topt & T_SSL_CKCLIENT) |
if (topt & T_SSL_CKCLIENT) |
421 |
check_filemode(secure.key); |
check_filemode(secure.key); |
422 |
|
|
423 |
swrite(SERVER, sd_client, "220 2.0.0 Ready to start TLS"CRLF); |
swrite(SERVER, remote_client, "220 2.0.0 Ready to start TLS"CRLF); |
424 |
secure.server = start_ssl_server((int)sd_client); |
secure.server = start_ssl_server((int)remote_client); |
425 |
if (!secure.server || (topt & T_ERROR)) { |
if (!secure.server || (topt & T_ERROR)) { |
426 |
swrite(SERVER, sd_client, |
swrite(SERVER, remote_client, |
427 |
"454 4.3.3 TLS not available"CRLF); |
"454 4.3.3 TLS not available"CRLF); |
428 |
return; |
return 0; |
429 |
} |
} |
430 |
sd_client = remote_client = (void *)secure.server; |
remote_client = (void *)secure.server; |
431 |
topt |= T_SSL_FINISHED; |
topt |= T_SSL_FINISHED; |
432 |
#else |
#else |
433 |
swrite(SERVER, sd_client, "503 5.5.0 TLS not available"CRLF); |
swrite(SERVER, remote_client, "503 5.5.0 TLS not available"CRLF); |
434 |
#endif /* USE_SSL */ |
#endif /* USE_SSL */ |
435 |
|
|
436 |
strncpy(command, "", 1); |
return 1; |
|
return; |
|
|
} |
|
|
return; |
|
437 |
} |
} |
438 |
|
|
439 |
static int |
static int |
440 |
transfer_command(void *sd_client, void *sd_server, MESSAGE *msg, char *command) |
process_command(MESSAGE *msg, char *command) |
441 |
{ |
{ |
|
char reply[2 * LINEBUFFER+1]; |
|
442 |
char buf[LINEBUFFER+1]; |
char buf[LINEBUFFER+1]; |
443 |
|
|
444 |
|
safe_strcpy(buf, command); /* make a back-up */ |
445 |
|
save_command(msg, buf); |
446 |
|
|
|
safe_strcpy(buf, command); |
|
447 |
change_to_lower(buf); |
change_to_lower(buf); |
448 |
swrite(CLIENT, sd_server, command); |
|
449 |
if (topt & T_ERROR) |
if (strncmp(buf, "starttls", 8) == 0) |
450 |
return 0; |
return handle_starttls(command); |
451 |
|
return 0; |
452 |
|
} |
453 |
|
|
454 |
if (strncmp(buf, "ehlo", 4) == 0) { |
static int |
455 |
get_response_smtp(CLIENT, sd_server, reply, 2 * LINEBUFFER); |
handle_ehlo(char *command, char *reply, size_t reply_size) |
456 |
|
{ |
457 |
|
get_response_smtp(CLIENT, remote_server, reply, reply_size - 1); |
458 |
|
|
459 |
if (strstr(reply, "STARTTLS")) |
if (strstr(reply, "STARTTLS")) |
460 |
topt |= T_STARTTLS; /* Yes, we can use the TLS/SSL encryption. */ |
topt |= T_STARTTLS; /* Yes, we can use the TLS/SSL encryption. */ |
461 |
|
|
462 |
#ifdef USE_SSL |
#ifdef USE_SSL |
463 |
if ((topt & T_SSL_ONEWAY) && (topt & T_STARTTLS) |
if ((topt & T_SSL_ONEWAY) |
464 |
&& !(topt & T_SSL_FINISHED)) { |
&& (topt & T_STARTTLS) |
465 |
|
&& !(topt & T_SSL_FINISHED)) { |
466 |
struct sockaddr_in rclient; |
|
467 |
char ehlo[LINEBUFFER+1]; |
struct sockaddr_in rclient; |
468 |
socklen_t addrlen; |
char ehlo[LINEBUFFER+1]; |
469 |
|
socklen_t addrlen; |
|
/* |
|
|
The 'ONEWAY' method is used when your MUA doesn't |
|
|
support the TLS/SSL, but your MTA does. |
|
|
Make the TLS/SSL connection with ESMTP server. |
|
|
*/ |
|
|
|
|
|
char newreply[LINEBUFFER+1]; |
|
|
info(NORMAL, _("Using the 'ONEWAY' TLS/SSL encryption...")); |
|
|
swrite(CLIENT, sd_server, "STARTTLS"CRLF); |
|
|
get_response_smtp(CLIENT, sd_server, newreply, LINEBUFFER); |
|
|
|
|
|
if (!isdigit((unsigned char)newreply[0]) || (unsigned char)newreply[0] > '3') { |
|
|
remcrlf(newreply); |
|
|
info(VERBOSE, _("WARNING: %s"), newreply); |
|
|
anubis_error(SOFT, _("STARTTLS (ONEWAY) command failed.")); |
|
|
topt &= ~T_SSL_ONEWAY; |
|
|
swrite(SERVER, sd_client, reply); |
|
|
return 1; |
|
|
} |
|
|
|
|
|
secure.client = start_ssl_client((int)sd_server); |
|
|
if (!secure.client || (topt & T_ERROR)) { |
|
|
topt &= ~T_ERROR; |
|
|
topt &= ~T_SSL_ONEWAY; |
|
|
swrite(SERVER, sd_client, reply); |
|
|
return 1; |
|
|
} |
|
470 |
|
|
471 |
sd_server = remote_server = (void *)secure.client; |
/* |
472 |
topt |= T_SSL_FINISHED; |
The 'ONEWAY' method is used when your MUA doesn't |
473 |
|
support the TLS/SSL, but your MTA does. |
474 |
|
Make the TLS/SSL connection with ESMTP server. |
475 |
|
*/ |
476 |
|
|
477 |
/* |
char newreply[LINEBUFFER+1]; |
478 |
Send the EHLO command (after the TLS/SSL negotiation). |
info(NORMAL, _("Using the 'ONEWAY' TLS/SSL encryption...")); |
479 |
*/ |
swrite(CLIENT, remote_server, "STARTTLS"CRLF); |
480 |
|
get_response_smtp(CLIENT, remote_server, newreply, |
481 |
addrlen = sizeof(rclient); |
sizeof(newreply) - 1); |
482 |
if (getpeername((int)sd_client, (struct sockaddr *)&rclient, &addrlen) == -1) |
|
483 |
anubis_error(HARD, _("getpeername() failed: %s."), strerror(errno)); |
if (!isdigit((unsigned char)newreply[0]) |
484 |
|
|| (unsigned char)newreply[0] > '3') { |
485 |
snprintf(ehlo, LINEBUFFER, |
remcrlf(newreply); |
486 |
"EHLO %s"CRLF, |
info(VERBOSE, _("WARNING: %s"), newreply); |
487 |
(topt & T_ERROR) ? "localhost" : inet_ntoa(rclient.sin_addr)); |
anubis_error(SOFT, |
488 |
|
_("STARTTLS (ONEWAY) command failed.")); |
489 |
|
topt &= ~T_SSL_ONEWAY; |
490 |
|
swrite(SERVER, remote_client, reply); |
491 |
|
return 1; |
492 |
|
} |
493 |
|
|
494 |
|
secure.client = start_ssl_client((int)remote_server); |
495 |
|
if (!secure.client || (topt & T_ERROR)) { |
496 |
topt &= ~T_ERROR; |
topt &= ~T_ERROR; |
497 |
swrite(CLIENT, sd_server, ehlo); |
topt &= ~T_SSL_ONEWAY; |
498 |
get_response_smtp(CLIENT, sd_server, reply, 2 * LINEBUFFER); |
swrite(SERVER, remote_client, reply); |
499 |
|
return 1; |
500 |
} |
} |
501 |
#endif /* USE_SSL */ |
|
502 |
|
remote_server = (void *)secure.client; |
503 |
|
topt |= T_SSL_FINISHED; |
504 |
|
|
505 |
/* |
/* |
506 |
Remove the STARTTLS command from the EHLO list |
Send the EHLO command (after the TLS/SSL negotiation). |
|
if no SSL is specified, the SSL is not available, |
|
|
or we're using the 'ONEWAY' TLS/SSL encryption. |
|
507 |
*/ |
*/ |
508 |
|
|
509 |
if ((topt & T_STARTTLS) |
addrlen = sizeof(rclient); |
510 |
&& (!(topt & T_SSL) || (topt & T_SSL_ONEWAY))) { |
if (getpeername((int)remote_client, |
511 |
char *starttls1 = "250-STARTTLS"; |
(struct sockaddr *)&rclient, &addrlen) == -1) |
512 |
char *starttls2 = "STARTTLS"; |
anubis_error(HARD, |
513 |
if (strstr(reply, starttls1)) |
_("getpeername() failed: %s."), |
514 |
remline(reply, starttls1); |
strerror(errno)); |
515 |
else if (strstr(reply, starttls2)) |
|
516 |
remline(reply, starttls2); |
snprintf(ehlo, sizeof ehlo, |
517 |
} |
"EHLO %s"CRLF, |
518 |
|
(topt & T_ERROR) ? "localhost" : |
519 |
|
inet_ntoa(rclient.sin_addr)); |
520 |
|
|
521 |
|
topt &= ~T_ERROR; |
522 |
|
swrite(CLIENT, remote_server, ehlo); |
523 |
|
get_response_smtp(CLIENT, remote_server, reply, reply_size); |
524 |
|
} |
525 |
|
#endif /* USE_SSL */ |
526 |
|
|
527 |
/* |
/* |
528 |
Check whether we can use the ESMTP AUTH. |
Remove the STARTTLS command from the EHLO list |
529 |
*/ |
if no SSL is specified, the SSL is not available, |
530 |
|
or we're using the 'ONEWAY' TLS/SSL encryption. |
531 |
|
*/ |
532 |
|
|
533 |
if ((topt & T_ESMTP_AUTH) && strstr(reply, "AUTH ")) { |
if ((topt & T_STARTTLS) |
534 |
esmtp_auth(sd_server, reply); |
&& (!(topt & T_SSL) || (topt & T_SSL_ONEWAY))) { |
535 |
memset(session.mta_username, 0, sizeof(session.mta_username)); |
char *starttls1 = "250-STARTTLS"; |
536 |
memset(session.mta_password, 0, sizeof(session.mta_password)); |
char *starttls2 = "STARTTLS"; |
537 |
} |
if (strstr(reply, starttls1)) |
538 |
|
remline(reply, starttls1); |
539 |
|
else if (strstr(reply, starttls2)) |
540 |
|
remline(reply, starttls2); |
541 |
} |
} |
|
else |
|
|
get_response_smtp(CLIENT, sd_server, reply, 2 * LINEBUFFER); |
|
542 |
|
|
543 |
swrite(SERVER, sd_client, reply); |
/* |
544 |
|
Check whether we can use the ESMTP AUTH. |
545 |
|
*/ |
546 |
|
|
547 |
|
if ((topt & T_ESMTP_AUTH) && strstr(reply, "AUTH ")) { |
548 |
|
esmtp_auth(remote_server, reply); |
549 |
|
memset(session.mta_username, 0, sizeof(session.mta_username)); |
550 |
|
memset(session.mta_password, 0, sizeof(session.mta_password)); |
551 |
|
} |
552 |
|
|
553 |
|
return 0; |
554 |
|
} |
555 |
|
|
556 |
|
static int |
557 |
|
transfer_command(MESSAGE *msg, char *command) |
558 |
|
{ |
559 |
|
char reply[2 * LINEBUFFER+1]; |
560 |
|
char buf[LINEBUFFER+1]; |
561 |
|
|
562 |
|
safe_strcpy(buf, command); |
563 |
|
change_to_lower(buf); |
564 |
|
swrite(CLIENT, remote_server, command); |
565 |
|
if (topt & T_ERROR) |
566 |
|
return 0; |
567 |
|
|
568 |
|
if (strncmp(buf, "ehlo", 4) == 0) { |
569 |
|
if (handle_ehlo(command, reply, sizeof reply)) |
570 |
|
return 1; |
571 |
|
} else |
572 |
|
get_response_smtp(CLIENT, remote_server, reply, sizeof reply); |
573 |
|
|
574 |
|
swrite(SERVER, remote_client, reply); |
575 |
if (topt & T_ERROR) |
if (topt & T_ERROR) |
576 |
return 0; |
return 0; |
577 |
|
|
585 |
topt &= ~T_ERROR; |
topt &= ~T_ERROR; |
586 |
} |
} |
587 |
else if (strncmp(buf, "data", 4) == 0) { |
else if (strncmp(buf, "data", 4) == 0) { |
588 |
process_data(sd_client, sd_server, msg); |
process_data(msg); |
589 |
topt &= ~T_ERROR; |
topt &= ~T_ERROR; |
590 |
} |
} |
591 |
} |
} |
593 |
} |
} |
594 |
|
|
595 |
void |
void |
596 |
process_data(void *sd_client, void *sd_server, MESSAGE *msg) |
process_data(MESSAGE *msg) |
597 |
{ |
{ |
598 |
char buf[LINEBUFFER+1]; |
char buf[LINEBUFFER+1]; |
599 |
|
|
600 |
alarm(1800); |
alarm(1800); |
601 |
|
|
602 |
collect_headers(sd_client, msg); |
collect_headers(msg); |
603 |
collect_body(sd_client, msg); |
collect_body(msg); |
604 |
|
|
605 |
rcfile_process_section(CF_CLIENT, "RULE", NULL, msg); |
rcfile_process_section(CF_CLIENT, "RULE", NULL, msg); |
606 |
|
|
607 |
transfer_header(sd_client, sd_server, msg->header); |
transfer_header(msg->header); |
608 |
transfer_body(sd_client, sd_server, msg); |
transfer_body(msg); |
609 |
|
|
610 |
recvline(CLIENT, sd_server, buf, LINEBUFFER); |
recvline(CLIENT, remote_server, buf, sizeof(buf) - 1); |
611 |
swrite(SERVER, sd_client, buf); |
swrite(SERVER, remote_client, buf); |
612 |
|
|
613 |
message_free(msg); |
message_free(msg); |
614 |
message_init(msg); |
message_init(msg); |
616 |
} |
} |
617 |
|
|
618 |
static void |
static void |
619 |
transfer_header(void *sd_client, void *sd_server, LIST *header_buf) |
transfer_header(LIST *header_buf) |
620 |
{ |
{ |
621 |
send_header(sd_server, header_buf); |
send_header(remote_server, header_buf); |
622 |
swrite(CLIENT, sd_server, CRLF); |
swrite(CLIENT, remote_server, CRLF); |
623 |
} |
} |
624 |
|
|
625 |
|
|
628 |
****************/ |
****************/ |
629 |
|
|
630 |
static void |
static void |
631 |
raw_transfer(void *sd_client, void *sd_server) |
raw_transfer() |
632 |
{ |
{ |
633 |
int nread; |
int nread; |
634 |
char buf[LINEBUFFER+1]; |
char buf[LINEBUFFER+1]; |
635 |
|
|
636 |
while ((nread = recvline(SERVER, sd_client, buf, LINEBUFFER)) > 0) { |
while ((nread = recvline(SERVER, remote_client, buf, |
637 |
|
sizeof(buf) - 1)) > 0) { |
638 |
if (strncmp(buf, "."CRLF, 3) == 0) /* EOM */ |
if (strncmp(buf, "."CRLF, 3) == 0) /* EOM */ |
639 |
break; |
break; |
640 |
swrite(CLIENT, sd_server, buf); |
swrite(CLIENT, remote_server, buf); |
641 |
} |
} |
642 |
} |
} |
643 |
|
|
644 |
void |
void |
645 |
transfer_body(void *sd_client, void *sd_server, MESSAGE *msg) |
transfer_body(MESSAGE *msg) |
646 |
{ |
{ |
647 |
if (msg->boundary) { |
if (msg->boundary) { |
648 |
send_body(msg, sd_server); |
send_body(msg, remote_server); |
649 |
|
|
650 |
/* Transfer everything else */ |
/* Transfer everything else */ |
651 |
raw_transfer(sd_client, sd_server); |
raw_transfer(); |
652 |
} else |
} else |
653 |
send_body(msg, sd_server); |
send_body(msg, remote_server); |
654 |
swrite(CLIENT, sd_server, "."CRLF); |
swrite(CLIENT, remote_server, "."CRLF); |
655 |
} |
} |
656 |
|
|
657 |
|
|