Subject: Pbs with smtp_send

From: Adam Treister <[email-masked]>
Date: Fri, 05 Apr 1996 21:16:30 -0800

C-client-ers:

I hope someone can point out the stupidity of my ways, cuz I cant find whats
wrong here.

I made a variation of the smtp_mail function that takes a Mac file pointer
instead of a BODY.  I need a version that of send that writes to the Outbox if
the program is not on line, and I decided to do the SMTP send from that file.
The code is below.

It works fine up to the last line before returning, where it sends the
terminating "period on a line by itself".  smtp_send sends ".\r\n" and gets a
prompt change in ioResult, but then it calls smtp_reply which calls tcp_getline
and that function never seems to get a response from the server (ioResult never
goes from 1 to 0) It just idles until I hit cmd-period.  (I've left it >4
minutes and it doesn't seem to time out on its own)

I've commented out the code that streams the file contents, and the behavior is
the same.  Its something about   smtp_send(stream,".",NIL);  (which I trust
works okay in smtp_mail).  If I comment out the line, then the same behavior
happens when smtp_close sends the "QUIT" string.  Similarly if I replace
smtp_send with smtp_soutr, the call succeeds but the next call to smtp_send with
not get its reply.

Does this ring any bells with anyone?  Its driving me crazy, cuz its really hard
to test if my MIME messages are well constructed if I can't send them out!

Adam

------------------------
Note: the first two thirds is a direct copy of smtp_mail, and works fine with my
messages.  

long smtp_sendfile (SENDSTREAM *stream,char *type,ENVELOPE *env,FSSpec
*inMacFile)
{
  char tmp[8*MAILTMPLEN];
  long error = NIL;
  if (!(env->to || env->cc || env->bcc)) {
  				/* no recipients in request */
    smtp_fake (stream,SMTPHARDERROR,"No recipients specified");
    return NIL;
  }
  				/* make sure stream is in good shape */
  smtp_send (stream,"RSET",NIL);
  strcpy (tmp,"FROM:<");	/* compose "MAIL FROM:<return-path>" */
  rfc822_address (tmp,env->return_path);
  strcat (tmp,">");
  if (stream->ok_8bitmime) strcat (tmp," BODY=8BITMIME");
				/* send "MAIL FROM" command */
  if (!(smtp_send (stream,type,tmp) == SMTPOK)) return NIL;
				/* negotiate the recipients */
  if (env->to) smtp_rcpt (stream,env->to,&error);
  if (env->cc) smtp_rcpt (stream,env->cc,&error);
  if (env->bcc) smtp_rcpt (stream,env->bcc,&error);
  if (error) {			/* any recipients failed? */
      				/* reset the stream */
    smtp_send (stream,"RSET",NIL);
    smtp_fake (stream,SMTPHARDERROR,"One or more recipients failed");
    return NIL;
  }
				/* negotiate data command */
  if (!(smtp_send (stream,"DATA",NIL) == SMTPREADY)) return NIL;
				/* set up error in case failure */
  smtp_fake (stream,SMTPSOFTFATAL,"SMTP connection went away!");
				/* encode body as necessary */
//  if (stream->ok_8bitmime) rfc822_encode_body_8bit (env,body);
//  else rfc822_encode_body_7bit (env,body);
				/* output data, return success status */
//--------------------------------------------------------------------------
// start of changes 		//?? AST 96/03/25

const long kBufferSize = 8 * MAILTMPLEN;		// or 8K -- this better not be more
than the tmp declaration above!
long bufferSize = kBufferSize;

	short refNum;
	OSErr err = FSpOpenDF(inMacFile,fsRdPerm,&refNum);
	Boolean done = (err != noErr);
	while (!done)
	{
		bufferSize = kBufferSize;
		err = FSRead(refNum,&bufferSize,tmp);
		if ((err == noErr) OR (err == eofErr))
			smtp_soutr(stream->tcpstream,tmp);
		done = (err != noErr) OR (bufferSize < kBufferSize);
	} 
		
	smtp_send(stream,".",NIL);
	return (err == noErr) ? 1 : 0;

}

---

From: Mark Crispin <[email-masked]>
Date: Fri, 5 Apr 1996 21:22:15 -0800 (PST)

Adam -

I'm willing to wager (with an 90% chance of certainty) that you forgot to
convert from Mac newlines (bare CR) to Internet newlines CRLF.  c-client goes
to effort to ensure this, but as far as I can tell your routine isn't.

The end of message signal is ``CR LF . CR LF''.  If you aren't sending proper
newlines then what's getting sent is likely to be ``CR . CR LF'' which won't
work.

As a kludge, you could change the smtp_send() call to send "\015\012.", but
the problem with that is that all your messages will have an extra blank line
at the bottom.  Better to fix your newlines; the routine to do that is
strcrlfcpy().  You need a second buffer that's (2*kBufferSize)+1 long to
handle the worst case situation.

-- Mark --

---

From: Adam Treister <[email-masked]>
Date: Sat, 06 Apr 1996 16:09:16 -0800

Mark,

>     Better to fix your newlines; the routine to do that is
>   strcrlfcpy().  

A couple of my many pbs were in strcrlfcpy.  It was converting CR -> LF CR.
Below is a version with two changes.  This should only affect MAC c-client
developers.

Let me know if you don't think they're appropriate.  This hasn't totally fixed
my pb, but is a step forward.

Adam

unsigned long strcrlfcpy (char **dst,unsigned long *dstl,char *src,
			  unsigned long srcl)
{
  long i,j;
  char *d = src;
				/* count number of CR's in source string(s) */

  for (i = srcl,j = 0; j < srcl; j++) 
  	if ((*d++ == '\015') && (*d != '\012'))							// ?AST - 96/04/06
  	  i++;
// REMOVED   for (i = srcl,j = 0; j < srcl; j++) if (*d++ == '\015') i++;

				/* flush destination buffer if too small */
  if (*dst && (i > *dstl)) fs_give ((void **) dst);
  if (!*dst) {			/* make a new buffer if needed */
    *dst = (char *) fs_get ((*dstl = i) + 1);
    if (dstl) *dstl = i;	/* return new buffer length to main program */
  }
  d = *dst;			/* destination string */
  while (srcl--) {		/* copy strings */
    *d++ = *src++;		/* copy character */
				/* append line feed to bare CR */
    if ((*(src-1) == '\015') && (*src != '\012')) *d++ = '\012';		// ?AST -
96/04/06
// REMOVED   if ((*src == '\015') && (src[1] != '\012')) *d++ = '\012';
  }
  *d = '\0';			/* tie off destination */
  return d - *dst;		/* return length */
}