1 /* Copyright 1996 Harry Hochheiser
3 * For license terms, see the file COPYING in this directory.
6 /***********************************************************************
9 programmer: Harry Hochheiser
10 description: Handling of SMTP connections, and processing of mail
11 to be forwarded via SMTP connections.
13 7/30/96. Note: since this file is new from scratch, I'll assume
14 that I'm working on a modern (ANSI) compiler, and I'll use
18 ***********************************************************************/
21 #include <sys/types.h>
25 #include "popforward.h"
28 static int POP3_parseHeaders(int number, int socket,char **from,int *replFlag);
29 static int SMTP_sendMessageHeaders(int mboxfd,struct optrec *option,
31 static int SendData(int f,char *buf,int check);
34 /*********************************************************************
36 description: Send a "HELO" message to the SMTP server.
39 socket TCP/IP socket for connection to SMTP
40 return value: Result of SMTP_OK: based on codes in popforward.h.
42 *********************************************************************/
44 int SMTP_helo(int socket,char *host)
47 char buf[SMTPBUFSIZE];
48 sprintf(buf,"HELO %s\r\n",host);
49 SockPrintf(socket,"%s",buf);
50 ok = SMTP_ok(socket,buf);
55 /*********************************************************************
57 description: Send a "MAIL FROM:" message to the SMTP server.
60 socket TCP/IP socket for connection to SMTP
61 fromuser: user name of originator
62 fromhost: host name of originator.
64 Note: these args are likely to change, as we get fancier about
67 return value: Result of SMTP_ok: based on codes in popforward.h.
69 *********************************************************************/
70 int SMTP_from(int socket,char *fromuser,char *fromhost)
72 char buf[SMTPBUFSIZE]; /* it's as good as size as any... */
74 SockPrintf(socket,"MAIL FROM %s@%s\n",fromuser,fromhost);
75 ok= SMTP_ok(socket,buf);
81 /*********************************************************************
83 description: Send a "RCPT TO:" message to the SMTP server.
86 socket TCP/IP socket for connection to SMTP
87 toser: user name of recipient
88 tohost: host name of recipient
90 return value: Result of SMTP_OK: based on codes in popforward.h.
92 *********************************************************************/
93 int SMTP_rcpt(int socket,char *touser,char *tohost)
95 char buf[SMTPBUFSIZE]; /* it's as good as size as any... */
98 SockPrintf(socket,"RCPT TO: %s@%s\n",touser,tohost);
99 ok = SMTP_ok(socket,buf);
105 /*********************************************************************
107 description: Send a "DATA" message to the SMTP server.
110 socket TCP/IP socket for connection to SMTP
112 return value: Result of SMTP_OK: based on codes in popforward.h.
114 *********************************************************************/
115 int SMTP_data(int socket)
117 SockPrintf(socket,"DATA\n");
121 /*********************************************************************
123 description: Send a "DATA" message to the SMTP server.
126 socket TCP/IP socket for connection to SMTP
128 return value: Result of SMTP_OK: based on codes in popforward.h.
130 *********************************************************************/
131 void SMTP_rset(int socket)
133 SockPrintf(socket,"RSET\n");
138 /*********************************************************************
140 description: Returns the status of the smtp connection
143 socket TCP/IP socket for connection to SMTP
145 return value: based on codes in popforward.h.
146 Do the dirty work of seeing what the status is..
147 *********************************************************************/
148 static int SMTP_check(int socket,char *argbuf)
151 char buf[SMTPBUFSIZE];
153 if (SMTP_Gets(socket, buf, sizeof(buf)) > 0) {
156 if (buf[0] == '1' || buf[0] == '2' || buf[0] == '3')
162 ok= SM_UNRECOVERABLE;
166 /*********************************************************************
168 description: Returns the statsus of the smtp connection
171 socket TCP/IP socket for connection to SMTP
173 return value: based on codes in popforward.h.
175 NOTE: As of 7/31/96 Initial implementation, we're just returning
176 a dummy value of SM_OK. Eventually, we should really implement this.
177 *********************************************************************/
178 int SMTP_ok(int socket,char *argbuf)
181 char buf[SMTPBUFSIZE];
183 /* I can tell that the SMTP server connection is ok if I can read a
184 status message that starts with "1xx" ,"2xx" or "3xx".
185 Therefore, it can't be ok if there's no data waiting to be read
187 Tried to deal with this with a call to SockDataWaiting, but
192 ok = SMTP_check(socket,argbuf);
193 if (ok == SM_ERROR) /* if we got an error, */
196 ok = SMTP_check(socket,argbuf); /* how does it look now ? */
198 ok = SM_ERROR; /* It's just a simple error, for*/
199 /* the current message */
201 ok = SM_UNRECOVERABLE; /* if It still says error, we're */
207 /*********************************************************************
209 description: Gets a line from the SMTP connection
212 socket TCP/IP socket for connection to SMTP
214 return value: number of bytes read.
216 *********************************************************************/
217 int SMTP_Gets(int socket,char *buf,int sz)
219 return read(socket,buf,sz);
223 /*********************************************************************
224 function: POP3_readSMTP
225 description: Read the message content as described in RFC 1225.
227 number message number.
228 socket ... to which the server is connected.
229 mboxfd open file descriptor to which the retrieved message will
231 options added 7/30/96, HSH send in the whole options package...
232 server: originating pop server. 7/30/96, HSH
234 This procedure is the SMTP version of the original POP3_readmsg that
235 is found in the original popforward. 8/2/96, HSH
236 return value: zero if success else PS_* return code.
238 globals: reads outlevel.
239 *********************************************************************/
241 int POP3_readSMTP(int number,int socket,int mboxfd,struct optrec *options,
244 char buf [MSGBUFSIZE];
245 char smtpbuf[SMTPBUFSIZE];
247 char fromBuf[MSGBUFSIZE];
248 char *summaryHeaders[3];
252 int lines,sizeticker;
260 /* HSH 8/19/96, Archive file */
267 /* This keeps the retrieved message count for display purposes */
270 /* set up for status message if outlevel allows it */
271 /* Get this into log file as well. */
274 ok = POP3_parseHeaders(number,socket,&from,&replFlag);
277 if (from) free(from);
281 ok = POP3_sendGet(number,options,socket);
284 if (from) free(from);
288 /* 8/19/96 HSH open the archive file.. */
290 if ((archive =archGetFile(options,&msgnum)) <= 0)
292 if (from) free(from);
296 /* reads the message content from the server */
299 sizeticker = MSGBUFSIZE;
301 if (SockGets(socket,buf,sizeof(buf)) < 0)
303 if (from) free(from);
307 if (buf[0] == '\r' || buf[0] == '\n')
312 break; /* end of message */
316 /* Check for Unix 'From' header, and add a bogus one if it's not
317 present -- only if not using an MDA.
318 XXX -- should probably parse real From: header and use its
319 address field instead of bogus 'POPmail' string.
325 if (strlen(bufp) >= strlen("From "))
326 needFrom = strncasecmp(bufp,"From ",strlen("From "));
330 if ((ok = SMTP_sendMessageHeaders(mboxfd,options,from)) != SM_OK)
335 sprintf(fromBuf,"From POPmail %s",ctime(&now));
336 if ((ok =SendData(mboxfd,fromBuf,0)) != SM_OK)
341 n = write(archive,bufp,strlen(bufp));
343 /* write this line to the file */
344 if ((ok =SendData(mboxfd,bufp,0)) != SM_OK)
346 /* Abort the message, so we'll be clear.. */
347 SendData(mboxfd,BINMAIL_TERM,0);
352 sizeticker -= strlen(bufp);
356 if ((ok =SendData(mboxfd,BINMAIL_TERM,0)) !=SM_OK)
360 /* finish up display output */
362 if (from) free(from);
363 if (archive != 0) close(archive);
367 if (archive != 0) close(archive);
369 if (from) free(from);
373 /******************************************************************
374 function: POP3_parseHeaders
375 description: Read the headers of the mail message, in order to grab the
376 "From" and "reply to" fields, to be used for proper
379 number message number
380 socket TCP socket for POP connection
381 from character pointer to hold value of message "FROM" field
382 replFlag indicates whether or not we've seen a reply flag.
384 ret. value: non-zero on success, else zero.
385 globals: SockGets POP3_OK.
386 calls: reads outlevel.
387 *****************************************************************/
388 int POP3_parseHeaders(number,socket,from,replFlag)
396 char buf[MSGBUFSIZE];
400 ok = POP3_sendTOP(number,0,socket);
404 ok = -1; /* we're not ok until we find "FROM: " */
405 /* read lines in until we're done.. */
409 if (SockGets(socket,buf,sizeof(buf)) < 0)
418 break; /* end of message */
422 if (len < strlen(HEADER_FROM)) /* since From header is shorter than reply-to, it */
423 continue; /* can't be either type. */
425 /* if it starts with "FROM: ", grab from */
426 if (strncasecmp(buf,HEADER_FROM,strlen(HEADER_FROM)) == 0)
428 bufp = buf + strlen(HEADER_FROM);
429 *from = strdup(bufp);
432 if (strncasecmp(buf,HEADER_REPLY,strlen(HEADER_REPLY)) == 0)
440 /******************************************************************
441 function: SMTP_sendMessageHeaders
442 description: Send the headers for the smtp message along to the mailbox..
444 number message number
445 socket TCP socket for POP connection
446 from character pointer to hold value of message "FROM" field
447 replFlag indicates whether or not we've seen a reply flag.
449 ret. value: non-zero on success, else zero.
450 globals: SockGets POP3_OK.
451 calls: reads outlevel.
452 *****************************************************************/
453 int SMTP_sendMessageHeaders(int mboxfd,struct optrec *options,char *from)
455 char smtpbuf[SMTPBUFSIZE];
456 char fromBuf[MSGBUFSIZE];
460 /* 7/30/96, HSH add stuff to print out the SMTP commands. */
461 ok = SMTP_ok(mboxfd,smtpbuf);
466 /* mail is from whoever the headers said it was from */
467 sprintf(fromBuf,"MAIL FROM: %s\r\n",from);
468 if ((ok = SendData(mboxfd,fromBuf,1)) != SM_OK)
471 /* Now here, add something for the receipt field. 7/30/96,
473 sprintf(fromBuf,"RCPT TO: %s@%s\r\n",options->forwarduser,
474 options->forwardhost);
475 if ((ok=SendData(mboxfd,fromBuf,1)) != SM_OK)
478 sprintf(fromBuf,"DATA\r\n");
479 ok =SendData(mboxfd,fromBuf,1);
484 /******************************************************************
486 description: Write to socket or file, as appropriate for destination
488 f socket or file descriptor
490 dest options destination.
491 check 1 if we should check for SMTP_ok, 0 if not...
492 ignored if DEST is not TO_SMTP
495 ret. value: 0 if ok, otherwise, non-zero..
498 *****************************************************************/
500 static int SendData(int f,char *buf,int check)
503 char smtpbuf[SMTPBUFSIZE];
504 int len = strlen(buf);
506 res = SockWrite(f,buf,len);
509 res = SMTP_ok(f,smtpbuf);