/* 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 #include "global.h" #include "pop3.h" #include "dstring.h" #include "util.h" static const char header_id[]=KBS_POP3_H; static const char message_id[]=KBS_MSG_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 #define HDR_DEBUG 4 /* ---------------------------------------- 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[0]=='+'; else flag=FALSE; if (ret) DSAddDS(ret,t); DSFree(t); return flag; } static int IsHeader(const DString line) { const char *p; p=line->text; while(*p && !isspace(*p)) { if (*p==':') return TRUE; p++; } return FALSE; } static int GetMultiLine(DString ret) { int done=FALSE; int flag=TRUE; while (!done) { if (GetLine(ret)) { if (IsHeader(ret)) { int ch; if ((ch=GetChar())!=-1) { if (ch!=' ' && ch!='\t') done=TRUE; UnGetChar(ch); } else { flag=FALSE; done=TRUE; } } else done=TRUE; } else { flag=FALSE; done=TRUE; } } 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}, /* {"Received: ", HDR_DEBUG}, */ {NULL, HDR_UNKNOWN} }; const char *name; 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) { name=field[f].text; 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; case HDR_DEBUG: printf("%s = '%s'\n",name,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) { char buff[256]; sprintf(buff,"DELE %d",msg); Send(buff,(const char *)NULL); if (GetResponse(NULL)) return POP3_OK; else return POP3_BADDELETE; } 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 */