X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=citadel%2Fmodules%2Fpop3client%2Fserv_pop3client.c;h=c7576146d70241effcb7757f571388cde1798d2e;hb=8c47559cb5ae97ec0fa35660ee16fd61a9451c72;hp=449dcc95e190a33c43de4704d574c69fe3433da5;hpb=e024165eb98df86eb314c5ddea3cb38fcf478e67;p=citadel.git diff --git a/citadel/modules/pop3client/serv_pop3client.c b/citadel/modules/pop3client/serv_pop3client.c index 449dcc95e..c7576146d 100644 --- a/citadel/modules/pop3client/serv_pop3client.c +++ b/citadel/modules/pop3client/serv_pop3client.c @@ -1,5 +1,23 @@ /* - * Aggregate remote POP3 accounts + * $Id$ + * + * 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 @@ -20,17 +38,21 @@ #include #include #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 { struct pop3aggr *next; @@ -38,14 +60,14 @@ struct pop3aggr { char pop3host[128]; char pop3user[128]; char pop3pass[128]; + int keep; + time_t interval; }; struct pop3aggr *palist = NULL; -#ifdef POP3_AGGREGATION - -void pop3_do_fetching(char *roomname, char *pop3host, char *pop3user, char *pop3pass) +void pop3_do_fetching(char *roomname, char *pop3host, char *pop3user, char *pop3pass, int keep) { int sock; char buf[SIZ]; @@ -57,49 +79,79 @@ void pop3_do_fetching(char *roomname, char *pop3host, char *pop3user, char *pop3 char *body = NULL; struct CtdlMessage *msg = NULL; long msgnum = 0; + char this_uidl[64]; + char utmsgid[SIZ]; + struct cdbdata *cdbut; + struct UseTable ut; - lprintf(CTDL_DEBUG, "POP3: %s %s %s %s\n", roomname, pop3host, pop3user, pop3pass); - 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; - /* Identify ourselves */ - snprintf(buf, sizeof buf, "USER %s", pop3user); - lprintf(CTDL_DEBUG, "<%s\n", buf); + 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); + 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", pop3pass); - lprintf(CTDL_DEBUG, "<%s\n", buf); + snprintf(buf, sizeof buf, "PASS %s\r", pop3pass); + 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"); - lprintf(CTDL_DEBUG, "<%s\n", buf); + snprintf(buf, sizeof buf, "LIST\r"); + 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) { @@ -117,42 +169,80 @@ void pop3_do_fetching(char *roomname, char *pop3host, char *pop3user, char *pop3 if (num_msgs) for (i=0; i%s\n", buf); + CtdlLogPrintf(CTDL_DEBUG, ">%s\n", buf); if (strncasecmp(buf, "+OK", 3)) goto bail; + extract_token(this_uidl, buf, 2, ' ', sizeof this_uidl); - /* 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; + snprintf(utmsgid, sizeof utmsgid, "pop3/%s/%s@%s", roomname, this_uidl, pop3host); - lprintf(CTDL_DEBUG, "Converting message...\n"); - msg = convert_internet_message(body); - body = NULL; /* yes, this should be dereferenced, NOT freed */ + if (CtdlThreadCheckStop()) + goto bail; - /* Do Something With It (tm) */ - msgnum = CtdlSubmitMsg(msg, NULL, roomname); - if (msgnum > 0L) { - /* Message has been committed to the store, so delete it from the remote server */ - snprintf(buf, sizeof buf, "DELE %d", msglist[i]); - lprintf(CTDL_DEBUG, "<%s\n", buf); + 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; - lprintf(CTDL_DEBUG, ">%s\n", buf); + 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; + + 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"); - lprintf(CTDL_DEBUG, "<%s\n", buf); + snprintf(buf, sizeof buf, "QUIT\r"); + 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); } @@ -169,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 */ @@ -188,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; } @@ -204,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; } @@ -221,29 +322,32 @@ 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) { - pop3_do_fetching(palist->roomname, palist->pop3host, palist->pop3user, palist->pop3pass); + 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; } -#endif CTDL_MODULE_INIT(pop3client) { -#ifdef POP3_AGGREGATION - CtdlRegisterSessionHook(pop3client_scan, EVT_TIMER); -#endif - + if (!threading) + { + CtdlRegisterSessionHook(pop3client_scan, EVT_TIMER); + } + /* return our Subversion id for the Log */ - return "$Id: $"; + return "$Id$"; }