smtp coding problem

Z

zaebos

hi, i have this code which is part of a main program, to email from
within the program a log file:

int MailIt (char *mailserver, char *emailto, char *emailfrom,
char *emailsubject, char *emailmessage) {
SOCKET sockfd;
WSADATA wsaData;
FILE *smtpfile;

#define bufsize 300
int bytes_sent; /* Sock FD */
int err;
struct hostent *host; /* info from gethostbyname */
struct sockaddr_in dest_addr; /* Host Address */
char line[1000];
char *Rec_Buf = (char*) malloc(bufsize+1);
smtpfile=fopen(SMTPLog,"a+");
if (WSAStartup(0x202,&wsaData) == SOCKET_ERROR) {
fputs("WSAStartup failed",smtpfile);
WSACleanup();
return -1;
}
if ( (host=gethostbyname(mailserver)) == NULL) {
perror("gethostbyname");
exit(1);
}
memset(&dest_addr,0,sizeof(dest_addr));
memcpy(&(dest_addr.sin_addr),host->h_addr,host->h_length);

/* Prepare dest_addr */
dest_addr.sin_family= host->h_addrtype; /* AF_INET from
gethostbyname */
dest_addr.sin_port= htons(25); /* PORT defined above */

/* Get socket */

if ((sockfd=socket(AF_INET,SOCK_STREAM,0)) < 0) {
perror("socket");
exit(1);
}
/* Connect !*/
fputs("Connecting....\n",smtpfile);

if (connect(sockfd, (struct sockaddr
*)&dest_addr,sizeof(dest_addr)) == -1){
perror("connect");
exit(1);
}
sleep(waittime);
err=recv(sockfd,Rec_Buf,bufsize,0);Rec_Buf[err] = '\0';
fputs(Rec_Buf,smtpfile);
strcpy(line,"helo me.somepalace.com\n");
fputs(line,smtpfile);
bytes_sent=send(sockfd,line,strlen(line),0);
sleep(waittime);
err=recv(sockfd,Rec_Buf,bufsize,0);Rec_Buf[err] = '\0';
fputs(Rec_Buf,smtpfile);
strcpy(line,"MAIL FROM:<");
strncat(line,emailfrom,strlen(emailfrom));
strncat(line,">\n",3);
fputs(line,smtpfile);
bytes_sent=send(sockfd,line,strlen(line),0);
sleep(waittime);
err=recv(sockfd,Rec_Buf,bufsize,0);Rec_Buf[err] = '\0';
fputs(Rec_Buf,smtpfile);
strcpy(line,"RCPT TO:<");
strncat(line,emailto,strlen(emailto));
strncat(line,">\n",3);
fputs(line,smtpfile);
bytes_sent=send(sockfd,line,strlen(line),0);
sleep(waittime);
err=recv(sockfd,Rec_Buf,bufsize,0);Rec_Buf[err] = '\0';
fputs(Rec_Buf,smtpfile);
strcpy(line,"DATA\n");
fputs(line,smtpfile);
bytes_sent=send(sockfd,line,strlen(line),0);
sleep(waittime);
err=recv(sockfd,Rec_Buf,bufsize,0);Rec_Buf[err] = '\0';
fputs(Rec_Buf,smtpfile);
sleep(waittime);
strcpy(line,"To:");
strcat(line,emailto);
strcat(line,"\n");
strcat(line,"From:");
strcat(line,emailfrom);
strcat(line,"\n");
strcat(line,"Subject:");
strcat(line,emailsubject);
strcat(line,"\n");
strcat(line,emailmessage);
strcat(line,"\r\n.\r\n");
fputs(line,smtpfile);
bytes_sent=send(sockfd,line,strlen(line),0);
sleep(waittime);
err=recv(sockfd,Rec_Buf,bufsize,0);Rec_Buf[err] = '\0';
fputs(Rec_Buf,smtpfile);
strcpy(line,"quit\n");
fputs(line,smtpfile);
bytes_sent=send(sockfd,line,strlen(line),0);
sleep(waittime);
err=recv(sockfd,Rec_Buf,bufsize,0);Rec_Buf[err] = '\0';
fputs(Rec_Buf,smtpfile);
fclose(smtpfile);
#ifdef WIN32
closesocket(sockfd);
WSACleanup();
#else
close(sockfd);
#endif
}

however, my mailserver(for which i pay for hosting) is tls only for
security, and requires authentication, so I am not sure how to modify
the code to authenticate over tls and send an email....

any help is appreciated.
 
V

Vladimir S. Oka

hi, i have this code which is part of a main program, to email from
within the program a log file:

