home *** CD-ROM | disk | FTP | other *** search
/ CD Shareware Magazine 1999 April / CD_Shareware_Magazine_31.iso / Free / Internet / blat180.exe / blat.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-10-30  |  57.6 KB  |  1,743 lines

  1. #include <windows.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <iostream.h>
  5. #include <time.h>
  6. /* generic socket DLL support */
  7. #include "gensock.h"
  8.  
  9. #ifdef WIN32
  10.    #define __far far
  11.    #define huge far
  12.    #define __near near
  13. #endif
  14.  
  15. #define MAXOUTLINE 255
  16.  
  17. #ifdef GENSOCK_STATIC_LINK
  18. HANDLE  dll_module_handle=0;
  19. #else
  20. HANDLE   gensock_lib = 0;
  21. #endif
  22.  
  23. int (FAR PASCAL *pgensock_connect) (char FAR * hostname, char FAR * service, socktag FAR * pst);
  24. int (FAR PASCAL *pgensock_getchar) (socktag st, int wait, char FAR * ch);
  25. int (FAR PASCAL *pgensock_put_data) (socktag st, char FAR * data, unsigned long length);
  26. int (FAR PASCAL *pgensock_close) (socktag st);
  27. int (FAR PASCAL *pgensock_gethostname) (char FAR * name, int namelen);
  28. int (FAR PASCAL *pgensock_put_data_buffered) (socktag st, char FAR * data, unsigned long length);
  29. int (FAR PASCAL *pgensock_put_data_flush) (socktag st);
  30.  
  31. void ConvertToQuotedPrintable(char ThisChar, int * CurrPos, char * buffer);
  32.  
  33. socktag SMTPSock;
  34. #define SERVER_SIZE 256     // #defines (bleah!) from Beverly Brown "beverly@datacube.com"
  35. #define SENDER_SIZE 256
  36. #define TRY_SIZE 20
  37. #define SUBJECT_SIZE 240
  38. #define DEST_SIZE 1024
  39. #define ORG_SIZE 512
  40. char SMTPHost[SERVER_SIZE];
  41. char SMTPPort[SERVER_SIZE];
  42. char Try[TRY_SIZE];
  43. char Sender[SENDER_SIZE];
  44. char Profile[TRY_SIZE];
  45. char *Recipients;
  46. char my_hostname[1024];
  47. char destination[DEST_SIZE];
  48. char cc_list[DEST_SIZE];
  49. char bcc_list[DEST_SIZE];
  50. char loginname[SENDER_SIZE];
  51. char senderid[SENDER_SIZE];
  52. char subject[SUBJECT_SIZE];
  53. char organization[ORG_SIZE];
  54. int mime=0;
  55. int quiet=0;
  56. int uuencode=0;
  57. int base64=0;
  58. int attach=0;
  59. char attachfile[64][200];
  60. char attachedfile[200];
  61. char * shortname;
  62. char my_hostname_wanted[1024]="";
  63.  
  64. WIN32_FIND_DATA FindFileData;
  65. DWORD dwordTime;
  66.  
  67. int attachtype[64];
  68. int noheader=0;
  69.  
  70. char *usage[]=
  71. {
  72.    "Blat v1.8: WinNT/95 console utility to mail a file via SMTP",
  73.    "by P.Mendes, M.Neal, G.Vollant, T. Charron",
  74.    "  http://www.interlog.com/~tcharron/blat.html",
  75.    "syntax:",
  76.    "  Blat <filename> -t <recipient> [optional switches (see below)]",
  77.    "  Blat -install <server addr> <sender's addr> [<try>[<port>[<profile>]]] [-q]",
  78.    "  Blat -profile [-delete | \"<default>\"] [profile1] [profileN] [-q]",
  79.    "  Blat -h [-q]",
  80.    "",
  81.    "-install <server addr> <sender's addr> [<try n times> [<port> [<profile>]]]",
  82.    "     : set's SMTP server, sender, number of tries and port for profile",
  83.    "       (<try n times> and <port> may be replaced by '-').",
  84.    "",
  85.    "<filename>     : file with the message body ('-' for console input, end with ^Z)",
  86.    "-t <recipient> : recipient list (comma separated)",
  87.    "-s <subj>      : subject line",
  88.    "-f <sender>    : overrides the default sender address (must be known to server)",
  89.    "-i <addr>      : a 'From:' address, not necessarily known to the SMTP server.",
  90.    "-c <recipient> : carbon copy recipient list (comma separated)",
  91.    "-b <recipient> : blind carbon copy recipient list (comma separated)",
  92.    "-o <organization>: Organization field",
  93.    "-h             : displays this help.",
  94.    "-q             : supresses *all* output.",
  95.    "-noh           : prevent X-Mailer header from showing homepage of blat",
  96.    "-noh2          : prevent X-Mailer header entirely",
  97.    "-p <profile>   : send with SMTP server, user and port defined in <profile>.",
  98.    "-server <addr> : overrides the default SMTP server to be used.",
  99.    "-port <port>   : port to be used on the server, defaults to SMTP (25)",
  100.    "-hostname <hst>: select the hostname used to send the message",
  101.    "-mime          : MIME Quoted-Printable Content-Transfer-Encoding.",
  102.    "-uuencode      : Send (binary) file UUEncoded",
  103.    "-base64        : Send (binary) file using base64 (binary Mime)",
  104.    "-try <n times> : how many time blat should try to send. from '1' to 'INFINITE'",
  105.    "-attach <file> : attach binary file to message (may be repeated)",
  106.    "-attacht <file>: attach text file to message (may be repeated)",
  107.    "",
  108.    "Note that if the '-i' option is used, <sender> is included in 'Reply-to:'",
  109.    "and 'Sender:' fields in the header of the message."
  110. };
  111. const NMLINES=38;
  112.  
  113. void
  114.    gensock_error (char * function, int retval)
  115. {
  116.    if ( ! quiet ) {
  117.       switch ( retval ) {
  118.       case 4001: printf("Error: Malloc failed (possibly out of memory)."); break;
  119.       case 4002: printf("Error: Error sending data."); break;
  120.       case 4003: printf("Error: Error initializing gensock.dll."); break;
  121.       case 4004: printf("Error: Version not supported."); break;
  122.       case 4005: printf("Error: The winsock version specified by gensock is not supported by this winsock.dll."); break;
  123.       case 4006: printf("Error: Network not ready."); break;
  124.       case 4007: printf("Error: Can't resolve (mailserver) hostname."); break;
  125.       case 4008: printf("Error: Can't create a socket (too many simultaneous links?)"); break;
  126.       case 4009: printf("Error: Error reading socket."); break;
  127.       case 4010: printf("Error: Not a socket."); break;
  128.       case 4011: printf("Error: Busy."); break;
  129.       case 4012: printf("Error: Error closing socket."); break;
  130.       case 4013: printf("Error: Wait a bit (possible timeout)."); break;
  131.       case 4014: printf("Error: Can't resolve service."); break;
  132.       case 4015: printf("Error: Can't connect to mailserver (timed out if winsock.dll error 10060)"); break;
  133.       case 4016: printf("Error: Connection to mailserver was dropped."); break;
  134.       case 4017: printf("Error: Mail server refused connection."); break;
  135.       default:   printf("error %d in function '%s'", retval, function);
  136.       }
  137.    }
  138. }
  139.  
  140. // loads the GENSOCK DLL file
  141. int load_gensock()
  142. {
  143. #ifdef GENSOCK_STATIC_LINK
  144.    pgensock_connect = gensock_connect;
  145.    pgensock_getchar = gensock_getchar ;
  146.    pgensock_put_data = gensock_put_data;
  147.    pgensock_close = gensock_close;
  148.    pgensock_gethostname=gensock_gethostname;
  149.    pgensock_put_data_buffered=gensock_put_data_buffered;
  150.    pgensock_put_data_flush=gensock_put_data_flush;
  151.    dll_module_handle = GetModuleHandle (NULL);
  152. #else
  153.    if ( (gensock_lib = LoadLibrary("gwinsock.dll")) == NULL ) {
  154.       if ( (gensock_lib = LoadLibrary("gensock.dll")) == NULL ) {
  155.          if ( ! quiet )
  156.             printf("Couldn't load either 'GWINSOCK.DLL' or 'GENSOCK.DLL'\nInstall one of these in your path.");
  157.          return(-1);
  158.       }
  159.    }
  160.  
  161.    if ( 
  162.       ( pgensock_connect =
  163.         (  int (FAR PASCAL *)(char FAR *, char FAR *, socktag FAR *) )
  164.         GetProcAddress(gensock_lib, "gensock_connect")
  165.       ) == NULL
  166.       ) {
  167.       if ( ! quiet )
  168.          printf("couldn't getprocaddress for gensock_connect\n");
  169.       return(-1);
  170.    }
  171.  
  172.    if ( 
  173.       ( pgensock_getchar =
  174.         ( int (FAR PASCAL *) (socktag, int, char FAR *) )
  175.         GetProcAddress(gensock_lib, "gensock_getchar")
  176.       ) == NULL
  177.       ) {
  178.       if ( ! quiet )
  179.          printf("couldn't getprocaddress for gensock_getchar\n");
  180.       return(-1);
  181.    }
  182.  
  183.    if ( 
  184.       ( pgensock_put_data =
  185.         ( int (FAR PASCAL *) (socktag, char FAR *, unsigned long) )
  186.         GetProcAddress(gensock_lib, "gensock_put_data")
  187.       ) == NULL
  188.       ) {
  189.       if ( ! quiet )
  190.          printf("couldn't getprocaddress for gensock_put_data\n");
  191.       return(-1);
  192.    }
  193.  
  194.    if ( 
  195.       ( pgensock_close =
  196.         (int (FAR PASCAL *) (socktag) )
  197.         GetProcAddress(gensock_lib, "gensock_close")
  198.       ) == NULL
  199.       ) {
  200.       if ( ! quiet )
  201.          printf("couldn't getprocaddress for gensock_close\n");
  202.       return(-1);
  203.    }
  204.  
  205.    if ( 
  206.       ( pgensock_gethostname =
  207.         (int (FAR PASCAL *) (char FAR *, int) )
  208.         GetProcAddress(gensock_lib, "gensock_gethostname")
  209.       ) == NULL
  210.       ) {
  211.       if ( ! quiet )
  212.          printf("couldn't getprocaddress for gensock_gethostname\n");
  213.       return(-1);
  214.    }
  215.  
  216.    if ( 
  217.       ( pgensock_put_data_buffered =
  218.         ( int (FAR PASCAL *) (socktag, char FAR *, unsigned long) )
  219.         GetProcAddress(gensock_lib, "gensock_put_data_buffered")
  220.       ) == NULL
  221.       ) {
  222.       if ( ! quiet )
  223.          printf("couldn't getprocaddress for gensock_put_data_buffered\n");
  224.       return(-1);
  225.    }
  226.  
  227.    if ( 
  228.       ( pgensock_put_data_flush =
  229.         ( int (FAR PASCAL *) (socktag) )
  230.         GetProcAddress(gensock_lib, "gensock_put_data_flush")
  231.       ) == NULL
  232.       ) {
  233.       if ( ! quiet )
  234.          printf("couldn't getprocaddress for gensock_put_data_flush\n");
  235.       return(-1);
  236.    }
  237. #endif
  238.    return(0);
  239. }
  240.  
  241. int open_smtp_socket( void )
  242. {
  243.    int retval;
  244.    char *ptr;
  245.  
  246.    /* load the library if it's not loaded */
  247. //  if (!gensock_lib)
  248.    if ( ( retval = load_gensock() ) ) return( retval );
  249.  
  250.    if ( NULL != (ptr=strchr(SMTPHost, ':')) ) {
  251.       *ptr=0;
  252.       strcpy(SMTPPort, ptr+1);
  253.    }
  254.  
  255.    if ( (retval = (*pgensock_connect) ((LPSTR) SMTPHost,
  256.                                        (LPSTR)((*SMTPPort == 0) ? "smtp" : SMTPPort),
  257.                                        &SMTPSock)) ) {
  258.       if ( retval == ERR_CANT_RESOLVE_SERVICE ) {
  259.          if ( (retval = (*pgensock_connect) ((LPSTR)SMTPHost,
  260.                                              (LPSTR)((*SMTPPort == 0) ? "25" : SMTPPort),
  261.                                              &SMTPSock)) ) {
  262.             gensock_error ("gensock_connect", retval);
  263.             return(-1);
  264.          }
  265.       }
  266.       // error other than can't resolve service
  267.       else {
  268.          gensock_error ("gensock_connect", retval);
  269.          return(-1);
  270.       }
  271.    }
  272.  
  273.    // we wait to do this until here because WINSOCK is
  274.    // guaranteed to be already initialized at this point.
  275.  
  276.    // get the local hostname (needed by SMTP)
  277.    if ( (retval = (*pgensock_gethostname) (my_hostname, sizeof(my_hostname))) ) {
  278.       gensock_error ("gensock_gethostname", retval);
  279.       return(-1);
  280.    }
  281.    return(0);
  282. }
  283.  
  284.  
  285. int close_smtp_socket( void )
  286. {
  287.    int retval;
  288.  
  289.    if ( (retval = (*pgensock_close) (SMTPSock)) ) {
  290.       gensock_error ("gensock_close", retval);
  291.       return(-1);
  292.    }
  293. #ifdef GENSOCK_STATIC_LINK
  294. #else
  295.    FreeLibrary( gensock_lib );
  296. #endif
  297.    return(0);
  298. }
  299.  
  300. int get_smtp_line( void )
  301. {
  302.    char ch = '.';
  303.    char in_data [MAXOUTLINE];
  304.    char * index;
  305.    int retval = 0;
  306.  
  307.    index = in_data;
  308.  
  309.    while ( ch != '\n' ) {
  310.       if ( (retval = (*pgensock_getchar) (SMTPSock, 0, &ch) ) ) {
  311.          gensock_error ("gensock_getchar", retval);
  312.          return(-1);
  313.       } else {
  314.          *index = ch;
  315.          index++;
  316.       }
  317.    }
  318.  
  319.    /* this is to support multi-line responses, common with */
  320.    /* servers that speak ESMTP */
  321.  
  322.    /* I know, I know, it's a hack 8^) */
  323.    if ( in_data[3] == '-' ) return( get_smtp_line() );
  324.    else return(atoi(in_data));
  325. }
  326.  
  327. int put_smtp_line( socktag sock, char far * line, unsigned int nchars )
  328. {
  329.    int retval;
  330.  
  331.    if ( (retval = (*pgensock_put_data) (sock, line, (unsigned long) nchars)) ) {
  332.       gensock_error ("gensock_put_data", retval);
  333.       return(-1);
  334.    }
  335.    return(0);
  336. }
  337.  
  338. int putline_internal (socktag sock, char * line, unsigned int nchars)
  339. {
  340.    int retval;
  341.  
  342.    if ( (retval =
  343.          (*pgensock_put_data) (sock,
  344.                                (char FAR *) line,
  345.                                (unsigned long) nchars)) ) {
  346.       switch ( retval ) {
  347.       case ERR_NOT_CONNECTED:
  348.          gensock_error( "SMTP server has closed the connection", retval );
  349.          break;
  350.  
  351.       default:
  352.          gensock_error ("gensock_put_data", retval);
  353.       }
  354.       return(-1);
  355.    }
  356.    return(0);
  357. }
  358.  
  359. void smtp_error (char * message)
  360. {
  361.    if ( ! quiet )
  362.       printf("%s\n",message);
  363.    put_smtp_line (SMTPSock, "QUIT\r\n", 6);
  364.    // this is to wait for the 221 response from the server
  365.    get_smtp_line();
  366.    close_smtp_socket();
  367. }
  368.  
  369.  
  370. // 'destination' is the address the message is to be sent to
  371. // 'message' is a pointer to a null-terminated 'string' containing the
  372. // entire text of the message.
  373.  
  374. int prepare_smtp_message(char * MailAddress, char * destination,
  375.                          const char* wanted_hostname)
  376. {
  377.    char out_data[MAXOUTLINE];
  378.    char str[1024];
  379.    char *ptr;
  380.    int len, startLen;
  381.  
  382.    if ( wanted_hostname!=NULL )
  383.       if ( (*wanted_hostname)=='\0' )
  384.          wanted_hostname=NULL;
  385.  
  386.    if ( 0 != open_smtp_socket() ) return(-1);
  387.  
  388.    if ( get_smtp_line() != 220 ) {
  389.       smtp_error ("SMTP server error");
  390.       return(-1);
  391.    }
  392.  
  393.    sprintf( out_data, "HELO %s\r\n",
  394.             (wanted_hostname==NULL) ? my_hostname  : wanted_hostname);
  395.    if ( 0!=put_smtp_line( SMTPSock, out_data, strlen (out_data) ) ) return(-1);
  396.  
  397.    if ( get_smtp_line() != 250 ) {
  398.       smtp_error ("SMTP server error");
  399.       return(-1);
  400.    }
  401.  
  402.    sprintf (out_data, "MAIL From:<%s>\r\n", loginname);
  403.    if ( 0!=put_smtp_line( SMTPSock, out_data, strlen (out_data) ) ) return(-1);
  404.  
  405.    if ( get_smtp_line() != 250 ) {
  406.       smtp_error ("The mail server doesn't like the sender name,\nhave you set your mail address correctly?");
  407.       return(-1);
  408.    }
  409.  
  410.    // do a series of RCPT lines for each name in address line
  411.    for ( ptr = destination; *ptr; ptr += len + 1 ) {
  412.       // if there's only one token left, then len will = startLen,
  413.       // and we'll iterate once only
  414.       startLen = strlen (ptr);
  415.       if ( (len = strcspn (ptr, " ,\n\t\r")) != startLen ) {
  416.          ptr[len] = '\0';                        // replace delim with NULL char
  417.          while ( strchr (" ,\n\t\r", ptr[len+1]) )   // eat white space
  418.             ptr[len++] = '\0';
  419.       }
  420.  
  421.       sprintf (out_data, "RCPT To: <%s>\r\n", ptr);
  422.       putline_internal( SMTPSock, out_data, strlen (out_data) );
  423.  
  424.       if ( get_smtp_line() != 250 ) {
  425.          sprintf (str, "The mail server doesn't like the name %s.\nHave you set the 'To: ' field correctly?", ptr);
  426.          smtp_error (str);
  427.          return(-1);
  428.       }
  429.  
  430.       if ( len == startLen )                     // last token, we're done
  431.          break;
  432.    }
  433.  
  434.    sprintf (out_data, "DATA\r\n");
  435.    if ( 0!=put_smtp_line( SMTPSock, out_data, strlen (out_data) ) ) return(-1);
  436.  
  437.    if ( get_smtp_line() != 354 ) {
  438.       smtp_error ("Mail server error accepting message data");
  439.       return(-1);
  440.    }
  441.  
  442.    return(0);
  443.  
  444. }
  445.  
  446. int transform_and_send_edit_data( socktag sock, char * editptr )
  447. {
  448.    char *index;
  449.    char *header_end;
  450.    char previous_char = 'x';
  451.    unsigned int send_len;
  452.    int retval;
  453.    BOOL done = 0;
  454.  
  455.    send_len = lstrlen(editptr);
  456.    index = editptr;
  457.  
  458.    header_end = strstr (editptr, "\r\n\r\n");
  459.  
  460.    while ( !done ) {
  461.       // room for extra char for double dot on end case
  462.       while ( (unsigned int) (index - editptr) < send_len ) {
  463.          switch ( *index ) {
  464.          case '.':
  465.             if ( previous_char == '\n' )
  466.                /* send _two_ dots... */
  467.                if ( (retval = (*pgensock_put_data_buffered) (sock, index, 1)) ) return(retval);
  468.             if ( (retval = (*pgensock_put_data_buffered) (sock, index, 1)) ) return(retval);
  469.             break;
  470.          case '\r':
  471.             // watch for soft-breaks in the header, and ignore them
  472.             if ( index < header_end && (strncmp (index, "\r\r\n", 3) == 0) )
  473.                index += 2;
  474.             else
  475.                if ( previous_char != '\r' )
  476.                if ( (retval = (*pgensock_put_data_buffered) (sock, index, 1)) )
  477.                   return(retval);
  478.                // soft line-break (see EM_FMTLINES), skip extra CR */
  479.             break;
  480.          default:
  481.             if ( (retval = (*pgensock_put_data_buffered) (sock, index, 1)) )
  482.                return(retval);
  483.          }
  484.          previous_char = *index;
  485.          index++;
  486.       }
  487.       if ( (unsigned int) (index - editptr) == send_len ) done = 1;
  488.    }
  489.  
  490.    // this handles the case where the user doesn't end the last
  491.    // line with a <return>
  492.  
  493.    if ( editptr[send_len-1] != '\n' ) {
  494.       if ( (retval = (*pgensock_put_data_buffered) (sock, "\r\n.\r\n", 5)) )
  495.          return(retval);
  496.    } else
  497.       if ( (retval = (*pgensock_put_data_buffered) (sock, ".\r\n", 3)) )
  498.       return(retval);
  499.  
  500.    /* now make sure it's all sent... */
  501.    if ( (retval = (*pgensock_put_data_flush)(sock)) ) return(retval);
  502.    return(0);
  503. }
  504.  
  505. int fixup(char * string)
  506. {
  507.    int ok=1;
  508.    int i,stl;
  509.    static char tempstring[2048];
  510.    char * p;
  511.    int Pos=0;
  512.  
  513.    // First, detect any funny characters.
  514.    stl=strlen(string);
  515.    for ( i=0;i<stl;i++ ) {
  516.       if ( (string[i]<0x20) || (string[i]>0x7D) || (string[i] == 0x3D) ) ok=0;
  517.    }
  518.  
  519.    // If needed, fixup the string.
  520.    if ( !ok ) {
  521.       strcpy(tempstring,string);
  522.       strcpy(string,"=?ISO-8859-1?Q?");
  523.       for ( i=0;i<stl;i++ ) {
  524.          ConvertToQuotedPrintable((tempstring[i]), &Pos, string + strlen(string));
  525.       }
  526.       strcat(string,"?=");
  527.       return(1);
  528.    }
  529.    return(0);
  530. }
  531.  
  532. int send_smtp_edit_data (char * message)
  533. {
  534.    int retval;
  535.  
  536.    if ( 0 != (retval=transform_and_send_edit_data( SMTPSock, message )) ) return(retval);
  537.  
  538.    if ( get_smtp_line() != 250 ) {
  539.       smtp_error ("Message not accepted by server");
  540.       return(-1);
  541.    }
  542.    return(0);
  543. }
  544.  
  545.  
  546. int finish_smtp_message( void )
  547. {
  548.    int ret;
  549.  
  550.    ret = put_smtp_line( SMTPSock, "QUIT\r\n", 6 );
  551.    // wait for a 221 message from the server
  552.    get_smtp_line();
  553.    return(ret);
  554. }
  555.  
  556. // create a registry entries for this program
  557. int CreateRegEntry( void )
  558. {
  559.    HKEY  hKey1;
  560.    DWORD  dwDisposition;
  561.    LONG   lRetCode;
  562.    char   strRegisterKey[256];
  563.  
  564.    strcpy(strRegisterKey,"SOFTWARE\\Public Domain\\Blat");
  565.    if ( Profile[0] != '\0' ) {
  566.       strcat(strRegisterKey, "\\");
  567.       strcat(strRegisterKey, Profile);
  568.    }
  569.  
  570.    /* try to create the .INI file key */
  571.    lRetCode = RegCreateKeyEx ( HKEY_LOCAL_MACHINE,
  572.                                strRegisterKey,
  573.                                0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE,NULL, &hKey1,&dwDisposition
  574.                              );
  575.  
  576.    /* if we failed, note it, and leave */
  577.    if ( lRetCode != ERROR_SUCCESS ) {
  578.       if ( ! quiet ) printf ("Error in creating blat key in the registry\n");
  579.       return(10);
  580.    }
  581.  
  582.    /* try to set a section value */
  583.    lRetCode = RegSetValueEx( hKey1,"SMTP server",0,REG_SZ, (BYTE *) &SMTPHost[0], (strlen(SMTPHost)+1));
  584.  
  585.    /* if we failed, note it, and leave */
  586.    if ( lRetCode != ERROR_SUCCESS ) {
  587.       if ( ! quiet ) printf ( "Error in setting SMTP server value in the registry\n");
  588.       return(11);
  589.    }
  590.  
  591.    /* try to set another section value */
  592.    lRetCode = RegSetValueEx( hKey1,"Sender",0,REG_SZ, (BYTE *) &Sender[0], (strlen(Sender)+1));
  593.  
  594.    /* if we failed, note it, and leave */
  595.    if ( lRetCode != ERROR_SUCCESS ) {
  596.       if ( ! quiet ) printf ( "Error in setting sender address value in the registry\n");
  597.       return(11);
  598.    }
  599.  
  600.    /* try to set another section value */
  601.    lRetCode = RegSetValueEx( hKey1,"SMTP Port",0,REG_SZ, (BYTE *) &SMTPPort[0], (strlen(SMTPPort)+1));
  602.  
  603.    /* if we failed, note it, and leave */
  604.    if ( lRetCode != ERROR_SUCCESS ) {
  605.       if ( ! quiet ) printf ( "Error in setting port value in the registry\n");
  606.       return(11);
  607.    }
  608.  
  609.    /* try to set another section value */
  610.    lRetCode = RegSetValueEx( hKey1,"Try",0,REG_SZ, (BYTE *) &Try[0], (strlen(Try)+1));
  611.  
  612.    /* if we failed, note it, and leave */
  613.    if ( lRetCode != ERROR_SUCCESS ) {
  614.       if ( ! quiet ) printf ( "Error in setting number of try value in the registry\n");
  615.       return(11);
  616.    }
  617.  
  618.    return(0);
  619. }
  620.  
  621. // Delete a registry entries for this program
  622. int DeleteRegEntry( void )
  623. {
  624.    HKEY  hKey1;
  625.    DWORD  dwDisposition;
  626.    LONG   lRetCode;
  627.    char   strRegisterKey[256];
  628.  
  629.    strcpy(strRegisterKey,"SOFTWARE\\Public Domain\\Blat");
  630.    if ( Profile[0] != '\0' ) {
  631.       strcat(strRegisterKey, "\\");
  632.       strcat(strRegisterKey, Profile);
  633.  
  634.  
  635.       /* try to create the .INI file key */
  636.       lRetCode = RegOpenKeyEx ( HKEY_LOCAL_MACHINE,
  637.                                 strRegisterKey,
  638.                                 0, KEY_ALL_ACCESS, &hKey1
  639.                               );
  640.  
  641.       /* if we failed, note it, and leave */
  642.       if ( lRetCode != ERROR_SUCCESS ) {
  643.          if ( ! quiet ) printf ("Error in finding blat profile %s in the registry\n", Profile);
  644.          return(10);
  645.       }
  646.  
  647.       /* try to remove a section*/
  648.       lRetCode = RegDeleteKey( hKey1,"");
  649.  
  650.       /* if we failed, note it, and leave */
  651.       if ( lRetCode != ERROR_SUCCESS ) {
  652.          if ( ! quiet ) printf ( "Error in deleting profile %s in the registry\n", Profile);
  653.          return(11);
  654.       }
  655.    }
  656.    return(0);
  657. }
  658.  
  659. // get the registry entries for this program
  660. int GetRegEntry( void )
  661. {
  662.    HKEY  hKey1;
  663.    DWORD  dwType;
  664.    DWORD  dwBytesRead;
  665.    LONG   lRetCode;
  666.    char   register_key[256];
  667.  
  668.    // open the registry key in read mode
  669.    strcpy(register_key, "SOFTWARE\\Public Domain\\Blat");
  670.    if ( Profile[0] != '\0' ) {
  671.       strcat(register_key, "\\");
  672.       strcat(register_key, Profile);
  673.    }
  674.    lRetCode = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  675.                             register_key,
  676.                             0, KEY_READ, &hKey1
  677.                           );
  678.    if ( lRetCode != ERROR_SUCCESS ) {
  679.       if ( ! quiet ) printf( "Failed to open registry key for Blat profile %s, using default.\n", Profile );
  680.       strcpy(register_key, "SOFTWARE\\Public Domain\\Blat");
  681.       lRetCode = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  682.                                register_key,
  683.                                0, KEY_READ, &hKey1
  684.                              );
  685.       if ( lRetCode != ERROR_SUCCESS ) {
  686. //       if ( ! quiet ) printf( "Failed to open registry key for Blat\n" );
  687.          return(12);
  688.       }
  689.    }
  690.    // set the size of the buffer to contain the data returned from the registry
  691.    // thanks to Beverly Brown "beverly@datacube.com" and "chick@cyberspace.com" for spotting it...
  692.    dwBytesRead=SERVER_SIZE;
  693.    // read the value of the SMTP server entry
  694.    lRetCode = RegQueryValueEx( hKey1, "SMTP server", NULL , &dwType, (BYTE *) &SMTPHost, &dwBytesRead);
  695.    // if we failed, note it, and leave
  696.    if ( lRetCode != ERROR_SUCCESS ) {
  697. //    if ( ! quiet ) printf( "Failed to read SMTP server value from the registry\n" );
  698.       return(12);
  699.    }
  700.  
  701.    dwBytesRead=SENDER_SIZE;
  702.    // read the value of the SMTP server entry
  703.    lRetCode = RegQueryValueEx( hKey1, "Sender", NULL , &dwType, (BYTE *) &Sender, &dwBytesRead);
  704.    // if we failed, note it, and leave
  705.    if ( lRetCode != ERROR_SUCCESS ) {
  706. //    if ( ! quiet ) printf( "Failed to read senders user name from the registry\n" );
  707.       return(12);
  708.    }
  709.  
  710.    dwBytesRead=TRY_SIZE;
  711.    // read the value of the number of try entry
  712.    lRetCode = RegQueryValueEx( hKey1, "Try", NULL , &dwType, (BYTE *) &Try, &dwBytesRead);
  713.    // if we failed, assign a default value
  714.    if ( lRetCode != ERROR_SUCCESS ) {
  715.       strcpy(Try,"1");
  716.    }
  717.  
  718.    dwBytesRead=SERVER_SIZE;
  719.    // read the value of the number of try entry
  720.    lRetCode = RegQueryValueEx( hKey1, "SMTP Port", NULL , &dwType, (BYTE *) &SMTPPort, &dwBytesRead);
  721.    // if we failed, assign a default value
  722.    if ( lRetCode != ERROR_SUCCESS ) *SMTPPort = 0;
  723.  
  724.    return(0);
  725. }
  726.  
  727. // List all profiles
  728. void ListProfiles(char *pstrProfile)
  729. {
  730.    HKEY  hKey1;
  731.    DWORD  dwType;
  732.    DWORD  dwBytesRead;
  733.    LONG   lRetCode;
  734.    char   register_key[256];
  735.    DWORD dwIndex;                                // index of subkey to enumerate
  736.    FILETIME lftLastWriteTime;
  737.    // address for time key last written to);
  738.  
  739.  
  740.    // open the registry key in read mode
  741.    strcpy(register_key, "SOFTWARE\\Public Domain\\Blat");
  742.    lRetCode = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  743.                             register_key,
  744.                             0, KEY_READ, &hKey1
  745.                           );
  746.    if ( lRetCode != ERROR_SUCCESS ) {
  747.       if ( ! quiet ) printf( "Failed to open registry key for Blat profile %s, using default.\n", Profile );
  748.    } else {
  749.  
  750.       dwBytesRead=sizeof(Profile);
  751.       if ( ! quiet ) {
  752.          printf( "BLAT PROFILE EDITOR\n");
  753.          printf( "To modify:    blat -install SMTPHost Sender [Try [Port [Profile]]]\n");
  754.          printf( "To delete:    blat -profile -delete Profile\n");
  755.          printf( "Profiles are listed as in the -install option:\n");
  756.          printf( "SMTPHost Sender Try SMTPPort Profile\n\n");
  757.       }
  758.       quiet=1;
  759.       Profile[0]='\0';
  760.       GetRegEntry();
  761.       if ( (!strcmp(pstrProfile,"<default>"))||(!strcmp(pstrProfile,"<all>")) ) {
  762.          printf("%s %s %s %s %s\n",SMTPHost,Sender,Try,SMTPPort,Profile);
  763.       }
  764.  
  765.       dwIndex=0;
  766.       do {
  767.          dwBytesRead=sizeof(Profile);
  768.          lRetCode = RegEnumKeyEx(  hKey1,        // handle of key to enumerate
  769.                                    dwIndex++,    // index of subkey to enumerate
  770.                                    Profile,      // address of buffer for subkey name
  771.                                    &dwBytesRead, // address for size of subkey buffer
  772.                                    NULL,         // reserved
  773.                                    NULL,         // address of buffer for class string
  774.                                    NULL,         // address for size of class buffer
  775.                                    &lftLastWriteTime
  776.                                    // address for time key last written to);
  777.                                 );
  778.          if ( lRetCode == 0 ) {
  779.             GetRegEntry();
  780.             if ( (!strcmp(pstrProfile,Profile))||(!strcmp(pstrProfile,"<all>")) ) {
  781.                printf("%s %s %s %s %s\n",SMTPHost,Sender,Try,SMTPPort,Profile);
  782.             }
  783.          };
  784.       } while ( lRetCode == 0 );
  785.    }
  786.  
  787. }
  788.  
  789. LPCSTR GetNameWithoutPath(LPCSTR lpFn)
  790. {
  791.    LPCSTR lpRet = lpFn ;
  792.    LPCSTR lpNext ;
  793.    while ( (*lpFn) != '\0' ) {
  794.       if ( ((*lpFn) == ':') || ((*lpFn) == '\\') ) lpRet = lpFn + 1;
  795.       lpNext=CharNext(lpFn);
  796.       lpFn = lpNext;
  797.    }
  798.    return(lpRet);
  799. }
  800.  
  801. #define UU_Mask(Ch) (char) ((char)(Ch) & 0x3f)
  802. void douuencode(const char * filebuffer,char * out,DWORD filesize,const char* filename)
  803. {
  804.    sprintf(out,"begin 644 %s\x0d\x0a",GetNameWithoutPath(filename));
  805.    out += strlen(out);
  806.    while ( filesize>0 ) {
  807.       int size_line = filesize;
  808.       if ( size_line>45 )
  809.          size_line=45;
  810.       filesize -= size_line;
  811.       *(out++) = ' ' + ((char)size_line);
  812.  
  813.       while ( size_line > 0 ) {
  814.          *(out) = UU_Mask(*(filebuffer) >> 2) + 0x20;
  815.          if ( (*out)==' ' ) *out='\x60';
  816.          out++;
  817.  
  818.          *(out) = UU_Mask((*(filebuffer) << 4) & 060 | (*(filebuffer+1) >> 4) & 017) + 0x20;
  819.          if ( (*out)==' ' ) *out='\x60';
  820.          out++;
  821.  
  822.          *(out) = UU_Mask((*(filebuffer+1) << 2) & 074 | (*(filebuffer+2) >> 6) & 03) + 0x20;
  823.          if ( (*out)==' ' ) *out='\x60';
  824.          out++;
  825.  
  826.          *(out) = UU_Mask(*(filebuffer+2) & 077) + 0x20;
  827.          if ( (*out)==' ' ) *out='\x60';
  828.          out++;
  829.  
  830.          filebuffer += 3;
  831.          size_line -=3;
  832.       }
  833.       *(out++) = '\x0d';
  834.       *(out++) = '\x0a';
  835.    }
  836.    strcpy(out,"\x60\x0d\x0a\x65\x6e\x64\x0d\x0a");
  837. }
  838.  
  839. // MIME Quoted-Printable Content-Transfer-Encoding
  840. #define MimeHexChar "0123456789ABCDEF";
  841. void ConvertToQuotedPrintable(char ThisChar, int * CurrPos, char * buffer)
  842. {
  843.    int ThisValue;
  844.    div_t result;
  845.    char HexTable[17] = MimeHexChar;
  846.  
  847.    ThisValue = (256 + (unsigned int) ThisChar) % 256;
  848.  
  849.    if ( ThisValue == 13 ) {
  850.       sprintf( buffer, "%s", "\0" );
  851.       return;
  852.    } else if ( ThisValue == 10 ) {
  853.       sprintf( buffer, "%s", "\r\n" );
  854.       (*CurrPos) = 0;
  855.       return;
  856.    } else if ( (ThisValue < 33) |
  857.                (ThisValue == 61) |
  858.                (ThisValue > 126) ) {
  859.       result = div(ThisValue,16);
  860.       buffer[0] = '=';
  861.       (*CurrPos)++;
  862.       buffer[1] = HexTable[result.quot];
  863.       (*CurrPos)++;
  864.       buffer[2] = HexTable[result.rem];
  865.       (*CurrPos)++;
  866.       buffer[3] = '\0';
  867.    } else {
  868.       buffer[0] = ThisChar;
  869.       (*CurrPos)++;
  870.       buffer[1] = '\0';
  871.    }
  872.  
  873.    if ( *CurrPos > 71 ) {
  874.       strcat(buffer, "=\r\n");                   /* Add soft line break */
  875.       (*CurrPos) = 0;
  876.    }
  877. }
  878.  
  879. // MIME base64 Content-Transfer-Encoding
  880. #define B64_ENC(Ch) (char) (base64table[(char)(Ch) & 0x3f])
  881. void base64_encode(char *in, char *endin, char *out)
  882. {
  883.    char base64table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  884.  
  885.    int length = endin - in ;
  886.  
  887.    char *b = out, *data = in;
  888.    for ( ; length > 2; length -= 3, data += 3 ) {
  889.       if ( ((data-in)%54) == 0 ) {
  890.          *b++ = '\r'; *b++ = '\n';
  891.       }
  892.       *b++ = B64_ENC(data[0] >> 2);
  893.       *b++ = B64_ENC(((data[0] << 4) & 060) | ((data[1] >> 4) & 017));
  894.       *b++ = B64_ENC(((data[1] << 2) & 074) | ((data[2] >> 6) & 03));
  895.       *b++ = B64_ENC(data[2] & 077);
  896.    }
  897.  
  898.    if ( length == 1 ) {
  899.       if ( ((data-in)%54) == 0 ) {
  900.          *b++ = '\r'; *b++ = '\n';
  901.       }
  902.       *b++ = B64_ENC(data[0] >> 2);
  903.       *b++ = B64_ENC((data[0] << 4) & 060);
  904.       *b++ = '=';
  905.       *b++ = '=';
  906.    } else if ( length == 2 ) {
  907.       if ( ((data-in)%54) == 0 ) {
  908.          *b++ = '\r'; *b++ = '\n';
  909.       }
  910.       *b++ = B64_ENC(data[0] >> 2);
  911.       *b++ = B64_ENC(((data[0] << 4) & 060) | ((data[1] >> 4) & 017));
  912.       *b++ = B64_ENC((data[1] << 2) & 074);
  913.       *b++ = '=';
  914.    }
  915.    *b = 0;
  916.  
  917.    return;
  918. }
  919.  
  920. // Convert the entry "n of try" to a numeric, defaults to 1
  921. int noftry()
  922. {
  923.    int n_of_try;
  924.    int i, j;
  925.    n_of_try = 0;
  926.  
  927.    for ( i=0; i<strlen(Try); i++ ) Try[i] = toupper(Try[i]);
  928.  
  929.    if ( !strcmp(Try, "ONCE") ) n_of_try = 1;
  930.    if ( !strcmp(Try, "TWICE") ) n_of_try = 2;
  931.    if ( !strcmp(Try, "THRICE") ) n_of_try = 3;
  932.    if ( !strcmp(Try, "INFINITE") ) n_of_try =  -1;
  933.    if ( !strcmp(Try, "-1") ) n_of_try =  -1;
  934.  
  935.    if ( n_of_try == 0 ) {
  936.       for ( i=0; i<strlen(Try); i++ ) {
  937.          if ( Try[i]>=48 && Try[i]<=57 ) n_of_try = n_of_try * 10 + (Try[i] - 48);
  938.       }
  939.    }
  940.  
  941.    if ( n_of_try == 0 || n_of_try <=-2 ) n_of_try=1;
  942.    return(n_of_try);
  943. }
  944.  
  945. int main( int argc,                              /* Number of strings in array argv          */
  946.           char *argv[],                          /* Array of command-line argument strings   */
  947.           char **envp )                          /* Array of environment variable strings    */
  948. {
  949.    int next_arg=2;
  950.    int impersonating = 0;
  951.    int penguin = 0;
  952.    int i, j, k;
  953.    int retcode, regerr;
  954.    int n_of_try;
  955.    char tempdir[MAX_PATH+1];
  956.    char tempfile[MAX_PATH+1];
  957.    HANDLE fileh;
  958.    FILE *tf;
  959.    int hours, minutes;
  960.    OFSTRUCT of;
  961.    char filename[240];
  962.  
  963.    // by default Blat is very noisy!
  964.    quiet = 0;
  965.  
  966.    // by default Blat does not use mime Quoted-Printable Content-Transfer-Encoding!
  967.    mime = 0;
  968.  
  969.    // by default Blat does not use UUEncode
  970.    // Added by Gilles Vollant
  971.    uuencode= 0;
  972.  
  973.    // base64 encoding -- Added by Tim Charron tcharron@interlog.com / Gilles Vollant
  974.    // by default Blat does not use base64 Quoted-Printable Content-Transfer-Encoding!
  975.    //  If you're looking for something to do, then it would be nice if this thing
  976.    //  detected any non-printable characters in the input, and use base64 whenever
  977.    //  quoted-printable wasn't chosen by the user.
  978.    base64 = 0;
  979.  
  980.    // attach -- Added in by Tim Charron (tcharron@interlog.com)
  981.    // If "-attach filename" is on the command line at least once,
  982.    // then those files will be attached as base64 encoded files.
  983.    // This variable is the count of how many of these files there are.
  984.    attach = 0;
  985.  
  986.    // no tempfile so far...
  987.    tempfile[0] = '\0';
  988.  
  989.    if ( argc<2 ) {
  990.       // must have at least file name to send
  991.       for ( i=0;i<NMLINES;i++ ) printf("%s\n",usage[i]);
  992.       return(1);
  993.    }
  994.  
  995.    for ( i=1; i < argc; i++ ) {
  996.       if ( lstrcmpi( "-noh",argv[i] ) == 0 ) noheader = 1;
  997.       if ( lstrcmpi( "-noh2",argv[i] ) == 0 ) noheader = 2;
  998.       if ( lstrcmpi( "-q",argv[i] ) == 0 ) quiet = 1;
  999.       if ( lstrcmpi( "-mime"  ,argv[i] ) == 0 ) {
  1000.          mime = 1; base64 = 0; uuencode=0;
  1001.       }
  1002.       if ( lstrcmpi( "-base64",argv[i] ) == 0 ) {
  1003.          mime = 0; base64 = 1; uuencode=0;
  1004.       }
  1005.       if ( lstrcmpi( "-uuencode",argv[i] ) == 0 ) {
  1006.          mime = 0; base64 = 0; uuencode=1;
  1007.       }
  1008.       if ( lstrcmpi( "-p",argv[i] ) == 0 ) {
  1009.          strcpy(Profile,argv[++i]);
  1010.       }
  1011.    }
  1012.  
  1013.    // get file name from argv[1]
  1014.    strcpy(filename,argv[1]);
  1015.  
  1016.    Sender[0] = '\0';
  1017.    SMTPHost[0] = '\0';
  1018.    SMTPPort[0] = '\0';
  1019.    Try[0] = '\0';
  1020.  
  1021.    regerr = GetRegEntry();
  1022.  
  1023.    strcpy(senderid, Sender);
  1024.    strcpy(loginname, Sender);
  1025.  
  1026.    // thanks to Beverly Brown "beverly@datacube.com" for
  1027.    // fixing the argument parsing in v1.5
  1028.    for ( next_arg=1;next_arg < argc;next_arg++ ) {
  1029.       // if arg is a '-p' just increase and continue looking
  1030.       // we have already dealt with -p at the beginning
  1031.       if ( lstrcmp("-p",argv[next_arg])==0 ) {
  1032.          next_arg++;                             // increment once to step to the profile argument
  1033.       }
  1034.  
  1035.       else if ( lstrcmpi("-h",argv[next_arg])==0 ) {
  1036.          if ( ! quiet ) for ( int i=0;i<NMLINES;i++ ) printf("%s\n",usage[i]);
  1037.          return(1);
  1038.       }
  1039.  
  1040.       // is argv[2] "-install"? If so, indicate error and return
  1041.       else if ( lstrcmpi("-install",argv[next_arg])==0 ) {
  1042.          if ( (argc >= 3) && (argc <= 7) ) {     //Correction: CH, 1998-06-15: replace || by &&
  1043.             strcpy( SMTPHost, argv[++next_arg] );
  1044.             strcpy( Sender, "" );
  1045.             if ( argc >= 4 ) strcpy( Sender, argv[++next_arg] );
  1046.             strcpy( Try, "1" );
  1047.             if ( argc >= 5 ) strcpy( Try, argv[++next_arg] );
  1048.             if ( !strcmp(Try,"-") ) strcpy(Try,"ONCE");
  1049.             if ( !strcmp(Try,"0") ) strcpy(Try,"ONCE");
  1050.  
  1051.             if ( argc >= 6 ) strcpy( SMTPPort, argv[++next_arg] );
  1052.             if ( !strcmp(SMTPPort,"-") ) strcpy(SMTPPort,"25");
  1053.             if ( !strcmp(SMTPPort,"0") ) strcpy(SMTPPort,"25");
  1054.  
  1055.             if ( argc == 7 ) strcpy( Profile, argv[++next_arg] );
  1056.  
  1057.             if ( CreateRegEntry() == 0 ) {
  1058.                if ( ! quiet ) printf("\nSMTP server set to %s on port %s with user %s, retry %s time(s)\n", SMTPHost, SMTPPort, Sender, Try );
  1059.                regerr = 0;
  1060.                return(0);
  1061.             }
  1062.          } else {
  1063.             if ( ! quiet )
  1064.                printf( "to set the SMTP server's address and the user name at that address do:\nblat -install server username");
  1065.             return(6);
  1066.          }
  1067.       }
  1068.  
  1069.       // is argv[2] "-profile"? If so, list or delete the profiles
  1070.       else if ( lstrcmpi("-profile",argv[next_arg])==0 ) {
  1071.          next_arg++;
  1072.          if ( (argc==2 && !quiet) || (argc==3 && quiet ) ) {
  1073.             ListProfiles("<all>");
  1074.          } else {
  1075.             if ( !strcmp(argv[next_arg],"-delete") ) {
  1076.                next_arg++;
  1077.                for ( i=next_arg; i<argc; i++ ) {
  1078.                   strcpy(Profile,argv[i]);
  1079.                   DeleteRegEntry();
  1080.                }
  1081.             } else {
  1082.                for ( i=next_arg; i<argc; i++ ) {
  1083.                   ListProfiles(argv[i]);
  1084.                }
  1085.             }
  1086.          }
  1087.          return(0);
  1088.       }
  1089.  
  1090.       // is argv[2] "-s"? If so, argv[3] is the subject
  1091.       else if ( lstrcmpi("-s",argv[next_arg])==0 ) {
  1092.          strcpy(subject, argv[++next_arg] );
  1093.       }
  1094.  
  1095.       // is argv[2] "-o"? If so, argv[3] is the Organization
  1096.       else if ( lstrcmpi("-o",argv[next_arg])==0 ) {
  1097.          strcpy(organization,argv[++next_arg]);
  1098.       }
  1099.  
  1100.       // is argv[2] "-c"? If so, argv[3] is the carbon-copy list
  1101.       else if ( lstrcmpi("-c",argv[next_arg])==0 ) {
  1102.          strcpy(cc_list,argv[++next_arg] );
  1103.       }
  1104.  
  1105.       // is argv[2] "-b"? If so, argv[3] is the blind carbon-copy list
  1106.       else if ( lstrcmpi("-b",argv[next_arg])==0 ) {
  1107.          strcpy(bcc_list,argv[++next_arg] );
  1108.       }
  1109.  
  1110.       // is next argv "-t"? If so, succeeding argv is the destination
  1111.       else if ( lstrcmpi("-t",argv[next_arg])==0 ) {
  1112.          strcpy(destination, argv[++next_arg] );
  1113.       }
  1114.  
  1115.       // is next argv "-server"? If so, succeeding argv is the SMTPHost
  1116.       else if ( lstrcmpi("-server",argv[next_arg])==0 ) {
  1117.          strcpy(SMTPHost,argv[++next_arg]);
  1118.       }
  1119.  
  1120.       // is next argv "-hostname"? If so, succeeding argv is the SMTPHost  
  1121.       else if ( lstrcmpi("-hostname",argv[next_arg])==0 ) {
  1122.          strcpy(my_hostname_wanted,argv[++next_arg]);
  1123.       }
  1124.  
  1125.       // is next argv "-port"? If so, succeeding argv is the SMTPPort
  1126.       else if ( lstrcmpi("-port",argv[next_arg])==0 ) {
  1127.          strcpy(SMTPPort,argv[++next_arg]);
  1128.       }
  1129.  
  1130.       // is next argv "-try"? If so, succeeding argv is the number of tries
  1131.       else if ( lstrcmpi("-try",argv[next_arg])==0 ) {
  1132.          strcpy(Try,argv[++next_arg]);
  1133.       }
  1134.  
  1135.       //is next argv '-f'? If so, succeeding argv is the loginname
  1136.       else if ( lstrcmp("-f",argv[next_arg])==0 ) {
  1137.          strcpy(loginname, argv[++next_arg]);
  1138.       }
  1139.  
  1140.       else if ( lstrcmp("-penguin",argv[next_arg])==0 ) {
  1141.          penguin = 1;
  1142.       }
  1143.  
  1144.       // we have already dealt with these at the beginning...
  1145.       else if ( (lstrcmp("-mime",argv[next_arg])==0)
  1146.                 || (lstrcmp("-base64",argv[next_arg]) == 0)
  1147.                 || (lstrcmp("-uuencode",argv[next_arg]) == 0)
  1148.                 || (lstrcmp("-q",argv[next_arg]) == 0) ) {
  1149.          // next_arg++; Don't increment, just ignore.  Fixed tcharron@interlog.com
  1150.       }
  1151.  
  1152.       // -attacht added 98.4.16 v1.7.2 tcharron@interlog.com
  1153.       else if ( lstrcmp("-attacht",argv[next_arg])==0 ) {
  1154.          if ( attach == 64 ) {
  1155.             printf("Max of 64 files allowed!  Others are being ignored\n");
  1156.          } else {
  1157.             attachtype[attach]=0;                // text
  1158.             strcpy( (char *) &attachfile[attach++][0], argv[++next_arg] );
  1159.          }
  1160.       }
  1161.  
  1162.       // -attach added 98.2.24 v1.6.3 tcharron@interlog.com
  1163.       else if ( lstrcmp("-attach",argv[next_arg])==0 ) {
  1164.          if ( attach == 64 ) {
  1165.             printf("Max of 64 files allowed!  Others are being ignored\n");
  1166.          } else {
  1167.             attachtype[attach]=1;                // binary
  1168.             strcpy( (char *) &attachfile[attach++][0], argv[++next_arg] );
  1169.          }
  1170.       }
  1171.  
  1172.       //is next argv '-i'? If so, succeeding argv is the sender id
  1173.       else if ( lstrcmp("-i",argv[next_arg])==0 ) {
  1174.          strcpy(senderid, argv[++next_arg]);
  1175.          impersonating = 1;
  1176.       }
  1177.  
  1178.       else if ( next_arg == 1 ) {
  1179.          if ( lstrcmp(filename, "-") != 0 ) {
  1180.             if ( lstrlen(filename)<=0 || OpenFile(filename,&of,OF_EXIST) == HFILE_ERROR ) {
  1181.                if ( ! quiet ) printf("%s does not exist\n",filename);
  1182.                return(2);
  1183.             }
  1184.          }
  1185.       } else {
  1186.          if ( ! quiet )
  1187.             for ( i=0;i<NMLINES;i++ )
  1188.                printf("%s\n",usage[i]);
  1189.          return(1);
  1190.       }
  1191.    }
  1192.  
  1193.    if ( (regerr==12) && (!quiet) )  printf( "Failed to open registry key for Blat\n" );
  1194.  
  1195.    // if we are not impersonating loginname is the same as the sender
  1196.    if ( ! impersonating )
  1197.       strcpy(senderid, loginname);
  1198.  
  1199.    // fixing the argument parsing
  1200.    // Ends here
  1201.  
  1202.    if ( (SMTPHost[0]=='\0')||(loginname[0]=='\0') ) {
  1203.       if ( ! quiet ) {
  1204.          printf( "to set the SMTP server's address and the user name at that address do:\nblat -install server username\n");
  1205.          printf( "or use '-server <server name>' and '-f <user name>'\n");
  1206.          printf( "aborting, nothing sent\n" );
  1207.       }
  1208.       return(12);
  1209.    }
  1210.  
  1211.    // make sure filename exists, get full pathname
  1212.    if ( lstrcmp(filename, "-") != 0 )
  1213.       if ( lstrlen(filename)<=0 || OpenFile(filename,&of,OF_EXIST)==HFILE_ERROR ) {
  1214.          if ( ! quiet ) printf("%s does not exist\n",filename);
  1215.          return(2);
  1216.       }
  1217.  
  1218.       // build temporary recipients list for parsing the "To:" line
  1219.    char *temp = new char [ strlen(destination) + strlen(cc_list) + strlen(bcc_list) + 4 ];
  1220.    // build the recipients list
  1221.    Recipients = new char [ strlen(destination) + strlen(cc_list) + strlen(bcc_list) + 4 ];
  1222.  
  1223.    // Parse the "To:" line
  1224.    for ( i = j = 0; i < (int) strlen(destination); i++ ) {
  1225.       // strip white space
  1226.       while ( destination[i]==' ' )
  1227.          i++;
  1228.       // look for comments in brackets, and omit
  1229.       if ( destination[i]=='(' ) {
  1230.          while ( destination[i]!=')' ) i++;
  1231.          i++;
  1232.       }
  1233.       // look for comments in quotes, and omit
  1234.       if ( destination[i]=='\'' ) {
  1235.          i++;
  1236.          while ( destination[i]!='\'' ) i++;
  1237.          i++;
  1238.       }
  1239.  
  1240.       temp[j++] = destination[i];
  1241.    }
  1242.    temp[j] = '\0';                               // End of list added!
  1243.    strcpy( Recipients, temp);
  1244.  
  1245.    // Parse the "Cc:" line
  1246.    for ( i = j = 0; i < (int) strlen(cc_list); i++ ) {
  1247.       // strip white space
  1248.       while ( cc_list[i]==' ' ) i++;
  1249.       // look for comments in brackets, and omit
  1250.       if ( cc_list[i]=='(' ) {
  1251.          while ( cc_list[i]!=')' ) i++;
  1252.          i++;
  1253.       }
  1254.       // look for comments in quotes, and omit
  1255.       if ( cc_list[i]=='\'' ) {
  1256.          i++;
  1257.          while ( cc_list[i]!='\'' ) i++;
  1258.          i++;
  1259.       }
  1260.       temp[j++] = cc_list[i];
  1261.    }
  1262.    temp[j] = '\0';                               // End of list added!
  1263.    if ( strlen(cc_list) > 0 ) {
  1264.       strcat(Recipients, "," );
  1265.       strcat(Recipients, temp);
  1266.    }
  1267.  
  1268.    // Parse the "Bcc:" line
  1269.    for ( i = j = 0; i < (int) strlen(bcc_list); i++ ) {
  1270.       // strip white space
  1271.       while ( bcc_list[i]==' ' ) i++;
  1272.       // look for comments in brackets, and omit
  1273.       if ( bcc_list[i]=='(' ) {
  1274.          while ( bcc_list[i]!=')' ) i++;
  1275.          i++;
  1276.       }
  1277.       // look for comments in quotes, and omit
  1278.       if ( bcc_list[i]=='\'' ) {
  1279.          i++;
  1280.          while ( bcc_list[i]!='\'' ) i++;
  1281.          i++;
  1282.       }
  1283.       temp[j++] = bcc_list[i];
  1284.    }
  1285.    temp[j] = '\0';                               // End of list added!
  1286.    if ( strlen(bcc_list) > 0 ) {
  1287.       strcat(Recipients, "," );
  1288.       strcat(Recipients, temp);
  1289.    }
  1290.    delete[] temp;
  1291.  
  1292.    // Generatea unique message boundary identifier.
  1293.    // Added 1.7.6 by Tim Charron (tcharron@interlog.com)
  1294.    srand( time( NULL ) );
  1295.    char boundary[23];
  1296.    char abclist[63]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
  1297.    for ( i=0 ; i<=20 ; i++ ) boundary[i] = abclist[rand()%62];
  1298.    boundary[21]=0;
  1299.    strcat(boundary,"\r\n");
  1300.  
  1301.    // create a header for the message
  1302.    char tmpstr[0x200];
  1303.    char tmpstr1[0x200];
  1304.    char tmpstr2[0x200];
  1305.    char header[0x2000];
  1306.    char header2[0x2000];
  1307.    int  headerlen;
  1308.    SYSTEMTIME curtime;
  1309.    TIME_ZONE_INFORMATION tzinfo;
  1310.    char * days[] = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
  1311.    char * months[] = { "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
  1312.    DWORD retval;
  1313.  
  1314.    GetLocalTime( &curtime );
  1315.    retval = GetTimeZoneInformation( &tzinfo );
  1316.    hours = (int) tzinfo.Bias / 60;
  1317.    minutes = (int) tzinfo.Bias % 60;
  1318.    if ( retval == TIME_ZONE_ID_STANDARD ) {
  1319.       hours += (int) tzinfo.StandardBias / 60;
  1320.       minutes += (int) tzinfo.StandardBias % 60;
  1321.    } else {
  1322.       hours += (int) tzinfo.DaylightBias / 60;
  1323.       minutes += (int) tzinfo.DaylightBias % 60;
  1324.    }
  1325.  
  1326.    // rfc1036 & rfc822 acceptable format
  1327.    // Mon, 29 Jun 94 02:15:23 GMT
  1328.    sprintf (tmpstr, "Date: %s, %.2d %s %.2d %.2d:%.2d:%.2d ",
  1329.             days[curtime.wDayOfWeek],
  1330.             curtime.wDay,
  1331.             months[curtime.wMonth - 1],
  1332.             curtime.wYear,
  1333.             curtime.wHour,
  1334.             curtime.wMinute,
  1335.             curtime.wSecond);
  1336.    strcpy( header, tmpstr );
  1337.    strcpy( header2, "");
  1338.  
  1339.    sprintf( tmpstr, "%+03d%02d", -hours, -minutes );
  1340.    //for(i=0;i<32;i++)
  1341.    //{
  1342.    // if( retval == TIME_ZONE_ID_STANDARD ) tmpstr[i] = (char) tzinfo.StandardName[i];
  1343.    // else tmpstr[i] = (char) tzinfo.DaylightName[i];
  1344.    //}
  1345.    strcat( header, tmpstr );
  1346.    strcat( header, "\r\n" );
  1347.    if ( fixup(senderid) ) mime=1;
  1348.    sprintf( tmpstr, "From: %s\r\n", senderid );
  1349.    strcat( header, tmpstr );
  1350.    if ( impersonating ) {
  1351.       if ( fixup(loginname) ) mime=1;
  1352.       sprintf( tmpstr, "Sender: %s\r\n", loginname );
  1353.       strcat( header, tmpstr );
  1354.       if ( !(penguin == 1) ) {
  1355.          sprintf( tmpstr, "Reply-to: %s\r\n", loginname );
  1356.          strcat( header, tmpstr );
  1357.       }
  1358.    }
  1359.    if ( *subject ) {
  1360.       if ( fixup(subject) ) mime=1;
  1361.       sprintf( tmpstr, "Subject: %s\r\n", subject );
  1362.       strcat( header, tmpstr );
  1363.    } else {
  1364.       if ( !(penguin == 1) ) {
  1365.          if ( lstrcmp(filename, "-") == 0 )
  1366.             sprintf( tmpstr, "Subject: Contents of console input\r\n" );
  1367.          else
  1368.             sprintf( tmpstr, "Subject: Contents of file: %s\r\n", filename );
  1369.          strcat( header, tmpstr );
  1370.       }
  1371.    }
  1372.  
  1373.    if ( fixup(destination) ) mime=1;
  1374.    sprintf( tmpstr, "To: %s\r\n", destination );
  1375.    strcat( header, tmpstr );
  1376.    if ( *cc_list ) {
  1377.       // Add line for the Carbon Copies
  1378.       if ( fixup(cc_list) ) mime=1;
  1379.       sprintf( tmpstr, "Cc: %s\r\n", cc_list );
  1380.       strcat( header, tmpstr );
  1381.    }
  1382.  
  1383.    if ( *organization ) {
  1384.       if ( fixup(organization) ) mime=1;
  1385.       sprintf( tmpstr, "Organization: %s\r\n", organization );
  1386.       strcat( header, tmpstr);
  1387.    }
  1388.  
  1389.    // This is either mime, base64, uuencoded, or neither.  With or without attachments.  Whew!
  1390.    if ( (!mime) && (!base64) ) {
  1391.       if ( attach>0 ) {
  1392.          sprintf( tmpstr, "MIME-Version: 1.0\r\n" );
  1393.          strcat( header, tmpstr );
  1394.          sprintf( tmpstr, "Content-Type: Multipart/Mixed; boundary=BlatBoundary-");
  1395.          strcat(tmpstr, boundary);
  1396.          strcat( header, tmpstr );
  1397.  
  1398.          sprintf( tmpstr, "\r\n--BlatBoundary-" );
  1399.          strcat( tmpstr, boundary );
  1400.          strcat( header2, tmpstr );
  1401.          sprintf( tmpstr, "Content-Type: text/plain; charset=US-ASCII\r\n" );
  1402.          strcat( header2, tmpstr );
  1403.          sprintf( tmpstr, "Content-Transfer-Encoding: 7BIT\r\n" );
  1404.          strcat( header2, tmpstr );
  1405.          sprintf( tmpstr, "Content-description: Mail message body\r\n" );
  1406.          strcat( header2, tmpstr );
  1407.       }
  1408.    }
  1409.    if ( mime ) {
  1410.       // Indicate MIME version and type
  1411.       sprintf( tmpstr, "MIME-Version: 1.0\r\n" );
  1412.       strcat( header, tmpstr );
  1413.       sprintf( tmpstr1, "Content-Type: text/plain; charset=ISO-8859-1\r\n" );
  1414.       sprintf( tmpstr2, "Content-Transfer-Encoding: quoted-printable\r\n" );
  1415.       if ( attach>0 ) {
  1416.          sprintf( tmpstr, "Content-Type: Multipart/Mixed; boundary=BlatBoundary-" );
  1417.          strcat( tmpstr, boundary );
  1418.          strcat( header, tmpstr );
  1419.  
  1420.          sprintf( tmpstr, "\r\n--BlatBoundary-" );
  1421.          strcat( tmpstr, boundary );
  1422.          strcat( header2, tmpstr );
  1423.          strcat( header2, tmpstr1 );
  1424.          strcat( header2, tmpstr2 );
  1425.       } else {
  1426.          strcat( header, tmpstr1 );
  1427.          strcat( header, tmpstr2 );
  1428.       }
  1429.    }
  1430.    if ( base64 ) {
  1431.       // Indicate MIME version and type
  1432.       sprintf( tmpstr, "MIME-Version: 1.0\r\n" );
  1433.       strcat( header, tmpstr );
  1434.       sprintf( tmpstr, "Content-Type: Multipart/Mixed; boundary=BlatBoundary-" );
  1435.       strcat( tmpstr, boundary );
  1436.       strcat( header, tmpstr );
  1437.       sprintf( tmpstr, "\r\n--BlatBoundary-" );
  1438.       strcat( tmpstr, boundary );
  1439.       strcat( header2, tmpstr );
  1440.       if ( lstrcmp(filename, "-") == 0 ) {
  1441.          sprintf( tmpstr, "Content-Type: application/octet-stream; name=stdin.txt\r\n" );
  1442.       } else {
  1443.          sprintf( tmpstr, "Content-Type: application/octet-stream; name=%s\r\n",
  1444.                   GetNameWithoutPath(filename) );
  1445.       }
  1446.       strcat( header2, tmpstr );
  1447.       if ( lstrcmp(filename, "-") == 0 ) {
  1448.          sprintf( tmpstr, "Content-Disposition: attachment; filename=\"stdin.txt\"\r\n");
  1449.       } else {
  1450.          sprintf( tmpstr, "Content-Disposition: attachment; filename=\"%s\"\r\n",
  1451.                   GetNameWithoutPath(filename) );
  1452.       }
  1453.       strcat( header2, tmpstr );
  1454.       sprintf( tmpstr, "Content-Transfer-Encoding: BASE64\r\n" );
  1455.       strcat( header2, tmpstr );
  1456.    }
  1457.  
  1458.    if ( noheader == 0 ) {
  1459.       strcat( header, "X-Mailer: WinNT's Blat ver 1.8 http://www.interlog.com/~tcharron\r\n" );
  1460.       strcat( header, header2 );
  1461.    } else if ( noheader == 1 ) {
  1462.       strcat( header, "X-Mailer: WinNT's Blat ver 1.8\r\n" );
  1463.       strcat( header, header2 );
  1464.    }                                             // noheader==2 means to omit X-Mailer header.
  1465.  
  1466.    if ( !(penguin == 1) )
  1467.       strcat( header, "\r\n" );
  1468.  
  1469.    headerlen = strlen( header );
  1470.  
  1471.    // if reading from the console, read everything into a temporary file first
  1472.    if ( lstrcmp(filename, "-") == 0 ) {
  1473.       // create a unique temporary file name
  1474.       GetTempPath( MAX_PATH, tempdir );
  1475.       GetTempFileName( tempdir, "blt", 0, tempfile );
  1476.  
  1477.       // open the file in write mode
  1478.       tf = fopen(tempfile,"w");
  1479.       if ( tf==NULL ) {
  1480.          if ( ! quiet ) printf("error opening temporary file %s, aborting\n",filename);
  1481.          delete [] Recipients;
  1482.          return(13);
  1483.       }
  1484.  
  1485.       do {
  1486.          DWORD dwNbRead = 0;
  1487.          i=0;
  1488.  
  1489.          if ( !ReadFile(GetStdHandle(STD_INPUT_HANDLE),&i,1,&dwNbRead,NULL) )
  1490.             //if (GetLastError()==ERROR_HANDLE_EOF)
  1491.             i=EOF;
  1492.          if ( i=='\x1A' )
  1493.             i=EOF;
  1494.          if ( i != EOF ) putc( i, tf );
  1495.       } while ( i != EOF );
  1496.  
  1497.       fclose( tf );
  1498.       strcpy(filename, tempfile);
  1499.    }
  1500.  
  1501.    //get the text of the file into a string buffer
  1502.    if ( (fileh=CreateFile(filename,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,
  1503.                           FILE_FLAG_SEQUENTIAL_SCAN,NULL))==INVALID_HANDLE_VALUE ) {
  1504.       if ( ! quiet ) printf("error reading %s, aborting\n",filename);
  1505.       delete [] Recipients;
  1506.       return(3);
  1507.    }
  1508.    if ( GetFileType(fileh)!=FILE_TYPE_DISK ) {
  1509.       if ( ! quiet ) printf("Sorry, I can only mail messages from disk files...\n");
  1510.       delete [] Recipients;
  1511.       return(4);
  1512.    }
  1513.    DWORD filesize = GetFileSize( fileh,NULL );
  1514.  
  1515.    // Oversized buffer for output message...
  1516.    // Quoted printable takes the most space...up to 3 bytes/byte + LFs
  1517.    // base64 uses CR every 54 bytes
  1518.    // 0x1000 is for the minimal Mime/UUEncode header
  1519.    int bufsize;
  1520.    bufsize = (3*(filesize+filesize/54))+headerlen+1+0x1000+strlen(filename);
  1521.  
  1522.    char *buffer = new char[bufsize];
  1523.    char *filebuffer = new char[filesize+1+4];
  1524.    char *tmpptr;
  1525.    char *q;
  1526.    char *p;
  1527.    char buffer2[240];
  1528.  
  1529.    // put the header at the top...
  1530.    strcpy( buffer, header );
  1531.    // point to the end of the header
  1532.    tmpptr = buffer + headerlen;
  1533.    // and put the whole file there
  1534.    DWORD dummy;
  1535.    if ( !ReadFile(fileh,filebuffer,filesize,&dummy,NULL) ) {
  1536.       if ( ! quiet ) printf("error reading %s, aborting\n",filename);
  1537.       CloseHandle(fileh);
  1538.       delete [] buffer;
  1539.       delete [] filebuffer;
  1540.       delete [] Recipients;
  1541.       return(5);
  1542.    }
  1543.    CloseHandle(fileh);
  1544.  
  1545.    q = filebuffer + filesize;
  1546.    (*q) = (*(q+1)) = (*(q+2)) = (*(q+3)) = (*(q+4)) = '\0';
  1547.  
  1548.    // MIME Quoted-Printable Content-Transfer-Encoding
  1549.    // or BASE64 encoding of main file.
  1550.    // or UUencoding of main file
  1551.    // or nothing special...
  1552.    if ( ! mime ) {
  1553.       if ( ! base64 ) {
  1554.          if ( ! uuencode ) {
  1555.             strcpy( tmpptr, filebuffer );
  1556.          } else {
  1557.             douuencode(filebuffer,tmpptr,filesize,filename);
  1558.          }
  1559.       } else {
  1560.          base64_encode(filebuffer,q,tmpptr);
  1561.       }
  1562.    } else {
  1563.       int PosValue = 0;
  1564.       int *Pos;
  1565.       char workbuf [8];
  1566.       Pos = &PosValue;
  1567.       p = filebuffer;
  1568.       while ( p < q ) {
  1569.          ConvertToQuotedPrintable(*p,Pos, workbuf);
  1570.          strcat(tmpptr,workbuf);
  1571.          *p++;
  1572.       }
  1573.    }
  1574.  
  1575.    // delete the temporary file if it has been used
  1576.    if ( *tempfile ) remove( tempfile );
  1577.  
  1578.    // make some noise about what we are doing
  1579.    if ( ! quiet ) {
  1580.       printf("Sending %s to %s\n",filename,(lstrlen(Recipients) ? Recipients : "<unspecified>"));
  1581.       if ( lstrlen(subject) ) printf("Subject:%s\n",subject);
  1582.       if ( lstrlen(loginname) ) printf("Login name is %s\n",loginname);
  1583.    }
  1584.  
  1585.    // Process any attachments
  1586.    HANDLE ihandle;
  1587.    int filewasfound=0;
  1588.    char path[MAX_PATH+1];
  1589.    char * pathptr;
  1590.    if ( attach>0 ) {
  1591.       for ( i=0;i<attach;i++ ) {
  1592.          if ( (!quiet) & (attachtype[i] == 1) ) {
  1593.             printf("Attached binary file: %s\n",attachfile[i]);
  1594.          } else {
  1595.             printf("Attached text file: %s\n",attachfile[i]);
  1596.          }
  1597.  
  1598. // Modification C.Henquin, 1998-06-12: Add support for wildcard
  1599.  
  1600.          // Get the path for opening file
  1601.          strcpy(path,attachfile[i]);
  1602.          pathptr=strrchr(path,'\\');
  1603.          if ( NULL != pathptr ) {
  1604.             *(pathptr+1) = 0;
  1605.          } else {
  1606.             strcpy(path, "");
  1607.          }
  1608.  
  1609.          ihandle = FindFirstFile(attachfile[i], & FindFileData);
  1610.          if ( ihandle == INVALID_HANDLE_VALUE ) {
  1611.             if ( !quiet ) printf("File not found: %s\n",attachfile[i]);
  1612.             filewasfound=0;
  1613.          } else {
  1614.             filewasfound=1;
  1615.          }
  1616.          while ( filewasfound != 0 ) {
  1617.             strcpy(attachedfile, path);
  1618.             strcat(attachedfile,FindFileData.cFileName);
  1619.             shortname = strrchr(attachedfile,'\\');
  1620.             if ( shortname==NULL ) {
  1621.                shortname=attachedfile;
  1622.             } else {
  1623.                shortname = shortname+1;
  1624.             }
  1625.             if ( (!quiet) && (   (NULL!=strchr(attachfile[i],'?'))
  1626.                                  || (NULL!=strchr(attachfile[i],'*')) ) )
  1627.                printf("  found %s\n",attachedfile);
  1628.             // Do the header bit...
  1629.             sprintf( header, "\r\n--BlatBoundary-" );
  1630.             strcat( header, boundary );
  1631.             if ( attachtype[i] == 1 ) {
  1632.                sprintf( tmpstr1, "Content-Type: application/octet-stream; name=%s\r\n", shortname );
  1633.                sprintf( tmpstr2, "Content-Disposition: attachment; filename=\"%s\"\r\n", shortname );
  1634.                strcat(  tmpstr2, "Content-Transfer-Encoding: BASE64\r\n" );
  1635.             } else {
  1636.                sprintf( tmpstr1, "Content-Type: text/plain; charset=US-ASCII\r\n" );
  1637.                strcat(  tmpstr1, "Content-Disposition: inline\r\n");
  1638.                sprintf( tmpstr2, "Content-description: %s\r\n", shortname );
  1639.             }
  1640.             strcat( header, tmpstr1 );
  1641.             strcat( header, tmpstr2 );
  1642.  
  1643.             if ( !(penguin == 1) )
  1644.                strcat( header, "\r\n" );
  1645.             headerlen = strlen( header );
  1646.             bufsize += headerlen;
  1647.             buffer = (char *) realloc( buffer , bufsize );
  1648.             // put the header at the end of existing message...
  1649.             strcat( buffer, header );
  1650.  
  1651.             //get the text of the file into a string buffer
  1652.             if ( (fileh=CreateFile(attachedfile,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,
  1653.                                    FILE_FLAG_SEQUENTIAL_SCAN,NULL))==INVALID_HANDLE_VALUE ) {
  1654.                if ( ! quiet ) printf("error reading %s, aborting\n",attachedfile);
  1655.                delete [] Recipients;
  1656.                return(3);
  1657.             }
  1658.             if ( GetFileType(fileh)!=FILE_TYPE_DISK ) {
  1659.                if ( ! quiet ) printf("Sorry, I can only mail messages from disk files...\n");
  1660.                delete [] Recipients;
  1661.                return(4);
  1662.             }
  1663.             filesize = GetFileSize( fileh,NULL );
  1664.  
  1665. // Until 1.7.3, this was using 72 instead of 54.  tcharron@interlog.com
  1666.             bufsize += (4*(filesize+3))/3+2*((filesize+53)/54)+3 ;
  1667.  
  1668.             buffer = (char *) realloc( buffer , bufsize );
  1669.             filebuffer = (char *) realloc( filebuffer, filesize+1+4 );
  1670.  
  1671.             if ( !ReadFile(fileh,filebuffer,filesize,&dummy,NULL) ) {
  1672.                if ( ! quiet ) printf("error reading %s, aborting\n",filename);
  1673.                CloseHandle(fileh);
  1674.                delete [] buffer;
  1675.                delete [] filebuffer;
  1676.                delete [] Recipients;
  1677.                return(5);
  1678.             }
  1679.             CloseHandle(fileh);
  1680.  
  1681.             q = filebuffer + filesize;
  1682.             (*q) = (*(q+1)) = (*(q+2)) = (*(q+3)) = (*(q+4)) = '\0';
  1683.  
  1684.             tmpptr = buffer + strlen(buffer);
  1685.             p = filebuffer;
  1686.             if ( attachtype[i] == 1 ) {
  1687.                base64_encode(p,q,tmpptr);
  1688.             } else {
  1689.                while ( p<=q ) {
  1690.                   *tmpptr = *p;
  1691.                   tmpptr++;
  1692.                   p++;
  1693.                }
  1694.             }
  1695.             filewasfound=FindNextFile(ihandle, & FindFileData);
  1696.          }
  1697.          FindClose( ihandle );
  1698.       }
  1699.    }
  1700.  
  1701.    // v1.7.9  9/10/1998 by Toby Korn (tkorn@snl.com)
  1702.    // Added this to add a terminating MIME boundary - omission of
  1703.    // a terminating boundary was causing some e-mail systems to not
  1704.    // process the message properly.
  1705. // Removed 1.8 -- this addition confuses some e-mail systems!
  1706. //   if ( (attach>0) || (base64) ) {
  1707. //      bufsize += 17 + strlen(boundary);             // Tim 98.9.16
  1708. //      buffer = (char *) realloc( buffer , bufsize );// Tim 98.9.16
  1709. //      strcat (buffer, "\r\n--BlatBoundary-");
  1710. //      strcat (buffer, boundary );
  1711. //      strcat (buffer, "\r\n");
  1712. //   }
  1713.  
  1714.    // send the message to the SMTP server!
  1715.    n_of_try = noftry();
  1716.    for ( k=1; k<=n_of_try || n_of_try == -1; k++ ) {
  1717.       if ( (!quiet) && (n_of_try > 1) ) printf("\nTry number %d of %d.\n", k, n_of_try);
  1718.  
  1719.       if ( k > 1 ) {
  1720.          dwordTime=GetCurrentTime();
  1721.          while ( GetCurrentTime()-dwordTime <= 15 ) {
  1722.          }
  1723.       }
  1724.  
  1725.       retcode = prepare_smtp_message( loginname, Recipients, my_hostname_wanted);
  1726.       if ( 0 == retcode ) {
  1727.          retcode = send_smtp_edit_data( buffer );
  1728.          if ( 0 == retcode ) {
  1729.             finish_smtp_message();
  1730.             n_of_try = k;
  1731.             k = n_of_try+1;
  1732.          }
  1733.          close_smtp_socket();
  1734.       }
  1735.    }
  1736.  
  1737.    delete [] buffer;
  1738.    delete [] filebuffer;
  1739.    delete [] Recipients;
  1740.    return(abs(retcode));
  1741. }
  1742.  
  1743.