/* 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 #include #include #include #include #include #include #include #include #include #include #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(senttext); 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;ftext,".")==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 */