/[anubis]/anubis/src/tunnel.c
ViewVC logotype

Diff of /anubis/src/tunnel.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.18 by gray, Sun Jun 22 08:21:52 2003 UTC revision 1.19 by gray, Fri Jun 27 13:10:54 2003 UTC
# Line 29  Line 29 
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 */
# Line 86  add_header(LIST *list, char *line) Line 86  add_header(LIST *list, char *line)
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)
# Line 182  send_string_list(void *sd_server, LIST * Line 182  send_string_list(void *sd_server, LIST *
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];
# Line 197  collect_body(void *sd_client, MESSAGE *m Line 197  collect_body(void *sd_client, MESSAGE *m
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                                    
# Line 272  send_body(MESSAGE *msg, void *sd_server) Line 273  send_body(MESSAGE *msg, void *sd_server)
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;
# Line 282  smtp_session(void *sd_client, void *sd_s Line 283  smtp_session(void *sd_client, void *sd_s
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) {
# Line 290  smtp_session(void *sd_client, void *sd_s Line 291  smtp_session(void *sd_client, void *sd_s
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, ' '))) {
# Line 301  smtp_session(void *sd_client, void *sd_s Line 303  smtp_session(void *sd_client, void *sd_s
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    
# Line 357  save_command(MESSAGE *msg, char *line) Line 354  save_command(MESSAGE *msg, char *line)
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    
# Line 570  transfer_command(void *sd_client, void * Line 585  transfer_command(void *sd_client, void *
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          }          }
# Line 578  transfer_command(void *sd_client, void * Line 593  transfer_command(void *sd_client, void *
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);
# Line 601  process_data(void *sd_client, void *sd_s Line 616  process_data(void *sd_client, void *sd_s
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    
# Line 613  transfer_header(void *sd_client, void *s Line 628  transfer_header(void *sd_client, void *s
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    

Legend:
Removed from v.1.18  
changed lines
  Added in v.1.19

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26