X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=citadel%2Fmodules%2Fpop3client%2Fserv_pop3client.c;h=c7576146d70241effcb7757f571388cde1798d2e;hb=8c47559cb5ae97ec0fa35660ee16fd61a9451c72;hp=8421d175def5aca2c2591538518006a3ada9b2a9;hpb=bb1031f933fcc7d60358028f0f3e1bdf8ba7aa8f;p=citadel.git diff --git a/citadel/modules/pop3client/serv_pop3client.c b/citadel/modules/pop3client/serv_pop3client.c index 8421d175d..c7576146d 100644 --- a/citadel/modules/pop3client/serv_pop3client.c +++ b/citadel/modules/pop3client/serv_pop3client.c @@ -3,6 +3,21 @@ * * Consolidate mail from remote POP3 accounts. * + * Copyright (c) 2007-2009 by the citadel.org team + * + * 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 3 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 */ #include @@ -25,17 +40,18 @@ #include #include #include +#include #include "citadel.h" #include "server.h" #include "citserver.h" #include "support.h" #include "config.h" -#include "tools.h" #include "room_ops.h" #include "ctdl_module.h" #include "clientsocket.h" #include "msgbase.h" #include "internet_addressing.h" +#include "database.h" #include "citadel_dirs.h" struct pop3aggr { @@ -44,16 +60,14 @@ struct pop3aggr { char pop3host[128]; char pop3user[128]; char pop3pass[128]; -}; - -struct uidl { - struct uidl *next; - char uidl[64]; + int keep; + time_t interval; }; struct pop3aggr *palist = NULL; -void pop3_do_fetching(char *roomname, char *pop3host, char *pop3user, char *pop3pass, int delete_from_server) + +void pop3_do_fetching(char *roomname, char *pop3host, char *pop3user, char *pop3pass, int keep) { int sock; char buf[SIZ]; @@ -66,55 +80,78 @@ void pop3_do_fetching(char *roomname, char *pop3host, char *pop3user, char *pop3 struct CtdlMessage *msg = NULL; long msgnum = 0; char this_uidl[64]; - struct uidl *new_uidl_map = NULL; - struct uidl *uptr; + char utmsgid[SIZ]; + struct cdbdata *cdbut; + struct UseTable ut; - lprintf(CTDL_DEBUG, "POP3: %s %s %s \n", roomname, pop3host, pop3user); - lprintf(CTDL_NOTICE, "Connecting to <%s>\n", pop3host); + CtdlLogPrintf(CTDL_DEBUG, "POP3: %s %s %s \n", roomname, pop3host, pop3user); + CtdlLogPrintf(CTDL_NOTICE, "Connecting to <%s>\n", pop3host); + + if (CtdlThreadCheckStop()) + return; + sock = sock_connect(pop3host, "110", "tcp"); if (sock < 0) { - lprintf(CTDL_ERR, "Could not connect: %s\n", strerror(errno)); + CtdlLogPrintf(CTDL_ERR, "Could not connect: %s\n", strerror(errno)); return; } - lprintf(CTDL_DEBUG, "Connected!\n"); + if (CtdlThreadCheckStop()) + goto bail; + + CtdlLogPrintf(CTDL_DEBUG, "Connected!\n"); /* Read the server greeting */ if (sock_getln(sock, buf, sizeof buf) < 0) goto bail; - lprintf(CTDL_DEBUG, ">%s\n", buf); + CtdlLogPrintf(CTDL_DEBUG, ">%s\n", buf); if (strncasecmp(buf, "+OK", 3)) goto bail; + if (CtdlThreadCheckStop()) + goto bail; + /* Identify ourselves. NOTE: we have to append a CR to each command. The LF will * automatically be appended by sock_puts(). Believe it or not, leaving out the CR * will cause problems if the server happens to be Exchange, which is so b0rken it * actually barfs on LF-terminated newlines. */ snprintf(buf, sizeof buf, "USER %s\r", pop3user); - lprintf(CTDL_DEBUG, "<%s\n", buf); + CtdlLogPrintf(CTDL_DEBUG, "<%s\n", buf); if (sock_puts(sock, buf) <0) goto bail; if (sock_getln(sock, buf, sizeof buf) < 0) goto bail; - lprintf(CTDL_DEBUG, ">%s\n", buf); + CtdlLogPrintf(CTDL_DEBUG, ">%s\n", buf); if (strncasecmp(buf, "+OK", 3)) goto bail; + if (CtdlThreadCheckStop()) + goto bail; + /* Password */ snprintf(buf, sizeof buf, "PASS %s\r", pop3pass); - lprintf(CTDL_DEBUG, "\n"); + CtdlLogPrintf(CTDL_DEBUG, "\n"); if (sock_puts(sock, buf) <0) goto bail; if (sock_getln(sock, buf, sizeof buf) < 0) goto bail; - lprintf(CTDL_DEBUG, ">%s\n", buf); + CtdlLogPrintf(CTDL_DEBUG, ">%s\n", buf); if (strncasecmp(buf, "+OK", 3)) goto bail; + if (CtdlThreadCheckStop()) + goto bail; + /* Get the list of messages */ snprintf(buf, sizeof buf, "LIST\r"); - lprintf(CTDL_DEBUG, "<%s\n", buf); + CtdlLogPrintf(CTDL_DEBUG, "<%s\n", buf); if (sock_puts(sock, buf) <0) goto bail; if (sock_getln(sock, buf, sizeof buf) < 0) goto bail; - lprintf(CTDL_DEBUG, ">%s\n", buf); + CtdlLogPrintf(CTDL_DEBUG, ">%s\n", buf); if (strncasecmp(buf, "+OK", 3)) goto bail; + if (CtdlThreadCheckStop()) + goto bail; + do { + if (CtdlThreadCheckStop()) + goto bail; + if (sock_getln(sock, buf, sizeof buf) < 0) goto bail; - lprintf(CTDL_DEBUG, ">%s\n", buf); + CtdlLogPrintf(CTDL_DEBUG, ">%s\n", buf); msg_to_fetch = atoi(buf); if (msg_to_fetch > 0) { if (alloc_msgs == 0) { @@ -134,66 +171,80 @@ void pop3_do_fetching(char *roomname, char *pop3host, char *pop3user, char *pop3 /* Find out the UIDL of the message, to determine whether we've already downloaded it */ snprintf(buf, sizeof buf, "UIDL %d\r", msglist[i]); - lprintf(CTDL_DEBUG, "<%s\n", buf); + CtdlLogPrintf(CTDL_DEBUG, "<%s\n", buf); if (sock_puts(sock, buf) <0) goto bail; if (sock_getln(sock, buf, sizeof buf) < 0) goto bail; - lprintf(CTDL_DEBUG, ">%s\n", buf); + CtdlLogPrintf(CTDL_DEBUG, ">%s\n", buf); if (strncasecmp(buf, "+OK", 3)) goto bail; - extract_token(this_uidl, buf, 3, ' ', sizeof this_uidl); + extract_token(this_uidl, buf, 2, ' ', sizeof this_uidl); - uptr = (struct uidl *) malloc(sizeof(struct uidl)); - if (uptr != NULL) { - safestrncpy(uptr->uidl, this_uidl, sizeof uptr->uidl); - uptr->next = new_uidl_map; - new_uidl_map = uptr; - } + snprintf(utmsgid, sizeof utmsgid, "pop3/%s/%s@%s", roomname, this_uidl, pop3host); - /* Tell the server to fetch the message */ - snprintf(buf, sizeof buf, "RETR %d\r", msglist[i]); - lprintf(CTDL_DEBUG, "<%s\n", buf); - if (sock_puts(sock, buf) <0) goto bail; - if (sock_getln(sock, buf, sizeof buf) < 0) goto bail; - lprintf(CTDL_DEBUG, ">%s\n", buf); - if (strncasecmp(buf, "+OK", 3)) goto bail; + if (CtdlThreadCheckStop()) + goto bail; + + cdbut = cdb_fetch(CDB_USETABLE, utmsgid, strlen(utmsgid)); + if (cdbut != NULL) { + /* message has already been seen */ + CtdlLogPrintf(CTDL_DEBUG, "%s has already been seen\n", utmsgid); + cdb_free(cdbut); + + /* rewrite the record anyway, to update the timestamp */ + strcpy(ut.ut_msgid, utmsgid); + ut.ut_timestamp = time(NULL); + cdb_store(CDB_USETABLE, utmsgid, strlen(utmsgid), &ut, sizeof(struct UseTable) ); + } + else { + /* Message has not been seen. Tell the server to fetch the message... */ + snprintf(buf, sizeof buf, "RETR %d\r", msglist[i]); + CtdlLogPrintf(CTDL_DEBUG, "<%s\n", buf); + if (sock_puts(sock, buf) <0) goto bail; + if (sock_getln(sock, buf, sizeof buf) < 0) goto bail; + CtdlLogPrintf(CTDL_DEBUG, ">%s\n", buf); + if (strncasecmp(buf, "+OK", 3)) goto bail; + + if (CtdlThreadCheckStop()) + goto bail; - /* If we get to this point, the message is on its way. Read it. */ - body = CtdlReadMessageBody(".", config.c_maxmsglen, NULL, 1, sock); - if (body == NULL) goto bail; - - lprintf(CTDL_DEBUG, "Converting message...\n"); - msg = convert_internet_message(body); - body = NULL; /* yes, this should be dereferenced, NOT freed */ - - /* Do Something With It (tm) */ - msgnum = CtdlSubmitMsg(msg, NULL, roomname); - if (msgnum > 0L) { - /* Message has been committed to the store */ - - if (delete_from_server) { - snprintf(buf, sizeof buf, "DELE %d\r", msglist[i]); - lprintf(CTDL_DEBUG, "<%s\n", buf); - if (sock_puts(sock, buf) <0) goto bail; - if (sock_getln(sock, buf, sizeof buf) < 0) goto bail; - lprintf(CTDL_DEBUG, ">%s\n", buf); /* errors here are non-fatal */ + /* If we get to this point, the message is on its way. Read it. */ + body = CtdlReadMessageBody(".", config.c_maxmsglen, NULL, 1, sock); + if (body == NULL) goto bail; + + CtdlLogPrintf(CTDL_DEBUG, "Converting message...\n"); + msg = convert_internet_message(body); + body = NULL; /* yes, this should be dereferenced, NOT freed */ + + /* Do Something With It (tm) */ + msgnum = CtdlSubmitMsg(msg, NULL, roomname, 0); + if (msgnum > 0L) { + /* Message has been committed to the store */ + + if (!keep) { + snprintf(buf, sizeof buf, "DELE %d\r", msglist[i]); + CtdlLogPrintf(CTDL_DEBUG, "<%s\n", buf); + if (sock_puts(sock, buf) <0) goto bail; + if (sock_getln(sock, buf, sizeof buf) < 0) goto bail; + CtdlLogPrintf(CTDL_DEBUG, ">%s\n", buf); /* errors here are non-fatal */ + } + + /* write the uidl to the use table so we don't fetch this message again */ + strcpy(ut.ut_msgid, utmsgid); + ut.ut_timestamp = time(NULL); + cdb_store(CDB_USETABLE, utmsgid, strlen(utmsgid), + &ut, sizeof(struct UseTable) ); } + CtdlFreeMessage(msg); } - CtdlFreeMessage(msg); } /* Log out */ snprintf(buf, sizeof buf, "QUIT\r"); - lprintf(CTDL_DEBUG, "<%s\n", buf); + CtdlLogPrintf(CTDL_DEBUG, "<%s\n", buf); if (sock_puts(sock, buf) <0) goto bail; if (sock_getln(sock, buf, sizeof buf) < 0) goto bail; - lprintf(CTDL_DEBUG, ">%s\n", buf); + CtdlLogPrintf(CTDL_DEBUG, ">%s\n", buf); bail: sock_close(sock); if (msglist) free(msglist); - - while (new_uidl_map != NULL) { - uptr = new_uidl_map->next; - free(new_uidl_map); - new_uidl_map = uptr; - } } @@ -208,6 +259,9 @@ void pop3client_scan_room(struct ctdlroom *qrbuf, void *data) FILE *fp; struct pop3aggr *pptr; + if (CtdlThreadCheckStop()) + return; + assoc_file_name(filename, sizeof filename, qrbuf, ctdl_netcfg_dir); /* Only do net processing for rooms that have netconfigs */ @@ -227,6 +281,8 @@ void pop3client_scan_room(struct ctdlroom *qrbuf, void *data) extract_token(pptr->pop3host, buf, 1, '|', sizeof pptr->pop3host); extract_token(pptr->pop3user, buf, 2, '|', sizeof pptr->pop3user); extract_token(pptr->pop3pass, buf, 3, '|', sizeof pptr->pop3pass); + pptr->keep = extract_int(buf, 4); + pptr->interval = extract_long(buf, 5); pptr->next = palist; palist = pptr; } @@ -243,11 +299,17 @@ void pop3client_scan(void) { static time_t last_run = 0L; static int doing_pop3client = 0; struct pop3aggr *pptr; + time_t fastest_scan; + + if (config.c_pop3_fastest < config.c_pop3_fetch) + fastest_scan = config.c_pop3_fastest; + else + fastest_scan = config.c_pop3_fetch; /* * Run POP3 aggregation no more frequently than once every n seconds */ - if ( (time(NULL) - last_run) < config.c_net_freq ) { + if ( (time(NULL) - last_run) < fastest_scan ) { return; } @@ -260,18 +322,20 @@ void pop3client_scan(void) { if (doing_pop3client) return; doing_pop3client = 1; - lprintf(CTDL_DEBUG, "pop3client started\n"); + CtdlLogPrintf(CTDL_DEBUG, "pop3client started\n"); ForEachRoom(pop3client_scan_room, NULL); - while (palist != NULL) { - /* FIXME set delete_from_server to 1 if the user wants to */ - pop3_do_fetching(palist->roomname, palist->pop3host, palist->pop3user, palist->pop3pass, 0); + while (palist != NULL && !CtdlThreadCheckStop()) { + if ((palist->interval && time(NULL) > (last_run + palist->interval)) + || (time(NULL) > last_run + config.c_pop3_fetch)) + pop3_do_fetching(palist->roomname, palist->pop3host, + palist->pop3user, palist->pop3pass, palist->keep); pptr = palist; palist = palist->next; free(pptr); } - lprintf(CTDL_DEBUG, "pop3client ended\n"); + CtdlLogPrintf(CTDL_DEBUG, "pop3client ended\n"); last_run = time(NULL); doing_pop3client = 0; } @@ -279,8 +343,11 @@ void pop3client_scan(void) { CTDL_MODULE_INIT(pop3client) { - CtdlRegisterSessionHook(pop3client_scan, EVT_TIMER); - + if (!threading) + { + CtdlRegisterSessionHook(pop3client_scan, EVT_TIMER); + } + /* return our Subversion id for the Log */ return "$Id$"; }