Your question as well as your code are off-topic in c.l.c. Try to find
a group that deals with mail protocols (I'd tell you which one/s/ but I
don't know).

Still, some remarks on what I see below:

1. Your code is hard to read. Better use of spacing would help a lot.
int MailIt (char *mailserver, char *emailto, char *emailfrom,
char *emailsubject, char *emailmessage) {
SOCKET sockfd;
WSADATA wsaData;
FILE *smtpfile;

#define bufsize 300

2. Macros are conventionally all-caps (unlike types and variables).
int bytes_sent; /* Sock FD */
int err;
struct hostent *host; /* info from gethostbyname */
struct sockaddr_in dest_addr; /* Host Address */
char line[1000];
char *Rec_Buf = (char*) malloc(bufsize+1);

3. Don't cast return value of malloc(). It may hide error of not
including stdlib.h.

There's probably more, but it's hard to read, so I quit.

said:
however, my mailserver(for which i pay for hosting) is tls only for
security, and requires authentication, so I am not sure how to modify
the code to authenticate over tls and send an email....

See the the top comment.
 
F

Flash Gordon

hi, i have this code which is part of a main program, to email from
within the program a log file:

#ifdef WIN32
closesocket(sockfd);
WSACleanup();
#else
close(sockfd);
#endif
}

however, my mailserver(for which i pay for hosting) is tls only for
security, and requires authentication, so I am not sure how to modify
the code to authenticate over tls and send an email....

Sockets, tls, ssl and the like are not part of standard C so you will
have to ask on groups dedicated to your implementations or socket
programming (if there are any). From the looks of it you are supporting
both Windows and POSIX systems, so you might have to ask on a couple of
groups. I would suggest comp.unix.programmer and one of the microsoft
groups as starting points, although you should check their FAQs and read
a few days posts first. Had you done that here you might have realised
that your question was not topical.
 
K

Keith Thompson

Vladimir S. Oka said:
(e-mail address removed) wrote: [...]
int MailIt (char *mailserver, char *emailto, char *emailfrom,
char *emailsubject, char *emailmessage) {
SOCKET sockfd;
WSADATA wsaData;
FILE *smtpfile;

#define bufsize 300

2. Macros are conventionally all-caps (unlike types and variables).

But FILE, defined in <stdio.h>, is an exception to this.
 
J

Jack Klein

Vladimir S. Oka said:
(e-mail address removed) wrote: [...]
int MailIt (char *mailserver, char *emailto, char *emailfrom,
char *emailsubject, char *emailmessage) {
SOCKET sockfd;
WSADATA wsaData;
FILE *smtpfile;

#define bufsize 300

2. Macros are conventionally all-caps (unlike types and variables).

But FILE, defined in <stdio.h>, is an exception to this.

Just curious, have you ever seen a <stdio.h> where FILE is not a macro
(i.e., a typedef?). I don't think I ever have.
 
B

Ben Pfaff

Jack Klein said:
Just curious, have you ever seen a <stdio.h> where FILE is not a macro
(i.e., a typedef?). I don't think I ever have.

In the locally installed glibc it appears to just be a typedef:
typedef struct _IO_FILE FILE;
There's a lot of conditional inclusion nonsense nearby so I might
be missing a macro definition.

You appear to be equating macros and typedefs. I don't
understand that.
 
K

Keith Thompson

Jack Klein said:
Vladimir S. Oka said:
(e-mail address removed) wrote: [...]
int MailIt (char *mailserver, char *emailto, char *emailfrom,
char *emailsubject, char *emailmessage) {
SOCKET sockfd;
WSADATA wsaData;
FILE *smtpfile;

#define bufsize 300

2. Macros are conventionally all-caps (unlike types and variables).

But FILE, defined in <stdio.h>, is an exception to this.

Just curious, have you ever seen a <stdio.h> where FILE is not a macro
(i.e., a typedef?). I don't think I ever have.

Typedefs are not macros.
 
W

Walter Roberson

Just curious, have you ever seen a <stdio.h> where FILE is not a macro
(i.e., a typedef?). I don't think I ever have.

SGI IRIX 6.2 and SGI IRIX 6.5 have it as a typedef.
 
K

Keith Thompson

Keith Thompson said:
Jack Klein said:
(e-mail address removed) wrote:
[...]
int MailIt (char *mailserver, char *emailto, char *emailfrom,
char *emailsubject, char *emailmessage) {
SOCKET sockfd;
WSADATA wsaData;
FILE *smtpfile;

#define bufsize 300

2. Macros are conventionally all-caps (unlike types and variables).

But FILE, defined in <stdio.h>, is an exception to this.

Just curious, have you ever seen a <stdio.h> where FILE is not a macro
(i.e., a typedef?). I don't think I ever have.

Typedefs are not macros.

Or did you mean "a typedef" to correspond to "not a macro" rather than
to "a macro"? If so, the question at least makes sense, but FILE is
usually a typedef (not a macro) in all the <stdio.h> implementations
I've seen.
 
K

Keith Thompson

Keith Thompson said:
Or did you mean "a typedef" to correspond to "not a macro" rather than
to "a macro"? If so, the question at least makes sense, but FILE is
usually a typedef (not a macro) in all the <stdio.h> implementations
I've seen.

That last sentence ("usually ... all") was a victim of careless
editing and insufficient proofreading.

I think that FILE is a typedef (not a macro) in all the <stdio.h>
implementations I've seen. I know it's a typedef in all the <stdio.h>
implementations I have easy access to at the moment (Linux, Cygwin,
Solaris, AIX, OSF); the fact that those are all Unix-like systems may
imply some bias.
 
J

Jordan Abel

That last sentence ("usually ... all") was a victim of careless
editing and insufficient proofreading.

I think that FILE is a typedef (not a macro) in all the <stdio.h>
implementations I've seen. I know it's a typedef in all the <stdio.h>
implementations I have easy access to at the moment (Linux, Cygwin,
Solaris, AIX, OSF); the fact that those are all Unix-like systems may
imply some bias.

Unix V7's stdio.h contains:

# ifndef FILE
extern struct _iobuf {
char *_ptr;
int _cnt;
char *_base;
char _flag;
char _file;
} _iob[_NFILE];
# endif
#define FILE struct _iobuf

Like many things in modern C implementations, stdio was, of course,
invented for v7. [v6 had a bizarre precursor library, with no FILE's -
the user-visible API used file descriptors despite the fact that the
library maintained buffering etc.]
 
D

Dave Thompson

On 7 Mar 2006 06:48:53 -0800, "(e-mail address removed)" <[email protected]>
wrote:

#if mostly_offtopic but see some points below
hi, i have this code which is part of a main program, to email from
within the program a log file:

int MailIt (char *mailserver, char *emailto, char *emailfrom,
char *emailsubject, char *emailmessage) {
SOCKET sockfd;
WSADATA wsaData;
FILE *smtpfile;

#define bufsize 300
int bytes_sent; /* Sock FD */
int err;
struct hostent *host; /* info from gethostbyname */
struct sockaddr_in dest_addr; /* Host Address */
char line[1000];
char *Rec_Buf = (char*) malloc(bufsize+1);

It's odd to make 1000 bytes automatic but 300+1 dynamic (heap). Legal,
but odd. Unless there's a reason for the difference, be consistent.
smtpfile=fopen(SMTPLog,"a+");

Your code doesn't need + (update), and you should check the result of
fopen for a null pointer (indicating failure) before using it.
if (WSAStartup(0x202,&wsaData) == SOCKET_ERROR) {
fputs("WSAStartup failed",smtpfile);
WSACleanup();
return -1;
}

As you conditionalize Windows/Unix below, this should be Win-only.
if ( (host=gethostbyname(mailserver)) == NULL) {
perror("gethostbyname");
exit(1);
}
memset(&dest_addr,0,sizeof(dest_addr));
memcpy(&(dest_addr.sin_addr),host->h_addr,host->h_length);

/* Prepare dest_addr */
dest_addr.sin_family= host->h_addrtype; /* AF_INET from
gethostbyname */
dest_addr.sin_port= htons(25); /* PORT defined above */

/* Get socket */

if ((sockfd=socket(AF_INET,SOCK_STREAM,0)) < 0) {
perror("socket");
exit(1);
}

This shouldn't work for Windows where SOCKET is a handle -- and the
part above would work _only_ for Windows. Should test ==
INVALID_SOCKET, which you can easily make work on Unix also.
/* Connect !*/
fputs("Connecting....\n",smtpfile);

if (connect(sockfd, (struct sockaddr
*)&dest_addr,sizeof(dest_addr)) == -1){
perror("connect");
exit(1);
}

Your other checks are for SOCKET_ERROR; this is inconsistent.
sleep(waittime);
err=recv(sockfd,Rec_Buf,bufsize,0);Rec_Buf[err] = '\0';
fputs(Rec_Buf,smtpfile);

There's no point in sleep'ing before recv'ing on a blocking socket.
The return from recv, as other POSIX I/O calls, can be negative, in
which case the array indexing is invalid. To be really picky, you
shouldn't assume a "message" from the other end of a TCP connection,
here the server banner, will always be received by one recv() call.
However, you have more serious problems to deal with.
strcpy(line,"helo me.somepalace.com\n");
fputs(line,smtpfile);
bytes_sent=send(sockfd,line,strlen(line),0);

SMTP commands (and responses), like most(?) other textual Internet
protocols, must end with CR LF. \n is a single character, almost
certainly (not absolutely) LF, but can't be two. For I/O to a text
stream using <stdio.h>, \n will be translated to (and from) the
system's line delimiter which on _some_ systems like Windows is CR LF,
but even there no such thing happens for socket routines.
sleep(waittime);
err=recv(sockfd,Rec_Buf,bufsize,0);Rec_Buf[err] = '\0';
fputs(Rec_Buf,smtpfile);
strcpy(line,"MAIL FROM:<");
strncat(line,emailfrom,strlen(emailfrom));

This will always terminate at the count rather than the null, and thus
not correctly terminate the string you're building. At best, if the
value you build here is shorter than the value you did above, you just
get a mixed wrong value; at worst, if your next line runs off into
uninitialized memory you officially get Undefined Behavior which could
in theory be anything up to nasal demons, and in practice will often
be a crash or garbage data.
strncat(line,">\n",3);

This works if the above line didn't leave an invalid string, but both
the previous one and this one could more easily use strcat() no n.
Or you could replace all three lines by
sprintf (line, "MAIL FROM <%s>\r\n", emailfrom);
(Note added CR per above. Or even better \x0D\x0A, although for a
seriously non-ASCII machine you need many other changes as well.)

But either of these ways is vulnerable to overflow if the supplied
string is too long; at simplest you could use
sprintf (line, "MAIL FROM <%.120s>\r\n", emailfrom);
which is small enough it won't cause problems on any real destination
but large enough to be useful. If you know more about the destinations
you will be talking to, and need to, could increase accordingly.

Aside: for limiting sprintf in general in a C99 implementation (rare)
or as an extension to C89 (more common) you can use snprintf. However,
it truncates without regard to the data content, which in this case
gives you a malformed command.
fputs(line,smtpfile);
bytes_sent=send(sockfd,line,strlen(line),0);
sleep(waittime);
err=recv(sockfd,Rec_Buf,bufsize,0);Rec_Buf[err] = '\0';
fputs(Rec_Buf,smtpfile);

You should always check the SMTP response before continuing. In theory
you should even have checked the banner.
strcpy(line,"RCPT TO:<");
strncat(line,emailto,strlen(emailto));
strncat(line,">\n",3);
fputs(line,smtpfile);
bytes_sent=send(sockfd,line,strlen(line),0);
sleep(waittime);
err=recv(sockfd,Rec_Buf,bufsize,0);Rec_Buf[err] = '\0';
fputs(Rec_Buf,smtpfile);

Ditto and ditto, and more below.
strcpy(line,"DATA\n");
fputs(line,smtpfile);
bytes_sent=send(sockfd,line,strlen(line),0);
sleep(waittime);
err=recv(sockfd,Rec_Buf,bufsize,0);Rec_Buf[err] = '\0';
fputs(Rec_Buf,smtpfile);
sleep(waittime);
strcpy(line,"To:");
strcat(line,emailto);
strcat(line,"\n");
strcat(line,"From:");
strcat(line,emailfrom);
strcat(line,"\n");
strcat(line,"Subject:");
strcat(line,emailsubject);
strcat(line,"\n");
strcat(line,emailmessage);
strcat(line,"\r\n.\r\n");

You finally got (part of) one right -- probably because without it
some servers weren't Postelian enough to recognize the (vital) EOM.
fputs(line,smtpfile);
bytes_sent=send(sockfd,line,strlen(line),0);
sleep(waittime);
err=recv(sockfd,Rec_Buf,bufsize,0);Rec_Buf[err] = '\0';
fputs(Rec_Buf,smtpfile);
strcpy(line,"quit\n");
fputs(line,smtpfile);
bytes_sent=send(sockfd,line,strlen(line),0);
sleep(waittime);
err=recv(sockfd,Rec_Buf,bufsize,0);Rec_Buf[err] = '\0';
fputs(Rec_Buf,smtpfile);
fclose(smtpfile);
#ifdef WIN32
closesocket(sockfd);
WSACleanup();
#else
close(sockfd);
#endif

You don't free(Rec_Buf); this is a memory leak.
}

however, my mailserver(for which i pay for hosting) is tls only for
security, and requires authentication, so I am not sure how to modify
the code to authenticate over tls and send an email....
Almost certainly your best bet is to use openssl, an opensource
library, if BSD-style terms are acceptable. See www.openssl.org.

Even so, it's not trivial; SSL/TLS is a pretty big protocol,
especially with all the options. At the level of understanding this
code displays, if your systems allow it, which both Windows and (any)
Unix do, you might be better off using system() to invoke a separate
(prebuilt) mail-sending program.

- David.Thompson1 at worldnet.att.net
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,961
Messages
2,570,131
Members
46,689
Latest member
liammiller

Latest Threads

Top