head	1.29;
access;
symbols
	V0-99-8:1.29
	V0-99-7:1.28
	V0-99-6:1.28
	V0-99-5:1.28
	V0-99-4:1.27
	V0-99-2:1.25
	V0-99-1:1.25
	V0-93-14:1.25
	V0-93-13:1.25
	V0-93-12:1.25
	V0-93-11:1.23
	V0-93-10:1.22
	V0-93-9:1.22
	V0-93-8:1.22
	V0-93-7:1.21
	V0-93-5:1.20;
locks; strict;
comment	@ * @;


1.29
date	96.08.13.04.55.55;	author dumoulin;	state Exp;
branches;
next	1.28;

1.28
date	95.06.06.04.12.22;	author ishido;	state Exp;
branches;
next	1.27;

1.27
date	95.05.20.01.21.08;	author dumoulin;	state Exp;
branches;
next	1.26;

1.26
date	95.05.20.01.16.05;	author dumoulin;	state Exp;
branches;
next	1.25;

1.25
date	95.01.11.21.58.54;	author rushing;	state Exp;
branches;
next	1.24;

1.24
date	95.01.11.21.16.06;	author rushing;	state Exp;
branches;
next	1.23;

1.23
date	94.12.21.19.09.23;	author rushing;	state Exp;
branches;
next	1.22;

1.22
date	94.11.28.22.01.06;	author jcooper;	state Exp;
branches;
next	1.21;

1.21
date	94.11.21.21.20.46;	author jcooper;	state Exp;
branches;
next	1.20;

1.20
date	94.11.10.01.27.39;	author rushing;	state Exp;
branches;
next	;


desc
@generic socket DLL interface
@


1.29
log
@add date to SMTP messages
@
text
@/* Interface to GENSOCK module */
/* $Id: wvsckgen.c 1.28 1995/06/06 04:12:22 ishido Exp $ */

#include <windows.h>
#include <windowsx.h>
#include "wvglob.h"
#include "winvn.h"
#pragma hdrstop
#include <stdlib.h>
#include <stdio.h>				/* for sprintf */
#include <stdarg.h>				/* for varargs stuff */
#include <ctype.h>				/* for isspace */
#define MAXSENDLEN 32767
#define COMMBUFSIZE	1600

/* generic socket DLL support */
#include "gensock\\gensock.h"

char CommBuff[COMMBUFSIZE];
int CommBuffIdx = COMMBUFSIZE + 1;
int CharsInCommBuff = 0;

socktag NNTPSock = 0;
socktag SMTPSock = 0;
char my_hostname[256];

/* functions the rest of winvn expects to see */
void PutCommLine (char *line);
void PutCommData (char *data, unsigned int length);

int MRRReadComm (void);
void MRRCloseComm (void);
int MRRInitComm (void);

/* internal to this file */
int open_smtp_socket (void);
void smtp_error (char *message);
int finish_smtp_message (void);
int get_smtp_line (void);
int put_smtp_line (socktag sock, char far * line, unsigned int nchars);

HINSTANCE gensock_lib = 0;

int (FAR PASCAL * pgensock_connect) (char FAR * hostname, char FAR * service, socktag FAR * pst);
int (FAR PASCAL * pgensock_getchar) (socktag st, int wait, char FAR * ch);
int (FAR PASCAL * pgensock_put_data) (socktag st, char FAR * data, unsigned long length);
int (FAR PASCAL * pgensock_close) (socktag st);
int (FAR PASCAL * pgensock_gethostname) (char FAR * name, int namelen);
int (FAR PASCAL * pgensock_put_data_buffered) (socktag st, char FAR * data, unsigned long length);
int (FAR PASCAL * pgensock_put_data_flush) (socktag st);


/*-- function MRRReadComm ---------------------------------------
 *
 *  Reads characters from the NNTP Socket
 */

#define ERROR_BUFFER_SIZE 1024

void
complain (int err, char *function, char *fmt,...)
{
  va_list marker;
  char message[ERROR_BUFFER_SIZE];
  char message1[100];
  int done = 0;
  static int messageOnScreen = FALSE; /* avoid cascading errors --> stack crash */

  /* Write text to a string and output the string. */
  if (!messageOnScreen) {
    va_start (marker, fmt);
    _vsnprintf (message, ERROR_BUFFER_SIZE, fmt, marker);
    va_end (marker);
	if (err >=0)
	   wsprintf (message1, "Error %d - Function '%s'",err,function);
	else
	   wsprintf (message1, "WinVN Function '%s'",function);
	messageOnScreen = TRUE;
    MessageBox (NetDoc.hDocWnd, message, message1, MB_OK);
	messageOnScreen = FALSE;
  }
}

void
gensock_error (char *function, int retval)
{
  char error_string[512];
  int len;

  len = LoadString (hInst, retval, error_string, sizeof (error_string));
  complain (retval,function,"%s",
			len == 0 ? "[couldn't get error string]" : error_string);
}

int 
MRRReadComm ()
{
  int retval;
  unsigned char ch;

  /* we set wait = 1, sortof non-blocking */
  if (NNTPSock && (retval = (*pgensock_getchar) (NNTPSock, 1, (char FAR *)&ch))) {
	switch (retval) {
	case WAIT_A_BIT:
	case ERR_BUSY:
	  break;
	case ERR_NOT_CONNECTED:
	  Initializing = INIT_NOT_CONNECTED;
	  SendMessage (NetDoc.hDocWnd, (UINT) WM_COMMAND,
				   (WPARAM) IDM_DISCONNECT, (LPARAM) 0);
	  Disconnect ();
	  complain (-1,"MRRReadComm","NNTP server has closed the connection");
	  return (-1);
	  break;
	default:
	  gensock_error ("gensock_getchar", retval);
	}
	return (-1);
  }
  else
	return ((int) ch);
}

int
putline_internal (socktag sock, char *line, unsigned int nchars)
{
  int retval;

  if (sock && (retval =
	   (*pgensock_put_data) (sock,
							 (char FAR *) line,
							 (unsigned long) nchars))) {
	switch (retval) {
	case ERR_NOT_CONNECTED:
	  Initializing = INIT_NOT_CONNECTED;
	  SendMessage (NetDoc.hDocWnd, (UINT) WM_COMMAND,
				   (WPARAM) IDM_DISCONNECT, (LPARAM) 0);
	  Disconnect ();
	  complain (-1,"PutLine_Internal","NNTP server has closed the connection");
	  return (-1);
	  break;

	default:
	  gensock_error ("gensock_put_data", retval);
	}
	return (-1);
  }
  return (0);
}

/* PutCommLine takes a string, sends it, followed by
 * \r\n.  All one-line sends in winvn should use this.
 */

void
PutCommLine (char *line)
{
  putline_internal (NNTPSock, line, lstrlen (line));
  putline_internal (NNTPSock, "\r\n", 2);
}

/* Use this function for sending larger chunks of data.
 * the text data from an Edit class window can be sent
 * using this function
 */

void
PutCommData (char *data, unsigned int length)
{
  putline_internal (NNTPSock, data, length);
}

/*-- function MRRCloseComm -----------------------------------------
 *
 *  Close the communications port, serial or TCP.
 */
void 
MRRCloseComm ()
{
  if (NNTPSock) {
	(*pgensock_close) (NNTPSock);
	NNTPSock = (socktag) 0;
  }
  if (!SMTPSock && gensock_lib) {
	FreeLibrary (gensock_lib);
	gensock_lib = 0;
  }
  CommState = ST_CLOSED_COMM;
  SetStatbarText (NetDoc.hWndFrame, "", &NetDoc, TRUE, TRUE);
  InvalidateRect (NetDoc.hDocWnd, NULL, TRUE);
}

