summaryrefslogtreecommitdiff
path: root/src/pop3.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/pop3.c')
-rw-r--r--src/pop3.c530
1 files changed, 530 insertions, 0 deletions
diff --git a/src/pop3.c b/src/pop3.c
new file mode 100644
index 0000000..8fd2750
--- /dev/null
+++ b/src/pop3.c
@@ -0,0 +1,530 @@
+/*
+
+ kbs - Simple, easily fooled, POP3 spam filter
+
+ Copyright (C) 2003 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ -------------------------------------------------------------------------
+
+ POP3 Interface
+
+*/
+static const char id[]="$Id$";
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <ctype.h>
+
+#include <sys/types.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <netdb.h>
+
+#include "global.h"
+#include "pop3.h"
+#include "dstring.h"
+#include "util.h"
+
+
+/* ---------------------------------------- CONSTANTS
+*/
+#define BLOCKSIZE 512
+
+#define HDR_UNKNOWN -1
+#define HDR_SUBJECT 0
+#define HDR_FROM 1
+#define HDR_TO 2
+#define HDR_CONTENT_TYPE 3
+
+/* ---------------------------------------- TYPES
+*/
+
+
+/* ---------------------------------------- GLOBALS
+*/
+static int sock;
+static int timeout;
+static int connected=FALSE;
+
+
+/* ---------------------------------------- PRIVATE FUNCTIONS
+*/
+static void Chomp(char *p)
+{
+ size_t l;
+
+ l=strlen(p);
+
+ if (l && p[l-1]=='\012')
+ {
+ p[--l]=0;
+ }
+
+ if (l && p[l-1]=='\015')
+ {
+ p[--l]=0;
+ }
+}
+
+
+static char *ChompQuotesWS(char *p)
+{
+ size_t l;
+
+ l=strlen(p);
+
+ while (l && (p[l-1]=='"' || isspace(p[l-1])))
+ {
+ p[--l]=0;
+ }
+
+ while (l && (p[0]=='"' || isspace(p[0])))
+ memmove(p,p+1,--l);
+
+ return p;
+}
+
+
+static int Connect(const char *hostname, int port)
+{
+ struct hostent *remote;
+ struct sockaddr_in addr;
+
+ if (!(remote=gethostbyname(hostname)))
+ {
+ return FALSE;
+ }
+
+ memcpy(&addr.sin_addr,remote->h_addr,remote->h_length);
+
+ if ((sock=socket(PF_INET,SOCK_STREAM,0))==-1)
+ return FALSE;
+
+ addr.sin_family=AF_INET;
+ addr.sin_port=htons(port);
+
+ if (connect(sock,(const void *)&addr,sizeof(addr))==-1)
+ return FALSE;
+
+ return TRUE;
+}
+
+
+static int SendSock(const char *p, size_t len)
+{
+ size_t sent=0;
+
+ while(sent<len)
+ {
+ ssize_t w;
+
+ w=write(sock,p+sent,len-sent);
+
+ if (w==-1)
+ return -1;
+
+ if (w==0)
+ return 0;
+
+ sent+=w;
+ }
+
+ return 1;
+}
+
+
+static int Send(const char *cmd, ...)
+{
+ va_list ap;
+ const char *p;
+ int status;
+
+ va_start(ap,cmd);
+
+ status=SendSock(cmd,strlen(cmd));
+
+ p=va_arg(ap,const char *);
+
+ while (p && status==1)
+ {
+ status=SendSock(p,strlen(p));
+ p=va_arg(ap,const char *);
+ }
+
+ va_end(ap);
+
+ if (status==1)
+ status=SendSock("\015\012",2);
+
+ return status;
+}
+
+
+static int GetChar(void)
+{
+ static char buff[BLOCKSIZE];
+ static ssize_t len=0;
+ static int ptr=0;
+ int ch;
+
+ if (len==0 || ptr==len)
+ {
+ struct timeval tv;
+ fd_set set;
+
+ tv.tv_sec=timeout;
+ tv.tv_usec=timeout;
+
+ FD_ZERO(&set);
+ FD_SET(sock,&set);
+
+ if (select(sock+1,&set,NULL,NULL,&tv)==-1)
+ return -1;
+
+ if (!FD_ISSET(sock,&set))
+ return -1;
+
+ if ((len=read(sock,buff,sizeof buff))<1)
+ return -1;
+
+ ptr=0;
+ }
+
+ return buff[ptr++];
+}
+
+
+static int GetLine(DString t)
+{
+ size_t size;
+ int done;
+ int ch;
+ int last;
+
+ done=FALSE;
+
+ while(!done && (ch=GetChar())!=-1)
+ {
+ DSAddChar(t,ch);
+
+ if (last=='\015' && ch=='\012')
+ done=TRUE;
+
+ last=ch;
+ }
+
+ if (ch==-1)
+ return FALSE;
+
+ Chomp(t->text);
+
+ return TRUE;
+}
+
+
+static int GetResponse(DString ret)
+{
+ DString t;
+ int flag;
+
+ t=DSInit();
+
+ if (GetLine(t))
+ flag=t->text[0]=='+';
+ else
+ flag=FALSE;
+
+ if (ret)
+ DSAddDS(ret,t);
+
+ DSFree(t);
+
+ return flag;
+}
+
+
+static int GetMultiLine(DString ret)
+{
+ int flag;
+
+ if (GetLine(ret))
+ flag=TRUE;
+ else
+ flag=FALSE;
+
+ return flag;
+}
+
+
+static void ParseHeader(POP3Message *msg, char *line)
+{
+ static const struct
+ {
+ const char *text;
+ int type;
+ } field[]=
+ {
+ {"Subject: ", HDR_SUBJECT},
+ {"From: ", HDR_FROM},
+ {"To: ", HDR_TO},
+ {"Content-type: ", HDR_CONTENT_TYPE},
+ {"Content-Type: ", HDR_CONTENT_TYPE},
+ {NULL, HDR_UNKNOWN}
+ };
+
+ int f;
+ int type=HDR_UNKNOWN;
+
+ for(f=0;type==HDR_UNKNOWN && field[f].text;f++)
+ if (strncmp(field[f].text,line,strlen(field[f].text))==0)
+ {
+ type=field[f].type;
+ line+=strlen(field[f].text);
+ }
+
+ switch(type)
+ {
+ case HDR_SUBJECT:
+ msg->subject=CopyStr(line);
+ break;
+
+ case HDR_FROM:
+ if (strchr(line,'<'))
+ {
+ char *t[3];
+
+ for(f=0;f<3 && t[f-1];f++)
+ t[f]=strtok(f==0 ? line:NULL,"<>@");
+
+ msg->from=CopyStr(t[0] ? ChompQuotesWS(t[0]) : "UNKNOWN");
+ msg->from_uname=CopyStr(t[1] ? t[1] : "UNKNOWN");
+ msg->from_domain=CopyStr(t[2] ? t[2] : "UNKNOWN");
+ }
+ else
+ {
+ char *t[2];
+
+ for(f=0;f<2 && t[f-1];f++)
+ t[f]=strtok(f==0 ? line:NULL,"@");
+
+ msg->from=CopyStr("UNKNOWN");
+ msg->from_uname=CopyStr(t[0] ? t[0] : "UNKNOWN");
+ msg->from_domain=CopyStr(t[1] ? t[1] : "UNKNOWN");
+ }
+ break;
+
+ case HDR_TO:
+ msg->to=CopyStr(line);
+ break;
+
+ case HDR_CONTENT_TYPE:
+ msg->content_type=CopyStr(line);
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+/* ---------------------------------------- INTERFACES
+*/
+
+POP3Status POP3Connect(const char *hostname, int port,
+ const char *username, const char *passwd,
+ int t)
+{
+ timeout=t;
+ connected=FALSE;
+
+ if (port==0)
+ {
+ struct servent *ent;
+
+ if ((ent=getservbyname("pop3","tcp")))
+ port=ntohs(ent->s_port);
+ else
+ port=110;
+ }
+
+ if (!Connect(hostname,port))
+ return POP3_NOCONNECT;
+
+ if (!GetResponse(NULL))
+ return POP3_COMMERROR;
+
+ if (Send("USER ",username,(const char *)NULL)!=1)
+ return POP3_COMMERROR;
+
+ if (!GetResponse(NULL))
+ return POP3_BADUSER;
+
+ if (Send("PASS ",passwd,(const char *)NULL)!=1)
+ return POP3_COMMERROR;
+
+ if(!GetResponse(NULL))
+ return POP3_BADPASSWD;
+
+ connected=TRUE;
+
+ return POP3_OK;
+}
+
+
+POP3Message *POP3GetList(void)
+{
+ POP3Message *msg=NULL;
+ DString t;
+ char *p;
+ int no;
+ int f;
+
+ if (!connected)
+ return NULL;
+
+ t=DSInit();
+
+ Send("STAT",(const char *)NULL);
+
+ if (!GetResponse(t))
+ goto end;
+
+ p=strtok(t->text," ");
+
+ if (p)
+ p=strtok(NULL," ");
+
+ if (!p)
+ goto end;
+
+ no=atoi(p);
+
+ msg=Malloc(sizeof *msg * (no+1));
+
+ for(f=0;f<no;f++)
+ {
+ char cmd[64];
+ int done=FALSE;
+
+ msg[f].id=f+1;
+ msg[f].to=NULL;
+ msg[f].from=NULL;
+ msg[f].from_uname=NULL;
+ msg[f].from_domain=NULL;
+ msg[f].subject=NULL;
+ msg[f].content_type=NULL;
+
+ sprintf(cmd,"TOP %d 0",f+1);
+
+ Send(cmd,(const char *)NULL);
+
+ if (!GetResponse(NULL))
+ {
+ free(msg);
+ msg=NULL;
+ goto end;
+ }
+
+ while(!done)
+ {
+ t=DSReset(t);
+
+ if (!GetMultiLine(t))
+ {
+ free(msg);
+ msg=NULL;
+ goto end;
+ }
+
+ if (strcmp(t->text,".")==0)
+ done=TRUE;
+ else
+ {
+ ParseHeader(msg+f,t->text);
+ }
+ }
+
+ if (!msg[f].to)
+ msg[f].to=CopyStr("UNKNOWN");
+
+ if (!msg[f].from)
+ msg[f].from=CopyStr("UNKNOWN");
+
+ if (!msg[f].from_uname)
+ msg[f].from_uname=CopyStr("UNKNOWN");
+
+ if (!msg[f].from_domain)
+ msg[f].from_domain=CopyStr("UNKNOWN");
+
+ if (!msg[f].subject)
+ msg[f].subject=CopyStr("UNKNOWN");
+
+ if (!msg[f].content_type)
+ msg[f].content_type=CopyStr("UNKNOWN");
+ }
+
+ msg[no].id=0;
+ msg[no].to=NULL;
+ msg[no].from=NULL;
+ msg[no].from_uname=NULL;
+ msg[no].from_domain=NULL;
+ msg[no].subject=NULL;
+
+end:
+ DSFree(t);
+ return msg;
+}
+
+
+POP3Status POP3Delete(int msg)
+{
+ return POP3_OK;
+}
+
+
+void POP3Logoff(void)
+{
+ Send("QUIT",(const char *)NULL);
+ GetResponse(NULL);
+}
+
+
+void POP3FreeList(POP3Message *list)
+{
+ if (list)
+ {
+ int f;
+
+ for(f=0;list[f].to;f++)
+ {
+ free(list[f].to);
+ free(list[f].from);
+ free(list[f].from_uname);
+ free(list[f].from_domain);
+ free(list[f].subject);
+ }
+
+ free(list);
+ }
+}
+
+
+/* END OF FILE */