"Fossies" - the Fresh Open Source Software Archive

Member "citadel/modules/pop3client/serv_pop3client.c" (5 Jun 2021, 7486 Bytes) of package /linux/www/citadel.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "serv_pop3client.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 9.01_vs_902.

    1 /*
    2  * Consolidate mail from remote POP3 accounts.
    3  *
    4  * Copyright (c) 2007-2021 by the citadel.org team
    5  *
    6  * This program is open source software; you can redistribute it and/or
    7  * modify it under the terms of the GNU General Public License as published
    8  * by the Free Software Foundation; either version 3 of the License, or
    9  * (at your option) any later version.
   10  *
   11  * This program is distributed in the hope that it will be useful,
   12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   14  * GNU General Public License for more details.
   15  */
   16 
   17 #include <stdlib.h>
   18 #include <unistd.h>
   19 #include <stdio.h>
   20 #include <sysconfig.h>
   21 #include <time.h>
   22 #include <ctype.h>
   23 #include <string.h>
   24 #include <errno.h>
   25 #include <sys/types.h>
   26 #include <sys/stat.h>
   27 #include <libcitadel.h>
   28 #include <curl/curl.h>
   29 #include "citadel.h"
   30 #include "server.h"
   31 #include "citserver.h"
   32 #include "support.h"
   33 #include "config.h"
   34 #include "ctdl_module.h"
   35 #include "clientsocket.h"
   36 #include "msgbase.h"
   37 #include "internet_addressing.h"
   38 #include "database.h"
   39 #include "citadel_dirs.h"
   40 
   41 struct p3cq {               // module-local queue of pop3 client work that needs processing
   42     struct p3cq *next;
   43     char *room;
   44     char *host;
   45     char *user;
   46     char *pass;
   47     int keep;
   48     long interval;
   49 };
   50 
   51 static int doing_pop3client = 0;
   52 struct p3cq *p3cq = NULL;
   53 
   54 /*
   55  * Process one mailbox.
   56  */
   57 void pop3client_one_mailbox(char *room, const char *host, const char *user, const char *pass, int keep, long interval) {
   58     syslog(LOG_DEBUG, "pop3client: room=<%s> host=<%s> user=<%s> keep=<%d> interval=<%ld>", room, host, user, keep, interval);
   59 
   60     char url[SIZ];
   61     CURL *curl;
   62     CURLcode res = CURLE_OK;
   63     StrBuf *Uidls = NULL;
   64     int i;
   65     char cmd[1024];
   66 
   67     curl = curl_easy_init();
   68     if (!curl) {
   69         return;
   70     }
   71 
   72     Uidls = NewStrBuf();
   73 
   74     curl_easy_setopt(curl, CURLOPT_USERNAME, user);
   75     curl_easy_setopt(curl, CURLOPT_PASSWORD, pass);
   76     curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
   77     curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
   78     curl_easy_setopt(curl, CURLOPT_TIMEOUT, 15);
   79     curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlFillStrBuf_callback); // What to do with downloaded data
   80     curl_easy_setopt(curl, CURLOPT_WRITEDATA, Uidls);           // Give it our StrBuf to work with
   81     curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "UIDL");
   82 
   83     /* Try POP3S (SSL encrypted) first */
   84     snprintf(url, sizeof url, "pop3s://%s", host);
   85     curl_easy_setopt(curl, CURLOPT_URL, url);
   86     res = curl_easy_perform(curl);
   87     if (res == CURLE_OK) {
   88     }
   89     else {
   90         syslog(LOG_DEBUG, "pop3client: POP3S connection failed: %s , trying POP3 next", curl_easy_strerror(res));
   91         snprintf(url, sizeof url, "pop3://%s", host);           // try unencrypted next
   92         curl_easy_setopt(curl, CURLOPT_URL, url);
   93         FlushStrBuf(Uidls);
   94         res = curl_easy_perform(curl);
   95     }
   96 
   97     if (res != CURLE_OK) {
   98         syslog(LOG_DEBUG, "pop3client: POP3 connection failed: %s", curl_easy_strerror(res));
   99         curl_easy_cleanup(curl);
  100         FreeStrBuf(&Uidls);
  101         return;
  102     }
  103 
  104     // If we got this far, a connection was established, we know whether it's pop3s or pop3, and UIDL is supported.
  105     // Now go through the UIDL list and look for messages.
  106 
  107     int num_msgs = num_tokens(ChrPtr(Uidls), '\n');
  108     syslog(LOG_DEBUG, "pop3client: there are %d messages", num_msgs);
  109     for (i=0; i<num_msgs; ++i) {
  110         char oneuidl[1024];
  111         extract_token(oneuidl, ChrPtr(Uidls), i, '\n', sizeof oneuidl);
  112         if (strlen(oneuidl) > 2) {
  113             if (oneuidl[strlen(oneuidl)-1] == '\r') {
  114                 oneuidl[strlen(oneuidl)-1] = 0;
  115             }
  116             int this_msg = atoi(oneuidl);
  117             char *c = strchr(oneuidl, ' ');
  118             if (c) strcpy(oneuidl, ++c);
  119 
  120             // Make up the Use Table record so we can check if we've already seen this message.
  121             StrBuf *UT = NewStrBuf();
  122             StrBufPrintf(UT, "pop3/%s/%s:%s@%s", room, oneuidl, user, host);
  123             int already_seen = CheckIfAlreadySeen(UT);
  124             FreeStrBuf(&UT);
  125 
  126             // Only fetch the message if we haven't seen it before.
  127             if (already_seen == 0) {
  128                 StrBuf *TheMsg = NewStrBuf();
  129                 snprintf(cmd, sizeof cmd, "RETR %d", this_msg);
  130                 curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, cmd);
  131                 curl_easy_setopt(curl, CURLOPT_WRITEDATA, TheMsg);
  132                 res = curl_easy_perform(curl);
  133                 if (res == CURLE_OK) {
  134                     struct CtdlMessage *msg = convert_internet_message_buf(&TheMsg);
  135                     CtdlSubmitMsg(msg, NULL, room);
  136                     CM_Free(msg);
  137                 }
  138                 else {
  139                     FreeStrBuf(&TheMsg);
  140                 }
  141 
  142                 // Unless the configuration says to keep the message on the server, delete it.
  143                 if (keep == 0) {
  144                     snprintf(cmd, sizeof cmd, "DELE %d", this_msg);
  145                     curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, cmd);
  146                     res = curl_easy_perform(curl);
  147                 }
  148             }
  149             else {
  150                 syslog(LOG_DEBUG, "pop3client: %s has already been retrieved", oneuidl);
  151             }
  152         }
  153     }
  154 
  155     curl_easy_cleanup(curl);
  156     FreeStrBuf(&Uidls);
  157     return;
  158 }
  159 
  160 
  161 // Scan a room's netconfig looking for RSS feed parsing requests
  162 //
  163 void pop3client_scan_room(struct ctdlroom *qrbuf, void *data)
  164 {
  165     char *serialized_config = NULL;
  166     int num_configs = 0;
  167     char cfgline[SIZ];
  168     char cfgelement[SIZ];
  169     int i = 0;
  170 
  171         serialized_config = LoadRoomNetConfigFile(qrbuf->QRnumber);
  172         if (!serialized_config) {
  173         return;
  174     }
  175 
  176     num_configs = num_tokens(serialized_config, '\n');
  177     for (i=0; i<num_configs; ++i) {
  178         extract_token(cfgline, serialized_config, i, '\n', sizeof cfgline);
  179         if (!strncasecmp(cfgline, HKEY("pop3client|"))) {
  180             struct p3cq *pptr = malloc(sizeof(struct p3cq));
  181             pptr->next = p3cq;
  182             p3cq = pptr;
  183             p3cq->room = strdup(qrbuf->QRname);
  184             extract_token(cfgelement, cfgline, 1, '|', sizeof cfgelement);
  185             p3cq->host = strdup(cfgelement);
  186             extract_token(cfgelement, cfgline, 2, '|', sizeof cfgelement);
  187             p3cq->user = strdup(cfgelement);
  188             extract_token(cfgelement, cfgline, 3, '|', sizeof cfgelement);
  189             p3cq->pass = strdup(cfgelement);
  190             p3cq->keep = extract_int(cfgline, 4);
  191             p3cq->interval = extract_long(cfgline, 5);
  192         }
  193     }
  194 
  195     free(serialized_config);
  196 }
  197 
  198 
  199 void pop3client_scan(void) {
  200     static time_t last_run = 0L;
  201     time_t fastest_scan;
  202     struct p3cq *pptr = NULL;
  203 
  204     if (CtdlGetConfigLong("c_pop3_fastest") < CtdlGetConfigLong("c_pop3_fetch")) {
  205         fastest_scan = CtdlGetConfigLong("c_pop3_fastest");
  206     }
  207     else {
  208         fastest_scan = CtdlGetConfigLong("c_pop3_fetch");
  209     }
  210 
  211     /*
  212      * Run POP3 aggregation no more frequently than once every n seconds
  213      */
  214     if ( (time(NULL) - last_run) < fastest_scan ) {
  215         return;
  216     }
  217 
  218     /*
  219      * This is a simple concurrency check to make sure only one pop3client
  220      * run is done at a time.  We could do this with a mutex, but since we
  221      * don't really require extremely fine granularity here, we'll do it
  222      * with a static variable instead.
  223      */
  224     if (doing_pop3client) return;
  225     doing_pop3client = 1;
  226 
  227     syslog(LOG_DEBUG, "pop3client: scan started");
  228     CtdlForEachRoom(pop3client_scan_room, NULL);
  229 
  230     /*
  231      * We have to queue and process in separate phases, otherwise we leave a cursor open
  232      */
  233     syslog(LOG_DEBUG, "pop3client: processing started");
  234     while (p3cq != NULL) {
  235         pptr = p3cq;
  236         p3cq = p3cq->next;
  237 
  238         pop3client_one_mailbox(pptr->room, pptr->host, pptr->user, pptr->pass, pptr->keep, pptr->interval);
  239 
  240         free(pptr->room);
  241         free(pptr->host);
  242         free(pptr->user);
  243         free(pptr->pass);
  244         free(pptr);
  245     }
  246 
  247     syslog(LOG_DEBUG, "pop3client: ended");
  248     last_run = time(NULL);
  249     doing_pop3client = 0;
  250 }
  251 
  252 
  253 CTDL_MODULE_INIT(pop3client)
  254 {
  255     if (!threading)
  256     {
  257         CtdlRegisterSessionHook(pop3client_scan, EVT_TIMER, PRIO_AGGR + 50);
  258     }
  259 
  260     /* return our module id for the log */
  261     return "pop3client";
  262 }