int
load_gensock ()
{
  int result = 0;

#ifdef WIN32
  if ((gensock_lib = LoadLibrary (GenSockDLL)) == NULL) {
#else
  if ((gensock_lib = LoadLibrary (GenSockDLL)) < HINSTANCE_ERROR) {
#endif
	char message[256];
	wsprintf (message, "Couldn't load '%s'", GenSockDLL);
	complain (-1,"Load_Gensock",message);
	gensock_lib = 0;
	return (-1);
  }

  if (!result && (pgensock_connect =
          (int (FAR PASCAL *) (char FAR *, char FAR *, socktag FAR *))
				  GetProcAddress (gensock_lib, "gensock_connect")) == NULL) {
	complain (-1,"Load_Gensock","couldn't getprocaddress for gensock_connect");
	result = -1;
  }

  if (!result && (pgensock_getchar =
          (int (FAR PASCAL *) (socktag, int, char FAR *))
				  GetProcAddress (gensock_lib, "gensock_getchar")) == NULL) {
	complain (-1,"Load_Gensock","couldn't getprocaddress for gensock_getchar");
	result = -1;
  }

  if (!result && (pgensock_put_data =
        (int (FAR PASCAL *) (socktag, char FAR *, unsigned long))
				GetProcAddress (gensock_lib, "gensock_put_data")) == NULL) {
	complain (-1,"Load_Gensock","couldn't getprocaddress for gensock_put_data");
	result = -1;
  }

  if (!result && (pgensock_close =
          (int (FAR PASCAL *) (socktag))
				  GetProcAddress (gensock_lib, "gensock_close")) == NULL) {
	complain (-1,"Load_Gensock","couldn't getprocaddress for gensock_close");
	result = -1;
  }

  if (!result && (pgensock_gethostname =
       (int (FAR PASCAL *) (char FAR *, int))
			 GetProcAddress (gensock_lib, "gensock_gethostname")) == NULL) {
	complain (-1,"Load_Gensock","couldn't getprocaddress for gensock_gethostname");
	result = -1;
  }

  if (!result && (pgensock_put_data_buffered =
     (int (FAR PASCAL *) (socktag, char FAR *, unsigned long))
	   GetProcAddress (gensock_lib, "gensock_put_data_buffered")) == NULL) {
	complain (-1,"Load_Gensock","couldn't getprocaddress for gensock_put_data_buffered");
	result = -1;
  }

  if (!result && (pgensock_put_data_flush =
      (int (FAR PASCAL *) (socktag))
		  GetProcAddress (gensock_lib, "gensock_put_data_flush")) == NULL) {
	complain (-1,"Load_Gensock","couldn't getprocaddress for gensock_put_data_flush");
	result = -1;
  }

  if (result) {
	FreeLibrary (gensock_lib);
	gensock_lib = 0;
  }
  return (result);
}

int
MRRInitComm ()
{
  int retval;

  /* load the library if it's not loaded */
  if (!gensock_lib) {
	if ((retval = load_gensock ())) {
	  return (retval);
	}
  }

  /* to keep our sanity, we will quietly try '119' in case it fails */
  if ((retval = (*pgensock_connect) ((LPSTR) NNTPHost,
									 (LPSTR) NNTPService,
									 &NNTPSock))) {
	if (retval == ERR_CANT_RESOLVE_SERVICE) {
	  if ((retval = (*pgensock_connect) ((LPSTR) NNTPHost,
										 (LPSTR) "119",
										 &NNTPSock))) {
		gensock_error ("gensock_connect", retval);
		return (-1);
	  }
	}
	/* error other than can't resolve service */
	else {
	  gensock_error ("gensock_connect", retval);
	  return (-1);
	}
  }

  IgnoreCommCh = '\r';
  EOLCommCh = '\n';

  CommLinePtr = CommLineIn;
  CommState = ST_ESTABLISH_COMM;
  CommBusy = FALSE;
  return (0);
}

/* ---------------------------------------------------------------------------
 * open/close SMTP socket
 */

void 
abort_mail_socket ()
{
  /* in case we're _not_ connected to a NNTP server, and
   * we just used SMTP mail only, then we probably want to
   * close the library...
   */
  SMTPSock = 0;
  if (!NNTPSock && gensock_lib) {
	FreeLibrary (gensock_lib);
	gensock_lib = 0;
  }
}

int 
open_smtp_socket ()
{
  int retval;

  if (gensock_lib && SMTPSock)	// already open

	return 0;

  /* load the library if it's not loaded */
  if (!gensock_lib) {
	if ((retval = load_gensock ())) {
	  return (retval);
	}
  }

  if ((retval = (*pgensock_connect) ((LPSTR) SMTPHost,
									 (LPSTR) "smtp",
									 &SMTPSock))) {
	if (retval == ERR_CANT_RESOLVE_SERVICE ||
		retval == ERR_NO_ERROR_CODE) {		/* Chameleon is bad, it fails but sets no error code. */
	  if ((retval = (*pgensock_connect) ((LPSTR) SMTPHost,
										 (LPSTR) "25",
										 &SMTPSock))) {
		gensock_error ("gensock_connect", retval);
		abort_mail_socket ();
		return (-1);
	  }
	}
	/* error other than can't resolve service */
	else {
	  gensock_error ("gensock_connect", retval);
	  abort_mail_socket ();
	  return (-1);
	}
  }

  /* we wait to do this until here because WINSOCK is
   * guaranteed to be already initialized at this point.
   */

  /* get the local hostname (needed by SMTP) */
  if ((retval = (*pgensock_gethostname) (my_hostname, sizeof (my_hostname)))) {
    /* This is failing very often, I hope no smtp server complains too loudly */
    strcpy (my_hostname, "idunnomyownname");
#if 0
    gensock_error ("gensock_gethostname", retval);
    abort_mail_socket ();
    return (-1);
#endif
  }
  return 0;
}

int 
close_smtp_socket ()
{
  int retval = 0;

  if (SMTPSock) {
	if ((retval = (*pgensock_close) (SMTPSock))) {
	  gensock_error ("gensock_close", retval);
	}
  }
  abort_mail_socket ();

  return (retval);
}

/* ---------------------------------------------------------------------------
 * internal SMTP functions
 */

int 
get_smtp_line ()
{
  char ch = '.';
  char in_data[MAXOUTLINE];
  char *index;
  int retval = 0;

  index = in_data;

  while (ch != '\n') {
	if ((retval = (*pgensock_getchar) (SMTPSock, 0, &ch))) {
	  gensock_error ("gensock_getchar", retval);
	  return (-1);
	}
	else {
	  *index = ch;
	  index++;
	}
  }

  /* this is to support multi-line responses, common with */
  /* servers that speak ESMTP */

  /* I know, I know, it's a hack 8^) */
  if (in_data[3] == '-')
	return (get_smtp_line ());
  else
	return (atoi (in_data));
}

int 
put_smtp_line (socktag sock, char far * line, unsigned int nchars)
{
  int retval;

  if (!sock || (retval = (*pgensock_put_data) (sock, line, (unsigned long) nchars))) {
	gensock_error ("gensock_put_data", retval);
	return (-1);
  }
  return (0);
}

int 
finish_smtp_message ()
{
  int retval;

  if ((retval = (*pgensock_put_data_flush) (SMTPSock))) {
	return (retval);
  }
  return (put_smtp_line (SMTPSock, "QUIT\r\n", 6));
}

void 
smtp_error (char *message)
{
  MessageBox (NetDoc.hDocWnd, message, "WinVN", MB_OK);
  put_smtp_line (SMTPSock, "QUIT\r\n", 6);
  close_smtp_socket ();
}

/* ---------------------------------------------------------------------------
 * The following are entry points
 * all return 0 on success or non-zero on fail
 */

int
end_post ()
{
  int retval;

  if ((retval = (*pgensock_put_data_buffered) (NNTPSock, ".\r\n", 3))) {
	return (retval);
  }
  if ((retval = (*pgensock_put_data_flush) (NNTPSock))) {
	return (retval);
  }
  // DEBUG_BREAK; // verify this as proper return value...
  return 0;
}

int
end_send_smtp ()
{
  int retval;

  if ((retval = (*pgensock_put_data_buffered) (SMTPSock, ".\r\n", 3))) {
	return (retval);
  }

  if ((retval = (*pgensock_put_data_flush) (SMTPSock))) {
	return (retval);
  }

  retval = get_smtp_line ();
  if (retval != 250 && retval != 251) {
	smtp_error ("Message not accepted by server");
	return -1;
  }
  finish_smtp_message ();
  close_smtp_socket ();

  return 0;
}


int
send_smtp_line (char *str, unsigned long len)
{
  int retval;

  if (*str == '.' &&			/* if line starts with dot, send two dots */
	  (retval = (*pgensock_put_data_buffered) (SMTPSock, str, 1))) {
	return (retval);
  }
  return ((*pgensock_put_data_buffered) (SMTPSock, str, len));
}

int
post_line (char *str, unsigned long len)
{
  int retval;

  if (*str == '.' &&			/* if line starts with dot, send two dots */
	  (retval = (*pgensock_put_data_buffered) (NNTPSock, str, 1))) {
	return (retval);
  }
  return ((*pgensock_put_data_buffered) (NNTPSock, str, len));
}

/* prepare_smtp_message
 * headers is a textblock containing the header lines for this mail
 * grab the From, To and any Cc from here to generate From: and RCPT:
 * SMTP commands
 */
int
prepare_smtp_message (TypTextBlock * headers)
{
  char out_data[MAXOUTLINE], address[MAXHEADERLINE];
  char *ptr, *line;
  int len, startLen, result;
  unsigned long i;

  if (open_smtp_socket ())
	return (-1);

  if (get_smtp_line () != 220) {
	smtp_error ("SMTP server error");
	return (-1);
  }

  sprintf (out_data, "HELO %s\r\n", my_hostname);
  put_smtp_line (SMTPSock, out_data, strlen (out_data));

  if (get_smtp_line () != 250) {
	smtp_error ("SMTP server error");
	return (-1);
  }

  for (i = 0; i < headers->numLines; i++) {
	line = TextBlockLine (headers, i);
	if (!_strnicmp (line, "from: ", 6))
	  break;
  }
  if (i < headers->numLines)
	ParseAddress (&line[6], address, MAXHEADERLINE, str, MAXINTERNALLINE);
  else
	strcpy (address, MailAddress);

  ptr = &address[strlen (address) - 1];
  while (isspace (*ptr))
	*ptr-- = '\0';				/* strip trailing space */
  sprintf (out_data, "MAIL From:<%s>\r\n", address);
  put_smtp_line (SMTPSock, out_data, strlen (out_data));

  if (get_smtp_line () != 250) {
	smtp_error ("The mail server doesn't like the sender name, "
				"have you set your mail address correctly?");
	return (-1);
  }

  /* do a series of RCPT lines for all To: addresses and Cc: address */
  for (i = 0; i < headers->numLines; i++) {
	line = TextBlockLine (headers, i);

	if (!_strnicmp (line, "to: ", 4) || !_strnicmp (line, "cc: ", 4)) {
	  ptr = strcpy (address, &line[4]);
	  while (*ptr) {
		// if there's only one token left, then len will = startLen,
		// and we'll iterate once only
		startLen = strlen (ptr);
		if ((len = strcspn (ptr, " ,\n\t\r")) != startLen) {
		  ptr[len++] = '\0';	// replace delim with NULL char

		  while (isspace (ptr[len]) || ptr[len] == ',')		// eat white space

			ptr[len++] = '\0';
		}

		sprintf (out_data, "RCPT To: <%s>\r\n", ptr);
		putline_internal (SMTPSock, out_data, strlen (out_data));

		result = get_smtp_line ();
		if (result != 250 && result != 251) {
		  sprintf (str, "The mail server doesn't like the name %s.  "
				   "Have you set the 'To: ' field correctly?", ptr);
		  smtp_error (str);
		  return (-1);
		}

		if (len == startLen)	// last token, we're done

		  break;

		ptr += len;
	  }							/* RCPT loop */
	}							/* if To: or Cc: */
  }								/* for header lines */

  sprintf (out_data, "DATA\r\n");
  put_smtp_line (SMTPSock, out_data, strlen (out_data));

  if (get_smtp_line () != 354) {
	smtp_error ("Mail server error accepting message data");
	return (-1);
  }

  return (0);

}

/* prepare_cc_smtp_message
 * destination is the address(es) to forward to
 * headers is a textblock containing the header lines for mail to be forwarded
 */
int 
prepare_cc_smtp_message (char *destination, TypTextBlock * headers)
{
  register unsigned long i;
  char toLine[MAXOUTLINE];
  char DateLine[MAXHEADERLINE];
  char contents[MAXHEADERLINE];
  char  *fromLine;
  TypTextBlock *tempHeader;
  int retval;

  /* create temporary header block containing only a To: and a From: 
   * to make prepare_smtp_message happy
   */
  if ((tempHeader = InitTextBlock (NetDoc.hDocWnd)) == NULL)
        return 1;
  _snprintf (toLine, MAXOUTLINE, "To: %s\r\n", destination);
  retval = AddLineToTextBlock (tempHeader, toLine);

  if (!retval) {
        /* copy From: line from real headers */
        for (i = 0; i < headers->numLines; i++) {
          fromLine = TextBlockLine (headers, i);
          if (!_strnicmp (TextBlockLine (headers, i), "from: ", 6))
                break;
        }
        if (i < headers->numLines) {
          retval = AddLineToTextBlock (tempHeader, fromLine);
        }
  }
  if ( (!retval)  && GetDate (contents, MAXHEADERLINE)) {
        _snprintf (DateLine, MAXHEADERLINE, "Date: %s\r\n", contents);
        retval = AddLineToTextBlock (tempHeader, DateLine);//Heirich 19960729 
/* adding is not needed yet, but keep headerblocks current for defensive 
programming */
  }
  retval = retval ||
        prepare_smtp_message (tempHeader) ||
        put_smtp_line (SMTPSock, toLine, lstrlen (toLine)) ||
        put_smtp_line (SMTPSock, DateLine, lstrlen (DateLine));

  FreeTextBlock (tempHeader);
  return (retval);
}

#ifdef OLD_STUFF
int send_smtp_message (TypTextBlock * headers, char *message);
int cc_smtp_message (char *destination, TypTextBlock * headers, char *editstr);
int post_edit_data (char *edit_data);
int post_unended_edit_data (char *edit_data);
int send_smtp_edit_data (char *edit_data);
int send_smtp_unended_edit_data (char *edit_data);
int post_textblock (TypTextBlock * textBlock);
int send_smtp_textblock (TypTextBlock * textBlock);

int forward_smtp_message (char *destination, TypDoc * Doc);
int send_smtp_article (char *destination, TypDoc * Doc);
int send_textblock_internal (socktag sock, TypTextBlock * textBlock);
int prepare_smtp_message (TypTextBlock * headers);


/* ---------------------------------------------------------------------------
 * transform_and_send_edit_data
 */

int 
transform_and_send_edit_data (socktag sock, char *editptr)
{
  char *index;
  char previous_char = 'x';
  unsigned int send_len;
  int retval;
  BOOL done = 0;

  send_len = lstrlen (editptr);
  index = editptr;

  while (!done) {
	/* room for extra char for double dot on end case */
	while ((unsigned int) (index - editptr) < send_len) {
	  switch (*index) {
	  case '.':
		if (previous_char == '\n') {
		  /* send _two_ dots... */
		  if ((retval = (*pgensock_put_data_buffered) (sock, index, 1))) {
			return (retval);
		  }
		}
		if ((retval = (*pgensock_put_data_buffered) (sock, index, 1))) {
		  return (retval);
		}
		break;
	  case '\r':
		if (previous_char != '\r') {
		  if ((retval = (*pgensock_put_data_buffered) (sock, index, 1))) {
			return (retval);
		  }
		}
		/* soft line-break (see EM_FMTLINES), skip extra CR */
		break;

	  default:
		if ((retval = (*pgensock_put_data_buffered) (sock, index, 1))) {
		  return (retval);
		}
	  }
	  previous_char = *index;
	  index++;
	}
	if ((unsigned int) (index - editptr) == send_len) {
	  done = 1;
	}
  }

  /* this handles the case where the user doesn't end the last
   * line with a <return>
   */

  if (editptr[send_len - 1] != '\n') {
	if ((retval = (*pgensock_put_data_buffered) (sock, "\r\n", 2))) {
	  return (retval);
	}
  }

  /* now make sure it's all sent... */
  if ((retval = (*pgensock_put_data_flush) (sock))) {
	return (retval);
  }
  return (0);
}

int
post_edit_data (char *edit_data)
{
  int retval;
  if ((retval = transform_and_send_edit_data (NNTPSock, edit_data))) {
	return (retval);
  }
  return (end_post ());
}

int
post_unended_edit_data (char *edit_data)
{
  int retval;
  if ((retval = transform_and_send_edit_data (NNTPSock, edit_data))) {
	return (retval);
  }
  return (0);
}

int
send_smtp_edit_data (char *edit_data)
{
  int retval;
  if ((retval = transform_and_send_edit_data (SMTPSock, edit_data))) {
	return (retval);
  }
  return (end_send_smtp ());
}

int
send_smtp_unended_data (char *edit_data)
{
  int retval;
  if ((retval = transform_and_send_edit_data (SMTPSock, edit_data))) {
	return (retval);
  }
  return (0);
}

/* send_smtp_message
 * headers is a textblock containing the header lines for this mail
 * message is a pointer to the text content of an edit control
 */
int
send_smtp_message (TypTextBlock * headers, char *message)
{
  result = FAIL;
  if (!prepare_smtp_message (headers) &&
	  !send_smtp_textblock (headers) &&
	  !send_smtp_edit_data (message) &&
	  !finish_smtp_message ()) {
	result = SUCCESS;
  }

  close_smtp_socket ();
  return (result);
}

int
send_textblock_internal (socktag sock, TypTextBlock * textBlock)
{
  register unsigned long i;
  char *line;
  int retval;

  for (i = 0; i < textBlock->numLines; i++) {
	line = TextBlockLine (textBlock, i);
	/* if line starts with dot, send two dots */
	if (*line == '.' &&
		(retval = (*pgensock_put_data_buffered) (sock, line, 1))) {
	  return (retval);
	}
	if ((retval = (*pgensock_put_data_buffered) (sock, line, strlen (line)))) {
	  return (retval);
	}
  }

  /* now make sure it's all sent... */
  if ((retval = (*pgensock_put_data_flush) (sock))) {
	return (retval);
  }
  return (0);
}

int
post_textblock (TypTextBlock * textBlock)
{
  return send_textblock_internal (NNTPSock, textBlock);
}

int
send_smtp_textblock (TypTextBlock * textBlock)
{
  return send_textblock_internal (SMTPSock, textBlock);
}

int 
forward_smtp_message (char *destination, TypDoc * Doc)
{
  int retval;

  if ((retval = prepare_smtp_message (destination))) {
	complain (-1,"Prepare_SMTP_Message","Return Code - %d\r\n", retval);
	return (retval);
  }
  else if ((retval = send_smtp_article (destination, Doc))) {
	complain (-1,"Send_SMTP_Message","Return Code - %d\r\n", retval);
	return (retval);
  }
  else if ((retval = finish_smtp_message ())) {
	complain (-1,"Finish_SMTP_Message","Return Code - %d\r\n", retval);
	close_smtp_socket ();
	return (retval);
  }
  close_smtp_socket ();
  return (1);
}

// testing new buffered stuff...

int 
send_smtp_article (char *destination, TypDoc * Doc)
{
  HANDLE hBlock;
  unsigned int Offset;
  TypLineID MyLineID;
  TypBlock far *BlockPtr;
  TypLine far *LinePtr;
  int retval;
  char line[MAXOUTLINE], temp[MAXOUTLINE];

  _snprintf (line,
			 MAXOUTLINE,
			 "From: %s (%s)\r\n",
			 MailAddress,
			 UserName);


  if ((retval =
	   (*pgensock_put_data_buffered) (SMTPSock, line, lstrlen (line)))) {
	return (retval);
  }

  _snprintf (line,
			 MAXOUTLINE,
			 "To: %s\r\n",
			 destination);


  if ((retval =
	   (*pgensock_put_data_buffered) (SMTPSock, line, lstrlen (line)))) {
	return (retval);
  }

  /* find the subject line */
  TopOfDoc (Doc, &BlockPtr, &LinePtr);
  *line = '\0';
  while (ExtractTextLine (Doc, LinePtr, temp, MAXOUTLINE - 1)) {
	if (!_strnicmp (temp, "subject:", 8)) {
	  _snprintf (line,
				 MAXOUTLINE,
				 "Subject: %s (fwd)\r\n",
				 &temp[8]);
	  break;
	}
	if (!NextLine (&BlockPtr, &LinePtr))
	  break;
  }
  if (*line && (retval =
		  (*pgensock_put_data_buffered) (SMTPSock, line, lstrlen (line)))) {
	return (retval);
  }

  _snprintf (line,
			 MAXOUTLINE,
			 "\r\n[article forwarded from %s (%s)]\r\n\r\n",
			 UserName,
			 MailAddress);

  if ((retval =
	   (*pgensock_put_data_buffered) (SMTPSock, line, lstrlen (line)))) {
	return (retval);
  }

  TopOfDoc (Doc, &BlockPtr, &LinePtr);
  while (ExtractTextLine (Doc, LinePtr, line, MAXOUTLINE - 1)) {
	/* double a leading dot */
	if (line[0] == '.') {
	  if ((retval = (*pgensock_put_data_buffered) (SMTPSock, ".", 1))) {
		return (retval);
	  }
	}
	strcat (line, "\r\n");

	if ((retval =
		 (*pgensock_put_data_buffered) (SMTPSock, line, strlen (line)))) {
	  return (retval);
	}

	if (!NextLine (&BlockPtr, &LinePtr))
	  break;
  }
  UnlockLine (BlockPtr, LinePtr, &hBlock, &Offset, &MyLineID);

  if ((retval =
	   (*pgensock_put_data_buffered) (SMTPSock, "\r\n.\r\n", 5))) {
	return (retval);
  }
  if ((retval =
	   (*pgensock_put_data_flush) (SMTPSock))) {
	return (retval);
  }

  if ((retval = get_smtp_line ()) != 250) {
	complain (-1,"Send_SMTP_Article", Send Failed. get_smtp_line() returned %d\r\n", retval);
  }

  return (0);
}
#endif

/* this is for emacs
 * Local variables:
 * tab-width: 2
 * end:
 */
@


1.28
log
@changed size of hostname buffer from 1024 to 256 to keep
from GPFing some WinSock stacks.
@
text
@d2 1
a2 1
/* $Id: wvsckgen.c 1.27 1995/05/20 01:21:08 dumoulin Exp $ */
a35 1
int close_smtp_socket (void);
d102 1
a102 1
  if (NNTPSock && (retval = (*pgensock_getchar) (NNTPSock, 1, &ch))) {
d210 2
a211 1
  if (!result && ((FARPROC) pgensock_connect =
d217 2
a218 1
  if (!result && ((FARPROC) pgensock_getchar =
d224 2
a225 1
  if (!result && ((FARPROC) pgensock_put_data =
d231 2
a232 1
  if (!result && ((FARPROC) pgensock_close =
d238 2
a239 1
  if (!result && ((FARPROC) pgensock_gethostname =
d245 2
a246 1
  if (!result && ((FARPROC) pgensock_put_data_buffered =
d252 2
a253 1
  if (!result && ((FARPROC) pgensock_put_data_flush =
d375 1
a375 1

d475 2
d637 4
a640 1
  char toLine[MAXOUTLINE], *fromLine;
d648 1
a648 2
	return 1;

d653 15
a667 9
	/* copy From: line from real headers */
	for (i = 0; i < headers->numLines; i++) {
	  fromLine = TextBlockLine (headers, i);
	  if (!_strnicmp (TextBlockLine (headers, i), "from: ", 6))
		break;
	}
	if (i < headers->numLines) {
	  retval = AddLineToTextBlock (tempHeader, fromLine);
	}
a668 1

d670 3
a672 2
	prepare_smtp_message (tempHeader) ||
	put_smtp_line (SMTPSock, toLine, lstrlen (toLine));
d988 1
a988 1
 * tab-width: 4
@


1.27
log
@recheckin to correct formatting problem
@
text
@d2 1
a2 1
/* $Id: wvsckgen.c 1.26 1995/05/20 01:16:05 dumoulin Exp $ */
d25 1
a25 1
char my_hostname[1024];
@


1.26
log
@modified Gensock error messages so that they don't look
as scary to new users.
@
text
@d1 974
a974 974
/* Interface to GENSOCK module */
/* $Id: wvsckgen.c 1.25 1995/01/11 21:58:54 rushing Exp $ */

#include <windows.h>
#include <windowsx.h>
#include "wvglob.h"
#include "winvn.h"
#pragma hdrstop
#include <stdlib.h>
#include <stdio.h>				/* for sprintf */
#include <stdarg.h>				/* for varargs stuff */
#include <ctype.h>				/* for isspace */
#define MAXSENDLEN 32767
#define COMMBUFSIZE	1600

/* generic socket DLL support */
#include "gensock\\gensock.h"

char CommBuff[COMMBUFSIZE];
int CommBuffIdx = COMMBUFSIZE + 1;
int CharsInCommBuff = 0;

socktag NNTPSock = 0;
socktag SMTPSock = 0;
char my_hostname[1024];

/* functions the rest of winvn expects to see */
void PutCommLine (char *line);
void PutCommData (char *data, unsigned int length);

int MRRReadComm (void);
void MRRCloseComm (void);
int MRRInitComm (void);

/* internal to this file */
int close_smtp_socket (void);
int open_smtp_socket (void);
void smtp_error (char *message);
int finish_smtp_message (void);
int get_smtp_line (void);
int put_smtp_line (socktag sock, char far * line, unsigned int nchars);

HINSTANCE gensock_lib = 0;

int (FAR PASCAL * pgensock_connect) (char FAR * hostname, char FAR * service, socktag FAR * pst);
int (FAR PASCAL * pgensock_getchar) (socktag st, int wait, char FAR * ch);
int (FAR PASCAL * pgensock_put_data) (socktag st, char FAR * data, unsigned long length);
int (FAR PASCAL * pgensock_close) (socktag st);
int (FAR PASCAL * pgensock_gethostname) (char FAR * name, int namelen);
int (FAR PASCAL * pgensock_put_data_buffered) (socktag st, char FAR * data, unsigned long length);
int (FAR PASCAL * pgensock_put_data_flush) (socktag st);


/*-- function MRRReadComm ---------------------------------------
 *
 *  Reads characters from the NNTP Socket
 */

#define ERROR_BUFFER_SIZE 1024

void
complain (int err, char *function, char *fmt,...)
{
  va_list marker;
  char message[ERROR_BUFFER_SIZE];
  char message1[100];
  int done = 0;
  static int messageOnScreen = FALSE; /* avoid cascading errors --> stack crash */

  /* Write text to a string and output the string. */
  if (!messageOnScreen) {
    va_start (marker, fmt);
    _vsnprintf (message, ERROR_BUFFER_SIZE, fmt, marker);
    va_end (marker);
	if (err >=0)
	   wsprintf (message1, "Error %d - Function '%s'",err,function);
	else
	   wsprintf (message1, "WinVN Function '%s'",function);
	messageOnScreen = TRUE;
    MessageBox (NetDoc.hDocWnd, message, message1, MB_OK);
	messageOnScreen = FALSE;
  }
}

void
gensock_error (char *function, int retval)
{
  char error_string[512];
  int len;

  len = LoadString (hInst, retval, error_string, sizeof (error_string));
  complain (retval,function,"%s",
			len == 0 ? "[couldn't get error string]" : error_string);
}

int 
MRRReadComm ()
{
  int retval;
  unsigned char ch;

  /* we set wait = 1, sortof non-blocking */
  if (NNTPSock && (retval = (*pgensock_getchar) (NNTPSock, 1, &ch))) {
	switch (retval) {
	case WAIT_A_BIT:
	case ERR_BUSY:
	  break;
	case ERR_NOT_CONNECTED:
	  Initializing = INIT_NOT_CONNECTED;
	  SendMessage (NetDoc.hDocWnd, (UINT) WM_COMMAND,
				   (WPARAM) IDM_DISCONNECT, (LPARAM) 0);
	  Disconnect ();
	  complain (-1,"MRRReadComm","NNTP server has closed the connection");
	  return (-1);
	  break;
	default:
	  gensock_error ("gensock_getchar", retval);
	}
	return (-1);
  }
  else
	return ((int) ch);
}

int
putline_internal (socktag sock, char *line, unsigned int nchars)
{
  int retval;

  if (sock && (retval =
	   (*pgensock_put_data) (sock,
							 (char FAR *) line,
							 (unsigned long) nchars))) {
	switch (retval) {
	case ERR_NOT_CONNECTED:
	  Initializing = INIT_NOT_CONNECTED;
	  SendMessage (NetDoc.hDocWnd, (UINT) WM_COMMAND,
				   (WPARAM) IDM_DISCONNECT, (LPARAM) 0);
	  Disconnect ();
	  complain (-1,"PutLine_Internal","NNTP server has closed the connection");
	  return (-1);
	  break;

	default:
	  gensock_error ("gensock_put_data", retval);
	}
	return (-1);
  }
  return (0);
}

/* PutCommLine takes a string, sends it, followed by
 * \r\n.  All one-line sends in winvn should use this.
 */

void
PutCommLine (char *line)
{
  putline_internal (NNTPSock, line, lstrlen (line));
  putline_internal (NNTPSock, "\r\n", 2);
}

/* Use this function for sending larger chunks of data.
 * the text data from an Edit class window can be sent
 * using this function
 */

void
PutCommData (char *data, unsigned int length)
{
  putline_internal (NNTPSock, data, length);
}

/*-- function MRRCloseComm -----------------------------------------
 *
 *  Close the communications port, serial or TCP.
 */
void 
MRRCloseComm ()
{
  if (NNTPSock) {
	(*pgensock_close) (NNTPSock);
	NNTPSock = (socktag) 0;
  }
  if (!SMTPSock && gensock_lib) {
	FreeLibrary (gensock_lib);
	gensock_lib = 0;
  }
  CommState = ST_CLOSED_COMM;
  SetStatbarText (NetDoc.hWndFrame, "", &NetDoc, TRUE, TRUE);
  InvalidateRect (NetDoc.hDocWnd, NULL, TRUE);
}

int
load_gensock ()
{
  int result = 0;

#ifdef WIN32
  if ((gensock_lib = LoadLibrary (GenSockDLL)) == NULL) {
#else
  if ((gensock_lib = LoadLibrary (GenSockDLL)) < HINSTANCE_ERROR) {
#endif
	char message[256];
	wsprintf (message, "Couldn't load '%s'", GenSockDLL);
	complain (-1,"Load_Gensock",message);
	gensock_lib = 0;
	return (-1);
  }

  if (!result && ((FARPROC) pgensock_connect =
				  GetProcAddress (gensock_lib, "gensock_connect")) == NULL) {
	complain (-1,"Load_Gensock","couldn't getprocaddress for gensock_connect");
	result = -1;
  }

  if (!result && ((FARPROC) pgensock_getchar =
				  GetProcAddress (gensock_lib, "gensock_getchar")) == NULL) {
	complain (-1,"Load_Gensock","couldn't getprocaddress for gensock_getchar");
	result = -1;
  }

  if (!result && ((FARPROC) pgensock_put_data =
				GetProcAddress (gensock_lib, "gensock_put_data")) == NULL) {
	complain (-1,"Load_Gensock","couldn't getprocaddress for gensock_put_data");
	result = -1;
  }

  if (!result && ((FARPROC) pgensock_close =
				  GetProcAddress (gensock_lib, "gensock_close")) == NULL) {
	complain (-1,"Load_Gensock","couldn't getprocaddress for gensock_close");
	result = -1;
  }

  if (!result && ((FARPROC) pgensock_gethostname =
			 GetProcAddress (gensock_lib, "gensock_gethostname")) == NULL) {
	complain (-1,"Load_Gensock","couldn't getprocaddress for gensock_gethostname");
	result = -1;
  }

  if (!result && ((FARPROC) pgensock_put_data_buffered =
	   GetProcAddress (gensock_lib, "gensock_put_data_buffered")) == NULL) {
	complain (-1,"Load_Gensock","couldn't getprocaddress for gensock_put_data_buffered");
	result = -1;
  }

  if (!result && ((FARPROC) pgensock_put_data_flush =
		  GetProcAddress (gensock_lib, "gensock_put_data_flush")) == NULL) {
	complain (-1,"Load_Gensock","couldn't getprocaddress for gensock_put_data_flush");
	result = -1;
  }

  if (result) {
	FreeLibrary (gensock_lib);
	gensock_lib = 0;
  }
  return (result);
}

int
MRRInitComm ()
{
  int retval;

  /* load the library if it's not loaded */
  if (!gensock_lib) {
	if ((retval = load_gensock ())) {
	  return (retval);
	}
  }

  /* to keep our sanity, we will quietly try '119' in case it fails */
  if ((retval = (*pgensock_connect) ((LPSTR) NNTPHost,
									 (LPSTR) NNTPService,
									 &NNTPSock))) {
	if (retval == ERR_CANT_RESOLVE_SERVICE) {
	  if ((retval = (*pgensock_connect) ((LPSTR) NNTPHost,
										 (LPSTR) "119",
										 &NNTPSock))) {
		gensock_error ("gensock_connect", retval);
		return (-1);
	  }
	}
	/* error other than can't resolve service */
	else {
	  gensock_error ("gensock_connect", retval);
	  return (-1);
	}
  }

  IgnoreCommCh = '\r';
  EOLCommCh = '\n';

  CommLinePtr = CommLineIn;
  CommState = ST_ESTABLISH_COMM;
  CommBusy = FALSE;
  return (0);
}

/* ---------------------------------------------------------------------------
 * open/close SMTP socket
 */

void 
abort_mail_socket ()
{
  /* in case we're _not_ connected to a NNTP server, and
   * we just used SMTP mail only, then we probably want to
   * close the library...
   */
  SMTPSock = 0;
  if (!NNTPSock && gensock_lib) {
	FreeLibrary (gensock_lib);
	gensock_lib = 0;
  }
}

int 
open_smtp_socket ()
{
  int retval;

  if (gensock_lib && SMTPSock)	// already open

	return 0;

  /* load the library if it's not loaded */
  if (!gensock_lib) {
	if ((retval = load_gensock ())) {
	  return (retval);
	}
  }

  if ((retval = (*pgensock_connect) ((LPSTR) SMTPHost,
									 (LPSTR) "smtp",
									 &SMTPSock))) {
	if (retval == ERR_CANT_RESOLVE_SERVICE ||
		retval == ERR_NO_ERROR_CODE) {		/* Chameleon is bad, it fails but sets no error code. */
	  if ((retval = (*pgensock_connect) ((LPSTR) SMTPHost,
										 (LPSTR) "25",
										 &SMTPSock))) {
		gensock_error ("gensock_connect", retval);
		abort_mail_socket ();
		return (-1);
	  }
	}
	/* error other than can't resolve service */
	else {
	  gensock_error ("gensock_connect", retval);
	  abort_mail_socket ();
	  return (-1);
	}
  }

  /* we wait to do this until here because WINSOCK is
   * guaranteed to be already initialized at this point.
   */

  /* get the local hostname (needed by SMTP) */
  if ((retval = (*pgensock_gethostname) (my_hostname, sizeof (my_hostname)))) {
    /* This is failing very often, I hope no smtp server complains too loudly */
    strcpy (my_hostname, "idunnomyownname");
#if 0
    gensock_error ("gensock_gethostname", retval);
    abort_mail_socket ();
    return (-1);
#endif
  }

}

int 
close_smtp_socket ()
{
  int retval = 0;

  if (SMTPSock) {
	if ((retval = (*pgensock_close) (SMTPSock))) {
	  gensock_error ("gensock_close", retval);
	}
  }
  abort_mail_socket ();

  return (retval);
}

/* ---------------------------------------------------------------------------
 * internal SMTP functions
 */

int 
get_smtp_line ()
{
  char ch = '.';
  char in_data[MAXOUTLINE];
  char *index;
  int retval = 0;

  index = in_data;

  while (ch != '\n') {
	if ((retval = (*pgensock_getchar) (SMTPSock, 0, &ch))) {
	  gensock_error ("gensock_getchar", retval);
	  return (-1);
	}
	else {
	  *index = ch;
	  index++;
	}
  }

  /* this is to support multi-line responses, common with */
  /* servers that speak ESMTP */

  /* I know, I know, it's a hack 8^) */
  if (in_data[3] == '-')
	return (get_smtp_line ());
  else
	return (atoi (in_data));
}

int 
put_smtp_line (socktag sock, char far * line, unsigned int nchars)
{
  int retval;

  if (!sock || (retval = (*pgensock_put_data) (sock, line, (unsigned long) nchars))) {
	gensock_error ("gensock_put_data", retval);
	return (-1);
  }
  return (0);
}

int 
finish_smtp_message ()
{
  int retval;

  if ((retval = (*pgensock_put_data_flush) (SMTPSock))) {
	return (retval);
  }
  return (put_smtp_line (SMTPSock, "QUIT\r\n", 6));
}

void 
smtp_error (char *message)
{
  MessageBox (NetDoc.hDocWnd, message, "WinVN", MB_OK);
  put_smtp_line (SMTPSock, "QUIT\r\n", 6);
  close_smtp_socket ();
}

/* ---------------------------------------------------------------------------
 * The following are entry points
 * all return 0 on success or non-zero on fail
 */

int
end_post ()
{
  int retval;

  if ((retval = (*pgensock_put_data_buffered) (NNTPSock, ".\r\n", 3))) {
	return (retval);
  }
  if ((retval = (*pgensock_put_data_flush) (NNTPSock))) {
	return (retval);
  }
}

int
end_send_smtp ()
{
  int retval;

  if ((retval = (*pgensock_put_data_buffered) (SMTPSock, ".\r\n", 3))) {
	return (retval);
  }

  if ((retval = (*pgensock_put_data_flush) (SMTPSock))) {
	return (retval);
  }

  retval = get_smtp_line ();
  if (retval != 250 && retval != 251) {
	smtp_error ("Message not accepted by server");
	return -1;
  }
  finish_smtp_message ();
  close_smtp_socket ();

  return 0;
}


int
send_smtp_line (char *str, unsigned long len)
{
  int retval;

  if (*str == '.' &&			/* if line starts with dot, send two dots */
	  (retval = (*pgensock_put_data_buffered) (SMTPSock, str, 1))) {
	return (retval);
  }
  return ((*pgensock_put_data_buffered) (SMTPSock, str, len));
}

int
post_line (char *str, unsigned long len)
{
  int retval;

  if (*str == '.' &&			/* if line starts with dot, send two dots */
	  (retval = (*pgensock_put_data_buffered) (NNTPSock, str, 1))) {
	return (retval);
  }
  return ((*pgensock_put_data_buffered) (NNTPSock, str, len));
}

/* prepare_smtp_message
 * headers is a textblock containing the header lines for this mail
 * grab the From, To and any Cc from here to generate From: and RCPT:
 * SMTP commands
 */
int
prepare_smtp_message (TypTextBlock * headers)
{
  char out_data[MAXOUTLINE], address[MAXHEADERLINE];
  char *ptr, *line;
  int len, startLen, result;
  unsigned long i;

  if (open_smtp_socket ())
	return (-1);

  if (get_smtp_line () != 220) {
	smtp_error ("SMTP server error");
	return (-1);
  }

  sprintf (out_data, "HELO %s\r\n", my_hostname);
  put_smtp_line (SMTPSock, out_data, strlen (out_data));

  if (get_smtp_line () != 250) {
	smtp_error ("SMTP server error");
	return (-1);
  }

  for (i = 0; i < headers->numLines; i++) {
	line = TextBlockLine (headers, i);
	if (!_strnicmp (line, "from: ", 6))
	  break;
  }
  if (i < headers->numLines)
	ParseAddress (&line[6], address, MAXHEADERLINE, str, MAXINTERNALLINE);
  else
	strcpy (address, MailAddress);

  ptr = &address[strlen (address) - 1];
  while (isspace (*ptr))
	*ptr-- = '\0';				/* strip trailing space */
  sprintf (out_data, "MAIL From:<%s>\r\n", address);
  put_smtp_line (SMTPSock, out_data, strlen (out_data));

  if (get_smtp_line () != 250) {
	smtp_error ("The mail server doesn't like the sender name, "
				"have you set your mail address correctly?");
	return (-1);
  }

  /* do a series of RCPT lines for all To: addresses and Cc: address */
  for (i = 0; i < headers->numLines; i++) {
	line = TextBlockLine (headers, i);

	if (!_strnicmp (line, "to: ", 4) || !_strnicmp (line, "cc: ", 4)) {
	  ptr = strcpy (address, &line[4]);
	  while (*ptr) {
		// if there's only one token left, then len will = startLen,
		// and we'll iterate once only
		startLen = strlen (ptr);
		if ((len = strcspn (ptr, " ,\n\t\r")) != startLen) {
		  ptr[len++] = '\0';	// replace delim with NULL char

		  while (isspace (ptr[len]) || ptr[len] == ',')		// eat white space

			ptr[len++] = '\0';
		}

		sprintf (out_data, "RCPT To: <%s>\r\n", ptr);
		putline_internal (SMTPSock, out_data, strlen (out_data));

		result = get_smtp_line ();
		if (result != 250 && result != 251) {
		  sprintf (str, "The mail server doesn't like the name %s.  "
				   "Have you set the 'To: ' field correctly?", ptr);
		  smtp_error (str);
		  return (-1);
		}

		if (len == startLen)	// last token, we're done

		  break;

		ptr += len;
	  }							/* RCPT loop */
	}							/* if To: or Cc: */
  }								/* for header lines */

  sprintf (out_data, "DATA\r\n");
  put_smtp_line (SMTPSock, out_data, strlen (out_data));

  if (get_smtp_line () != 354) {
	smtp_error ("Mail server error accepting message data");
	return (-1);
  }

  return (0);

}

/* prepare_cc_smtp_message
 * destination is the address(es) to forward to
 * headers is a textblock containing the header lines for mail to be forwarded
 */
int 
prepare_cc_smtp_message (char *destination, TypTextBlock * headers)
{
  register unsigned long i;
  char toLine[MAXOUTLINE], *fromLine;
  TypTextBlock *tempHeader;
  int retval;

  /* create temporary header block containing only a To: and a From: 
   * to make prepare_smtp_message happy
   */
  if ((tempHeader = InitTextBlock (NetDoc.hDocWnd)) == NULL)
	return 1;

  _snprintf (toLine, MAXOUTLINE, "To: %s\r\n", destination);
  retval = AddLineToTextBlock (tempHeader, toLine);

  if (!retval) {
	/* copy From: line from real headers */
	for (i = 0; i < headers->numLines; i++) {
	  fromLine = TextBlockLine (headers, i);
	  if (!_strnicmp (TextBlockLine (headers, i), "from: ", 6))
		break;
	}
	if (i < headers->numLines) {
	  retval = AddLineToTextBlock (tempHeader, fromLine);
	}
  }

  retval = retval ||
	prepare_smtp_message (tempHeader) ||
	put_smtp_line (SMTPSock, toLine, lstrlen (toLine));

  FreeTextBlock (tempHeader);
  return (retval);
}

#ifdef OLD_STUFF
int send_smtp_message (TypTextBlock * headers, char *message);
int cc_smtp_message (char *destination, TypTextBlock * headers, char *editstr);
int post_edit_data (char *edit_data);
int post_unended_edit_data (char *edit_data);
int send_smtp_edit_data (char *edit_data);
int send_smtp_unended_edit_data (char *edit_data);
int post_textblock (TypTextBlock * textBlock);
int send_smtp_textblock (TypTextBlock * textBlock);

int forward_smtp_message (char *destination, TypDoc * Doc);
int send_smtp_article (char *destination, TypDoc * Doc);
int send_textblock_internal (socktag sock, TypTextBlock * textBlock);
int prepare_smtp_message (TypTextBlock * headers);


/* ---------------------------------------------------------------------------
 * transform_and_send_edit_data
 */

int 
transform_and_send_edit_data (socktag sock, char *editptr)
{
  char *index;
  char previous_char = 'x';
  unsigned int send_len;
  int retval;
  BOOL done = 0;

  send_len = lstrlen (editptr);
  index = editptr;

  while (!done) {
	/* room for extra char for double dot on end case */
	while ((unsigned int) (index - editptr) < send_len) {
	  switch (*index) {
	  case '.':
		if (previous_char == '\n') {
		  /* send _two_ dots... */
		  if ((retval = (*pgensock_put_data_buffered) (sock, index, 1))) {
			return (retval);
		  }
		}
		if ((retval = (*pgensock_put_data_buffered) (sock, index, 1))) {
		  return (retval);
		}
		break;
	  case '\r':
		if (previous_char != '\r') {
		  if ((retval = (*pgensock_put_data_buffered) (sock, index, 1))) {
			return (retval);
		  }
		}
		/* soft line-break (see EM_FMTLINES), skip extra CR */
		break;

	  default:
		if ((retval = (*pgensock_put_data_buffered) (sock, index, 1))) {
		  return (retval);
		}
	  }
	  previous_char = *index;
	  index++;
	}
	if ((unsigned int) (index - editptr) == send_len) {
	  done = 1;
	}
  }

  /* this handles the case where the user doesn't end the last
   * line with a <return>
   */

  if (editptr[send_len - 1] != '\n') {
	if ((retval = (*pgensock_put_data_buffered) (sock, "\r\n", 2))) {
	  return (retval);
	}
  }

  /* now make sure it's all sent... */
  if ((retval = (*pgensock_put_data_flush) (sock))) {
	return (retval);
  }
  return (0);
}

int
post_edit_data (char *edit_data)
{
  int retval;
  if ((retval = transform_and_send_edit_data (NNTPSock, edit_data))) {
	return (retval);
  }
  return (end_post ());
}

int
post_unended_edit_data (char *edit_data)
{
  int retval;
  if ((retval = transform_and_send_edit_data (NNTPSock, edit_data))) {
	return (retval);
  }
  return (0);
}

int
send_smtp_edit_data (char *edit_data)
{
  int retval;
  if ((retval = transform_and_send_edit_data (SMTPSock, edit_data))) {
	return (retval);
  }
  return (end_send_smtp ());
}

int
send_smtp_unended_data (char *edit_data)
{
  int retval;
  if ((retval = transform_and_send_edit_data (SMTPSock, edit_data))) {
	return (retval);
  }
  return (0);
}

/* send_smtp_message
 * headers is a textblock containing the header lines for this mail
 * message is a pointer to the text content of an edit control
 */
int
send_smtp_message (TypTextBlock * headers, char *message)
{
  result = FAIL;
  if (!prepare_smtp_message (headers) &&
	  !send_smtp_textblock (headers) &&
	  !send_smtp_edit_data (message) &&
	  !finish_smtp_message ()) {
	result = SUCCESS;
  }

  close_smtp_socket ();
  return (result);
}

int
send_textblock_internal (socktag sock, TypTextBlock * textBlock)
{
  register unsigned long i;
  char *line;
  int retval;

  for (i = 0; i < textBlock->numLines; i++) {
	line = TextBlockLine (textBlock, i);
	/* if line starts with dot, send two dots */
	if (*line == '.' &&
		(retval = (*pgensock_put_data_buffered) (sock, line, 1))) {
	  return (retval);
	}
	if ((retval = (*pgensock_put_data_buffered) (sock, line, strlen (line)))) {
	  return (retval);
	}
  }

  /* now make sure it's all sent... */
  if ((retval = (*pgensock_put_data_flush) (sock))) {
	return (retval);
  }
  return (0);
}

int
post_textblock (TypTextBlock * textBlock)
{
  return send_textblock_internal (NNTPSock, textBlock);
}

int
send_smtp_textblock (TypTextBlock * textBlock)
{
  return send_textblock_internal (SMTPSock, textBlock);
}

int 
forward_smtp_message (char *destination, TypDoc * Doc)
{
  int retval;

  if ((retval = prepare_smtp_message (destination))) {
	complain (-1,"Prepare_SMTP_Message","Return Code - %d\r\n", retval);
	return (retval);
  }
  else if ((retval = send_smtp_article (destination, Doc))) {
	complain (-1,"Send_SMTP_Message","Return Code - %d\r\n", retval);
	return (retval);
  }
  else if ((retval = finish_smtp_message ())) {
	complain (-1,"Finish_SMTP_Message","Return Code - %d\r\n", retval);
	close_smtp_socket ();
	return (retval);
  }
  close_smtp_socket ();
  return (1);
}

// testing new buffered stuff...

int 
send_smtp_article (char *destination, TypDoc * Doc)
{
  HANDLE hBlock;
  unsigned int Offset;
  TypLineID MyLineID;
  TypBlock far *BlockPtr;
  TypLine far *LinePtr;
  int retval;
  char line[MAXOUTLINE], temp[MAXOUTLINE];

  _snprintf (line,
			 MAXOUTLINE,
			 "From: %s (%s)\r\n",
			 MailAddress,
			 UserName);


  if ((retval =
	   (*pgensock_put_data_buffered) (SMTPSock, line, lstrlen (line)))) {
	return (retval);
  }

  _snprintf (line,
			 MAXOUTLINE,
			 "To: %s\r\n",
			 destination);


  if ((retval =
	   (*pgensock_put_data_buffered) (SMTPSock, line, lstrlen (line)))) {
	return (retval);
  }

  /* find the subject line */
  TopOfDoc (Doc, &BlockPtr, &LinePtr);
  *line = '\0';
  while (ExtractTextLine (Doc, LinePtr, temp, MAXOUTLINE - 1)) {
	if (!_strnicmp (temp, "subject:", 8)) {
	  _snprintf (line,
				 MAXOUTLINE,
				 "Subject: %s (fwd)\r\n",
				 &temp[8]);
	  break;
	}
	if (!NextLine (&BlockPtr, &LinePtr))
	  break;
  }
  if (*line && (retval =
		  (*pgensock_put_data_buffered) (SMTPSock, line, lstrlen (line)))) {
	return (retval);
  }

  _snprintf (line,
			 MAXOUTLINE,
			 "\r\n[article forwarded from %s (%s)]\r\n\r\n",
			 UserName,
			 MailAddress);

  if ((retval =
	   (*pgensock_put_data_buffered) (SMTPSock, line, lstrlen (line)))) {
	return (retval);
  }

  TopOfDoc (Doc, &BlockPtr, &LinePtr);
  while (ExtractTextLine (Doc, LinePtr, line, MAXOUTLINE - 1)) {
	/* double a leading dot */
	if (line[0] == '.') {
	  if ((retval = (*pgensock_put_data_buffered) (SMTPSock, ".", 1))) {
		return (retval);
	  }
	}
	strcat (line, "\r\n");

	if ((retval =
		 (*pgensock_put_data_buffered) (SMTPSock, line, strlen (line)))) {
	  return (retval);
	}

	if (!NextLine (&BlockPtr, &LinePtr))
	  break;
  }
  UnlockLine (BlockPtr, LinePtr, &hBlock, &Offset, &MyLineID);

  if ((retval =
	   (*pgensock_put_data_buffered) (SMTPSock, "\r\n.\r\n", 5))) {
	return (retval);
  }
  if ((retval =
	   (*pgensock_put_data_flush) (SMTPSock))) {
	return (retval);
  }

  if ((retval = get_smtp_line ()) != 250) {
	complain (-1,"Send_SMTP_Article", Send Failed. get_smtp_line() returned %d\r\n", retval);
  }

  return (0);
}
#endif

/* this is for emacs
 * Local variables:
 * tab-width: 4
 * end:
 */
@


1.25
log
@.bracket typo
@
text
@d1 974
a974 972
/* Interface to GENSOCK module */
/* $Id: wvsckgen.c 1.24 1995/01/11 21:16:06 rushing Exp rushing $ */

#include <windows.h>
#include <windowsx.h>
#include "wvglob.h"
#include "winvn.h"
#pragma hdrstop
#include <stdlib.h>
#include <stdio.h>				/* for sprintf */
#include <stdarg.h>				/* for varargs stuff */
#include <ctype.h>				/* for isspace */
#define MAXSENDLEN 32767
#define COMMBUFSIZE	1600

/* generic socket DLL support */
#include "gensock\\gensock.h"

char CommBuff[COMMBUFSIZE];
int CommBuffIdx = COMMBUFSIZE + 1;
int CharsInCommBuff = 0;

socktag NNTPSock = 0;
socktag SMTPSock = 0;
char my_hostname[1024];

/* functions the rest of winvn expects to see */
void PutCommLine (char *line);
void PutCommData (char *data, unsigned int length);

int MRRReadComm (void);
void MRRCloseComm (void);
int MRRInitComm (void);

/* internal to this file */
int close_smtp_socket (void);
int open_smtp_socket (void);
void smtp_error (char *message);
int finish_smtp_message (void);
int get_smtp_line (void);
int put_smtp_line (socktag sock, char far * line, unsigned int nchars);

HINSTANCE gensock_lib = 0;

int (FAR PASCAL * pgensock_connect) (char FAR * hostname, char FAR * service, socktag FAR * pst);
int (FAR PASCAL * pgensock_getchar) (socktag st, int wait, char FAR * ch);
int (FAR PASCAL * pgensock_put_data) (socktag st, char FAR * data, unsigned long length);
int (FAR PASCAL * pgensock_close) (socktag st);
int (FAR PASCAL * pgensock_gethostname) (char FAR * name, int namelen);
int (FAR PASCAL * pgensock_put_data_buffered) (socktag st, char FAR * data, unsigned long length);
int (FAR PASCAL * pgensock_put_data_flush) (socktag st);


/*-- function MRRReadComm ---------------------------------------
 *
 *  Reads characters from the NNTP Socket
 */

#define ERROR_BUFFER_SIZE 1024

void
complain (char *fmt,...)
{
  va_list marker;
  char message[ERROR_BUFFER_SIZE];
  int done = 0;
  static int messageOnScreen = FALSE; /* avoid cascading errors --> stack crash */

  /* Write text to a string and output the string. */
  if (!messageOnScreen) {
    va_start (marker, fmt);
    _vsnprintf (message, ERROR_BUFFER_SIZE, fmt, marker);
    va_end (marker);
	messageOnScreen = TRUE;
    MessageBox (NetDoc.hDocWnd, message, "WinVN GenSock Library Error", MB_OK);
	messageOnScreen = FALSE;
  }
}

void
gensock_error (char *function, int retval)
{
  char error_string[512];
  int len;

  len = LoadString (hInst, retval, error_string, sizeof (error_string));
  complain ("error %d in function '%s', '%s'",
			retval,
			function,
			len == 0 ? "[couldn't get error string]" : error_string);
}

int 
MRRReadComm ()
{
  int retval;
  unsigned char ch;

  /* we set wait = 1, sortof non-blocking */
  if (NNTPSock && (retval = (*pgensock_getchar) (NNTPSock, 1, &ch))) {
	switch (retval) {
	case WAIT_A_BIT:
	case ERR_BUSY:
	  break;
	case ERR_NOT_CONNECTED:
	  Initializing = INIT_NOT_CONNECTED;
	  SendMessage (NetDoc.hDocWnd, (UINT) WM_COMMAND,
				   (WPARAM) IDM_DISCONNECT, (LPARAM) 0);
	  Disconnect ();
	  complain ("NNTP server has closed the connection");
	  return (-1);
	  break;
	default:
	  gensock_error ("gensock_getchar", retval);
	}
	return (-1);
  }
  else
	return ((int) ch);
}

int
putline_internal (socktag sock, char *line, unsigned int nchars)
{
  int retval;

  if (sock && (retval =
	   (*pgensock_put_data) (sock,
							 (char FAR *) line,
							 (unsigned long) nchars))) {
	switch (retval) {
	case ERR_NOT_CONNECTED:
	  Initializing = INIT_NOT_CONNECTED;
	  SendMessage (NetDoc.hDocWnd, (UINT) WM_COMMAND,
				   (WPARAM) IDM_DISCONNECT, (LPARAM) 0);
	  Disconnect ();
	  complain ("NNTP server has closed the connection");
	  return (-1);
	  break;

	default:
	  gensock_error ("gensock_put_data", retval);
	}
	return (-1);
  }
  return (0);
}

/* PutCommLine takes a string, sends it, followed by
 * \r\n.  All one-line sends in winvn should use this.
 */

void
PutCommLine (char *line)
{
  putline_internal (NNTPSock, line, lstrlen (line));
  putline_internal (NNTPSock, "\r\n", 2);
}

/* Use this function for sending larger chunks of data.
 * the text data from an Edit class window can be sent
 * using this function
 */

void
PutCommData (char *data, unsigned int length)
{
  putline_internal (NNTPSock, data, length);
}

/*-- function MRRCloseComm -----------------------------------------
 *
 *  Close the communications port, serial or TCP.
 */
void 
MRRCloseComm ()
{
  if (NNTPSock) {
	(*pgensock_close) (NNTPSock);
	NNTPSock = (socktag) 0;
  }
  if (!SMTPSock && gensock_lib) {
	FreeLibrary (gensock_lib);
	gensock_lib = 0;
  }
  CommState = ST_CLOSED_COMM;
  SetStatbarText (NetDoc.hWndFrame, "", &NetDoc, TRUE, TRUE);
  InvalidateRect (NetDoc.hDocWnd, NULL, TRUE);
}

int
load_gensock ()
{
  int result = 0;

#ifdef WIN32
  if ((gensock_lib = LoadLibrary (GenSockDLL)) == NULL) {
#else
  if ((gensock_lib = LoadLibrary (GenSockDLL)) < HINSTANCE_ERROR) {
#endif
	char message[256];
	wsprintf (message, "Couldn't load '%s'", GenSockDLL);
	complain (message);
	gensock_lib = 0;
	return (-1);
  }

  if (!result && ((FARPROC) pgensock_connect =
				  GetProcAddress (gensock_lib, "gensock_connect")) == NULL) {
	complain ("couldn't getprocaddress for gensock_connect");
	result = -1;
  }

  if (!result && ((FARPROC) pgensock_getchar =
				  GetProcAddress (gensock_lib, "gensock_getchar")) == NULL) {
	complain ("couldn't getprocaddress for gensock_getchar");
	result = -1;
  }

  if (!result && ((FARPROC) pgensock_put_data =
				GetProcAddress (gensock_lib, "gensock_put_data")) == NULL) {
	complain ("couldn't getprocaddress for gensock_put_data");
	result = -1;
  }

  if (!result && ((FARPROC) pgensock_close =
				  GetProcAddress (gensock_lib, "gensock_close")) == NULL) {
	complain ("couldn't getprocaddress for gensock_close");
	result = -1;
  }

  if (!result && ((FARPROC) pgensock_gethostname =
			 GetProcAddress (gensock_lib, "gensock_gethostname")) == NULL) {
	complain ("couldn't getprocaddress for gensock_gethostname");
	result = -1;
  }

  if (!result && ((FARPROC) pgensock_put_data_buffered =
	   GetProcAddress (gensock_lib, "gensock_put_data_buffered")) == NULL) {
	complain ("couldn't getprocaddress for gensock_put_data_buffered");
	result = -1;
  }

  if (!result && ((FARPROC) pgensock_put_data_flush =
		  GetProcAddress (gensock_lib, "gensock_put_data_flush")) == NULL) {
	complain ("couldn't getprocaddress for gensock_put_data_flush");
	result = -1;
  }

  if (result) {
	FreeLibrary (gensock_lib);
	gensock_lib = 0;
  }
  return (result);
}


int
MRRInitComm ()
{
  int retval;

  /* load the library if it's not loaded */
  if (!gensock_lib) {
	if ((retval = load_gensock ())) {
	  return (retval);
	}
  }

  /* to keep our sanity, we will quietly try '119' in case it fails */
  if ((retval = (*pgensock_connect) ((LPSTR) NNTPHost,
									 (LPSTR) NNTPService,
									 &NNTPSock))) {
	if (retval == ERR_CANT_RESOLVE_SERVICE) {
	  if ((retval = (*pgensock_connect) ((LPSTR) NNTPHost,
										 (LPSTR) "119",
										 &NNTPSock))) {
		gensock_error ("gensock_connect", retval);
		return (-1);
	  }
	}
	/* error other than can't resolve service */
	else {
	  gensock_error ("gensock_connect", retval);
	  return (-1);
	}
  }

  IgnoreCommCh = '\r';
  EOLCommCh = '\n';

  CommLinePtr = CommLineIn;
  CommState = ST_ESTABLISH_COMM;
  CommBusy = FALSE;
  return (0);
}

/* ---------------------------------------------------------------------------
 * open/close SMTP socket
 */

void 
abort_mail_socket ()
{
  /* in case we're _not_ connected to a NNTP server, and
   * we just used SMTP mail only, then we probably want to
   * close the library...
   */
  SMTPSock = 0;
  if (!NNTPSock && gensock_lib) {
	FreeLibrary (gensock_lib);
	gensock_lib = 0;
  }
}

int 
open_smtp_socket ()
{
  int retval;

  if (gensock_lib && SMTPSock)	// already open

	return 0;

  /* load the library if it's not loaded */
  if (!gensock_lib) {
	if ((retval = load_gensock ())) {
	  return (retval);
	}
  }

  if ((retval = (*pgensock_connect) ((LPSTR) SMTPHost,
									 (LPSTR) "smtp",
									 &SMTPSock))) {
	if (retval == ERR_CANT_RESOLVE_SERVICE ||
		retval == ERR_NO_ERROR_CODE) {		/* Chameleon is bad, it fails but sets no error code. */
	  if ((retval = (*pgensock_connect) ((LPSTR) SMTPHost,
										 (LPSTR) "25",
										 &SMTPSock))) {
		gensock_error ("gensock_connect", retval);
		abort_mail_socket ();
		return (-1);
	  }
	}
	/* error other than can't resolve service */
	else {
	  gensock_error ("gensock_connect", retval);
	  abort_mail_socket ();
	  return (-1);
	}
  }

  /* we wait to do this until here because WINSOCK is
   * guaranteed to be already initialized at this point.
   */

  /* get the local hostname (needed by SMTP) */
  if ((retval = (*pgensock_gethostname) (my_hostname, sizeof (my_hostname)))) {
    /* This is failing very often, I hope no smtp server complains too loudly */
    strcpy (my_hostname, "idunnomyownname");
#if 0
    gensock_error ("gensock_gethostname", retval);
    abort_mail_socket ();
    return (-1);
#endif
  }

}

int 
close_smtp_socket ()
{
  int retval = 0;

  if (SMTPSock) {
	if ((retval = (*pgensock_close) (SMTPSock))) {
	  gensock_error ("gensock_close", retval);
	}
  }
  abort_mail_socket ();

  return (retval);
}

/* ---------------------------------------------------------------------------
 * internal SMTP functions
 */

int 
get_smtp_line ()
{
  char ch = '.';
  char in_data[MAXOUTLINE];
  char *index;
  int retval = 0;

  index = in_data;

  while (ch != '\n') {
	if ((retval = (*pgensock_getchar) (SMTPSock, 0, &ch))) {
	  gensock_error ("gensock_getchar", retval);
	  return (-1);
	}
	else {
	  *index = ch;
	  index++;
	}
  }

  /* this is to support multi-line responses, common with */
  /* servers that speak ESMTP */

  /* I know, I know, it's a hack 8^) */
  if (in_data[3] == '-')
	return (get_smtp_line ());
  else
	return (atoi (in_data));
}

int 
put_smtp_line (socktag sock, char far * line, unsigned int nchars)
{
  int retval;

  if (!sock || (retval = (*pgensock_put_data) (sock, line, (unsigned long) nchars))) {
	gensock_error ("gensock_put_data", retval);
	return (-1);
  }
  return (0);
}

int 
finish_smtp_message ()
{
  int retval;

  if ((retval = (*pgensock_put_data_flush) (SMTPSock))) {
	return (retval);
  }
  return (put_smtp_line (SMTPSock, "QUIT\r\n", 6));
}

void 
smtp_error (char *message)
{
  MessageBox (NetDoc.hDocWnd, message, "WinVN", MB_OK);
  put_smtp_line (SMTPSock, "QUIT\r\n", 6);
  close_smtp_socket ();
}

/* ---------------------------------------------------------------------------
 * The following are entry points
 * all return 0 on success or non-zero on fail
 */

int
end_post ()
{
  int retval;

  if ((retval = (*pgensock_put_data_buffered) (NNTPSock, ".\r\n", 3))) {
	return (retval);
  }
  if ((retval = (*pgensock_put_data_flush) (NNTPSock))) {
	return (retval);
  }
}

int
end_send_smtp ()
{
  int retval;

  if ((retval = (*pgensock_put_data_buffered) (SMTPSock, ".\r\n", 3))) {
	return (retval);
  }

  if ((retval = (*pgensock_put_data_flush) (SMTPSock))) {
	return (retval);
  }

  retval = get_smtp_line ();
  if (retval != 250 && retval != 251) {
	smtp_error ("Message not accepted by server");
	return -1;
  }
  finish_smtp_message ();
  close_smtp_socket ();

  return 0;
}


int
send_smtp_line (char *str, unsigned long len)
{
  int retval;

  if (*str == '.' &&			/* if line starts with dot, send two dots */
	  (retval = (*pgensock_put_data_buffered) (SMTPSock, str, 1))) {
	return (retval);
  }
  return ((*pgensock_put_data_buffered) (SMTPSock, str, len));
}

int
post_line (char *str, unsigned long len)
{
  int retval;

  if (*str == '.' &&			/* if line starts with dot, send two dots */
	  (retval = (*pgensock_put_data_buffered) (NNTPSock, str, 1))) {
	return (retval);
  }
  return ((*pgensock_put_data_buffered) (NNTPSock, str, len));
}

/* prepare_smtp_message
 * headers is a textblock containing the header lines for this mail
 * grab the From, To and any Cc from here to generate From: and RCPT:
 * SMTP commands
 */
int
prepare_smtp_message (TypTextBlock * headers)
{
  char out_data[MAXOUTLINE], address[MAXHEADERLINE];
  char *ptr, *line;
  int len, startLen, result;
  unsigned long i;

  if (open_smtp_socket ())
	return (-1);

  if (get_smtp_line () != 220) {
	smtp_error ("SMTP server error");
	return (-1);
  }

  sprintf (out_data, "HELO %s\r\n", my_hostname);
  put_smtp_line (SMTPSock, out_data, strlen (out_data));

  if (get_smtp_line () != 250) {
	smtp_error ("SMTP server error");
	return (-1);
  }

  for (i = 0; i < headers->numLines; i++) {
	line = TextBlockLine (headers, i);
	if (!_strnicmp (line, "from: ", 6))
	  break;
  }
  if (i < headers->numLines)
	ParseAddress (&line[6], address, MAXHEADERLINE, str, MAXINTERNALLINE);
  else
	strcpy (address, MailAddress);

  ptr = &address[strlen (address) - 1];
  while (isspace (*ptr))
	*ptr-- = '\0';				/* strip trailing space */
  sprintf (out_data, "MAIL From:<%s>\r\n", address);
  put_smtp_line (SMTPSock, out_data, strlen (out_data));

  if (get_smtp_line () != 250) {
	smtp_error ("The mail server doesn't like the sender name, "
				"have you set your mail address correctly?");
	return (-1);
  }

  /* do a series of RCPT lines for all To: addresses and Cc: address */
  for (i = 0; i < headers->numLines; i++) {
	line = TextBlockLine (headers, i);

	if (!_strnicmp (line, "to: ", 4) || !_strnicmp (line, "cc: ", 4)) {
	  ptr = strcpy (address, &line[4]);
	  while (*ptr) {
		// if there's only one token left, then len will = startLen,
		// and we'll iterate once only
		startLen = strlen (ptr);
		if ((len = strcspn (ptr, " ,\n\t\r")) != startLen) {
		  ptr[len++] = '\0';	// replace delim with NULL char

		  while (isspace (ptr[len]) || ptr[len] == ',')		// eat white space

			ptr[len++] = '\0';
		}

		sprintf (out_data, "RCPT To: <%s>\r\n", ptr);
		putline_internal (SMTPSock, out_data, strlen (out_data));

		result = get_smtp_line ();
		if (result != 250 && result != 251) {
		  sprintf (str, "The mail server doesn't like the name %s.  "
				   "Have you set the 'To: ' field correctly?", ptr);
		  smtp_error (str);
		  return (-1);
		}

		if (len == startLen)	// last token, we're done

		  break;

		ptr += len;
	  }							/* RCPT loop */
	}							/* if To: or Cc: */
  }								/* for header lines */

  sprintf (out_data, "DATA\r\n");
  put_smtp_line (SMTPSock, out_data, strlen (out_data));

  if (get_smtp_line () != 354) {
	smtp_error ("Mail server error accepting message data");
	return (-1);
  }

  return (0);

}

/* prepare_cc_smtp_message
 * destination is the address(es) to forward to
 * headers is a textblock containing the header lines for mail to be forwarded
 */
int 
prepare_cc_smtp_message (char *destination, TypTextBlock * headers)
{
  register unsigned long i;
  char toLine[MAXOUTLINE], *fromLine;
  TypTextBlock *tempHeader;
  int retval;

  /* create temporary header block containing only a To: and a From: 
   * to make prepare_smtp_message happy
   */
  if ((tempHeader = InitTextBlock (NetDoc.hDocWnd)) == NULL)
	return 1;

  _snprintf (toLine, MAXOUTLINE, "To: %s\r\n", destination);
  retval = AddLineToTextBlock (tempHeader, toLine);

  if (!retval) {
	/* copy From: line from real headers */
	for (i = 0; i < headers->numLines; i++) {
	  fromLine = TextBlockLine (headers, i);
	  if (!_strnicmp (TextBlockLine (headers, i), "from: ", 6))
		break;
	}
	if (i < headers->numLines) {
	  retval = AddLineToTextBlock (tempHeader, fromLine);
	}
  }

  retval = retval ||
	prepare_smtp_message (tempHeader) ||
	put_smtp_line (SMTPSock, toLine, lstrlen (toLine));

  FreeTextBlock (tempHeader);
  return (retval);
}

#ifdef OLD_STUFF
int send_smtp_message (TypTextBlock * headers, char *message);
int cc_smtp_message (char *destination, TypTextBlock * headers, char *editstr);
int post_edit_data (char *edit_data);
int post_unended_edit_data (char *edit_data);
int send_smtp_edit_data (char *edit_data);
int send_smtp_unended_edit_data (char *edit_data);
int post_textblock (TypTextBlock * textBlock);
int send_smtp_textblock (TypTextBlock * textBlock);

int forward_smtp_message (char *destination, TypDoc * Doc);
int send_smtp_article (char *destination, TypDoc * Doc);
int send_textblock_internal (socktag sock, TypTextBlock * textBlock);
int prepare_smtp_message (TypTextBlock * headers);


/* ---------------------------------------------------------------------------
 * transform_and_send_edit_data
 */

int 
transform_and_send_edit_data (socktag sock, char *editptr)
{
  char *index;
  char previous_char = 'x';
  unsigned int send_len;
  int retval;
  BOOL done = 0;

  send_len = lstrlen (editptr);
  index = editptr;

  while (!done) {
	/* room for extra char for double dot on end case */
	while ((unsigned int) (index - editptr) < send_len) {
	  switch (*index) {
	  case '.':
		if (previous_char == '\n') {
		  /* send _two_ dots... */
		  if ((retval = (*pgensock_put_data_buffered) (sock, index, 1))) {
			return (retval);
		  }
		}
		if ((retval = (*pgensock_put_data_buffered) (sock, index, 1))) {
		  return (retval);
		}
		break;
	  case '\r':
		if (previous_char != '\r') {
		  if ((retval = (*pgensock_put_data_buffered) (sock, index, 1))) {
			return (retval);
		  }
		}
		/* soft line-break (see EM_FMTLINES), skip extra CR */
		break;

	  default:
		if ((retval = (*pgensock_put_data_buffered) (sock, index, 1))) {
		  return (retval);
		}
	  }
	  previous_char = *index;
	  index++;
	}
	if ((unsigned int) (index - editptr) == send_len) {
	  done = 1;
	}
  }

  /* this handles the case where the user doesn't end the last
   * line with a <return>
   */

  if (editptr[send_len - 1] != '\n') {
	if ((retval = (*pgensock_put_data_buffered) (sock, "\r\n", 2))) {
	  return (retval);
	}
  }

  /* now make sure it's all sent... */
  if ((retval = (*pgensock_put_data_flush) (sock))) {
	return (retval);
  }
  return (0);
}

int
post_edit_data (char *edit_data)
{
  int retval;
  if ((retval = transform_and_send_edit_data (NNTPSock, edit_data))) {
	return (retval);
  }
  return (end_post ());
}

int
post_unended_edit_data (char *edit_data)
{
  int retval;
  if ((retval = transform_and_send_edit_data (NNTPSock, edit_data))) {
	return (retval);
  }
  return (0);
}

int
send_smtp_edit_data (char *edit_data)
{
  int retval;
  if ((retval = transform_and_send_edit_data (SMTPSock, edit_data))) {
	return (retval);
  }
  return (end_send_smtp ());
}

int
send_smtp_unended_data (char *edit_data)
{
  int retval;
  if ((retval = transform_and_send_edit_data (SMTPSock, edit_data))) {
	return (retval);
  }
  return (0);
}

/* send_smtp_message
 * headers is a textblock containing the header lines for this mail
 * message is a pointer to the text content of an edit control
 */
int
send_smtp_message (TypTextBlock * headers, char *message)
{
  result = FAIL;
  if (!prepare_smtp_message (headers) &&
	  !send_smtp_textblock (headers) &&
	  !send_smtp_edit_data (message) &&
	  !finish_smtp_message ()) {
	result = SUCCESS;
  }

  close_smtp_socket ();
  return (result);
}

int
send_textblock_internal (socktag sock, TypTextBlock * textBlock)
{
  register unsigned long i;
  char *line;
  int retval;

  for (i = 0; i < textBlock->numLines; i++) {
	line = TextBlockLine (textBlock, i);
	/* if line starts with dot, send two dots */
	if (*line == '.' &&
		(retval = (*pgensock_put_data_buffered) (sock, line, 1))) {
	  return (retval);
	}
	if ((retval = (*pgensock_put_data_buffered) (sock, line, strlen (line)))) {
	  return (retval);
	}
  }

  /* now make sure it's all sent... */
  if ((retval = (*pgensock_put_data_flush) (sock))) {
	return (retval);
  }
  return (0);
}

int
post_textblock (TypTextBlock * textBlock)
{
  return send_textblock_internal (NNTPSock, textBlock);
}

int
send_smtp_textblock (TypTextBlock * textBlock)
{
  return send_textblock_internal (SMTPSock, textBlock);
}

int 
forward_smtp_message (char *destination, TypDoc * Doc)
{
  int retval;

  if ((retval = prepare_smtp_message (destination))) {
	complain ("prepare_smtp_message returned %d\r\n", retval);
	return (retval);
  }
  else if ((retval = send_smtp_article (destination, Doc))) {
	complain ("send_smtp_article returned %d\r\n", retval);
	return (retval);
  }
  else if ((retval = finish_smtp_message ())) {
	complain ("finish_smtp_message() returned %d\r\n", retval);
	close_smtp_socket ();
	return (retval);
  }
  close_smtp_socket ();
  return (1);
}

// testing new buffered stuff...

int 
send_smtp_article (char *destination, TypDoc * Doc)
{
  HANDLE hBlock;
  unsigned int Offset;
  TypLineID MyLineID;
  TypBlock far *BlockPtr;
  TypLine far *LinePtr;
  int retval;
  char line[MAXOUTLINE], temp[MAXOUTLINE];

  _snprintf (line,
			 MAXOUTLINE,
			 "From: %s (%s)\r\n",
			 MailAddress,
			 UserName);


  if ((retval =
	   (*pgensock_put_data_buffered) (SMTPSock, line, lstrlen (line)))) {
	return (retval);
  }

  _snprintf (line,
			 MAXOUTLINE,
			 "To: %s\r\n",
			 destination);


  if ((retval =
	   (*pgensock_put_data_buffered) (SMTPSock, line, lstrlen (line)))) {
	return (retval);
  }

  /* find the subject line */
  TopOfDoc (Doc, &BlockPtr, &LinePtr);
  *line = '\0';
  while (ExtractTextLine (Doc, LinePtr, temp, MAXOUTLINE - 1)) {
	if (!_strnicmp (temp, "subject:", 8)) {
	  _snprintf (line,
				 MAXOUTLINE,
				 "Subject: %s (fwd)\r\n",
				 &temp[8]);
	  break;
	}
	if (!NextLine (&BlockPtr, &LinePtr))
	  break;
  }
  if (*line && (retval =
		  (*pgensock_put_data_buffered) (SMTPSock, line, lstrlen (line)))) {
	return (retval);
  }

  _snprintf (line,
			 MAXOUTLINE,
			 "\r\n[article forwarded from %s (%s)]\r\n\r\n",
			 UserName,
			 MailAddress);

  if ((retval =
	   (*pgensock_put_data_buffered) (SMTPSock, line, lstrlen (line)))) {
	return (retval);
  }

  TopOfDoc (Doc, &BlockPtr, &LinePtr);
  while (ExtractTextLine (Doc, LinePtr, line, MAXOUTLINE - 1)) {
	/* double a leading dot */
	if (line[0] == '.') {
	  if ((retval = (*pgensock_put_data_buffered) (SMTPSock, ".", 1))) {
		return (retval);
	  }
	}
	strcat (line, "\r\n");

	if ((retval =
		 (*pgensock_put_data_buffered) (SMTPSock, line, strlen (line)))) {
	  return (retval);
	}

	if (!NextLine (&BlockPtr, &LinePtr))
	  break;
  }
  UnlockLine (BlockPtr, LinePtr, &hBlock, &Offset, &MyLineID);

  if ((retval =
	   (*pgensock_put_data_buffered) (SMTPSock, "\r\n.\r\n", 5))) {
	return (retval);
  }
  if ((retval =
	   (*pgensock_put_data_flush) (SMTPSock))) {
	return (retval);
  }

  if ((retval = get_smtp_line ()) != 250) {
	complain ("Send Failed. get_smtp_line() returned %d\r\n", retval);
  }

  return (0);
}
#endif

/* this is for emacs
 * Local variables:
 * tab-width: 4
 * end:
 */
@


1.24
log
@catch errors without error codes in open_smtp_socket()
@
text
@d2 1
a2 1
/* $Id: wvsckgen.c 1.23 1994/12/21 19:09:23 rushing Exp rushing $ */
d336 1
a336 2
		retval == ERR_NO_ERROR_CODE)		/* Chameleon is bad, it fails but sets no error code. */
		) {
@


1.23
log
@punt to a bogus name for HELO command when gethostname() fails...
@
text
@d2 1
a2 1
/* $Id: wvsckgen.c 1.22 1994/11/28 22:01:06 jcooper Exp $ */
d335 3
a337 1
	if (retval == ERR_CANT_RESOLVE_SERVICE) {
d968 6
@


1.22
log
@93.8 update from jcooper
@
text
@d2 1
a2 1
/* $Id: wvsckgen.c 1.21 1994/11/21 21:20:46 jcooper Exp $ */
d358 7
a364 3
	gensock_error ("gensock_gethostname", retval);
	abort_mail_socket ();
	return (-1);
d366 1
@


1.21
log
@93.7 update
@
text
@d2 1
a2 1
/* $Id: wvsckgen.c 1.20 1994/11/10 01:27:39 rushing Exp $ */
d419 1
a419 1
  if ((retval = (*pgensock_put_data) (sock, line, (unsigned long) nchars))) {
@


1.20
log
@restart
@
text
@d17 1
a17 1
#include "gensock.h"
d67 1
d70 8
a77 4
  va_start (marker, fmt);
  _vsnprintf (message, ERROR_BUFFER_SIZE, fmt, marker);
  va_end (marker);
  MessageBox (NetDoc.hDocWnd, message, "WinVN GenSock Library Error", MB_OK);
d100 1
a100 1
  if ((retval = (*pgensock_getchar) (NNTPSock, 1, &ch))) {
d127 1
a127 1
  if ((retval =
d455 1
a455 1
  if ((retval = (*pgensock_put_data_buffered) (NNTPSock, "\r\n.\r\n", 5))) {
d468 1
a468 1
  if ((retval = (*pgensock_put_data_buffered) (SMTPSock, "\r\n.\r\n", 5))) {
@
