closer...
[citadel.git] / citadel / modules / listsub / serv_listsub.c
index bc00efa00b24ba956231b9f534bc747ac08edcc5..ae41d1746f8b3a639b5564ac1a51dc53273f7d47 100644 (file)
@@ -1,15 +1,15 @@
 /*
  * This module handles self-service subscription/unsubscription to mail lists.
  *
- * Copyright (c) 2002-2012 by the citadel.org team
+ * Copyright (c) 2002-2016 by the citadel.org team
  *
  * This program is open source software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 3.
  *  
- *  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.
+ * 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.
  */
 
 #include "sysdep.h"
@@ -48,7 +48,6 @@
 #include "msgbase.h"
 #include "internet_addressing.h"
 #include "clientsocket.h"
-#include "file_ops.h"
 #include "ctdl_module.h"
 
 /*
 void listsub_generate_token(char *buf) {
        char sourcebuf[SIZ];
        static int seq = 0;
+       size_t len;
 
        /* Theo, please sit down and shut up.  This key doesn't have to be
         * tinfoil-hat secure, it just needs to be reasonably unguessable
         * and unique.
         */
-       sprintf(sourcebuf, "%lx",
+       len = sprintf(sourcebuf, "%lx",
                (long) (++seq + getpid() + time(NULL))
        );
 
        /* Convert it to base64 so it looks cool */     
-       CtdlEncodeBase64(buf, sourcebuf, strlen(sourcebuf), 0);
+       len = CtdlEncodeBase64(buf, sourcebuf, len, 0);
+       if (buf[len - 1] == '\n') {
+               buf[len - 1] = '\0';
+       }
 }
 
 const RoomNetCfg ActiveSubscribers[] = {listrecp, digestrecp};
@@ -79,7 +82,7 @@ int CountThisSubscriber(OneRoomNetCfg *OneRNCfg, StrBuf *email)
        int found_sub = 0;
        int i;
 
-       for (i = 0; i < sizeof (ActiveSubscribers); i++)
+       for (i = 0; i < 2; i++)
        {
                Line = OneRNCfg->NetConfigs[ActiveSubscribers[i]];
                while (Line != NULL)
@@ -97,18 +100,6 @@ int CountThisSubscriber(OneRoomNetCfg *OneRNCfg, StrBuf *email)
 }
 
 /*
-       subpending,
-       unsubpending,
-       ignet_push_share,
-       listrecp,
-       digestrecp,
-       pop3client,
-       rssclient,
-       participate,
-       roommailalias,
-       maxRoomNetCfg
-
-/ *
  * Enter a subscription request
  */
 void do_subscribe(StrBuf **room, StrBuf **email, StrBuf **subtype, StrBuf **webpage) {
@@ -121,6 +112,7 @@ void do_subscribe(StrBuf **room, StrBuf **email, StrBuf **subtype, StrBuf **webp
        const char *RoomMailAddress;
        OneRoomNetCfg *OneRNCfg;
        RoomNetCfgLine *Line;
+       const char *EmailSender = NULL;
        long RoomMailAddressLen;
 
        if (CtdlGetRoom(&qrbuf, ChrPtr(*room)) != 0) {
@@ -142,10 +134,11 @@ void do_subscribe(StrBuf **room, StrBuf **email, StrBuf **subtype, StrBuf **webp
 
        RoomMailAddress = qrbuf.QRname;
        OneRNCfg = CtdlGetNetCfgForRoom(qrbuf.QRnumber);
-       if (OneRNCfg!=NULL) {
+       if (OneRNCfg != NULL) {
                found_sub = CountThisSubscriber(OneRNCfg, *email);
-               if (StrLength(OneRNCfg->Sender) > 0)
-                       RoomMailAddress = ChrPtr(OneRNCfg->Sender);
+               if (StrLength(OneRNCfg->Sender) > 0) {
+                      EmailSender = RoomMailAddress = ChrPtr(OneRNCfg->Sender);
+               }
        }
 
        if (found_sub != 0) {
@@ -154,6 +147,7 @@ void do_subscribe(StrBuf **room, StrBuf **email, StrBuf **subtype, StrBuf **webp
                        ChrPtr(*email),
                        RoomMailAddress);
 
+               FreeRoomNetworkStruct(&OneRNCfg);
                end_critical_section(S_NETCONFIGS);
                return;
        }
@@ -169,7 +163,7 @@ void do_subscribe(StrBuf **room, StrBuf **email, StrBuf **subtype, StrBuf **webp
 
        Line->Value = (StrBuf**) malloc(sizeof(StrBuf*) * 5);
        
-       Line->Value[0] = *email; *email = NULL;
+       Line->Value[0] = NewStrBufDup(*email);
        Line->Value[1] = *subtype; *subtype = NULL;
        Line->Value[2] = NewStrBufPlain(token, -1);
        Line->Value[3] = NewStrBufPlain(NULL, 10);
@@ -277,19 +271,21 @@ void do_subscribe(StrBuf **room, StrBuf **email, StrBuf **subtype, StrBuf **webp
                     "\n"
                     "--__ctdlmultipart__--\n"), 0);
 
+       SaveRoomNetConfigFile(OneRNCfg, qrbuf.QRnumber);
+       FreeRoomNetworkStruct(&OneRNCfg);
        end_critical_section(S_NETCONFIGS);
 
        pcf_req = SmashStrBuf(&cf_req);
        quickie_message(        /* This delivers the message */
                "Citadel",
-               NULL,
+               EmailSender,
                ChrPtr(*email),
                NULL,
                pcf_req,
                FMT_RFC822,
                "Please confirm your list subscription"
                );
-       free(cf_req);
+       free(pcf_req);
        cprintf("%d Subscription entered; confirmation request sent\n", CIT_OK);
 
        FreeStrBuf(&UrlRoom);
@@ -301,6 +297,7 @@ void do_subscribe(StrBuf **room, StrBuf **email, StrBuf **subtype, StrBuf **webp
  */
 void do_unsubscribe(StrBuf **room, StrBuf **email, StrBuf **webpage) {
        struct ctdlroom qrbuf;
+       const char *EmailSender = NULL;
        char token[256];
        char *pcf_req;
        StrBuf *cf_req;
@@ -335,15 +332,12 @@ void do_unsubscribe(StrBuf **room, StrBuf **email, StrBuf **webpage) {
        if (OneRNCfg!=NULL) {
                found_sub = CountThisSubscriber(OneRNCfg, *email);
                if (StrLength(OneRNCfg->Sender) > 0)
-                       RoomMailAddress = ChrPtr(OneRNCfg->Sender);
+                       EmailSender = RoomMailAddress = ChrPtr(OneRNCfg->Sender);
        }
 
        if (found_sub == 0) {
-               cprintf("%d '%s' is not subscribed to '%s'.\n",
-                       ERROR + NO_SUCH_USER,
-                       ChrPtr(*email),
-                       qrbuf.QRname);
-
+               cprintf("%d '%s' is not subscribed to '%s'.\n", ERROR + NO_SUCH_USER, ChrPtr(*email), qrbuf.QRname);
+               FreeRoomNetworkStruct(&OneRNCfg);
                end_critical_section(S_NETCONFIGS);
                return;
        }
@@ -356,14 +350,14 @@ void do_unsubscribe(StrBuf **room, StrBuf **email, StrBuf **webpage) {
        Line = (RoomNetCfgLine*)malloc(sizeof(RoomNetCfgLine));
        memset(Line, 0, sizeof(RoomNetCfgLine));
 
-       Line->Value = (StrBuf**) malloc(sizeof(StrBuf*) * 5);
+       Line->Value = (StrBuf**) malloc(sizeof(StrBuf*) * 4);
        
-       Line->Value[0] = *email; *email = NULL;
-       Line->Value[2] = NewStrBufPlain(token, -1);
-       Line->Value[3] = NewStrBufPlain(NULL, 10);
-       StrBufPrintf(Line->Value[3], "%ld", time(NULL));
-       Line->Value[4] = *webpage; *webpage = NULL;
-       Line->nValues = 5;
+       Line->Value[0] = NewStrBufDup(*email);
+       Line->Value[1] = NewStrBufPlain(token, -1);
+       Line->Value[2] = NewStrBufPlain(NULL, 10);
+       StrBufPrintf(Line->Value[2], "%ld", time(NULL));
+       Line->Value[3] = *webpage; *webpage = NULL;
+       Line->nValues = 4;
 
        AddRoomCfgLine(OneRNCfg, &qrbuf, unsubpending, Line);
 
@@ -398,11 +392,11 @@ void do_unsubscribe(StrBuf **room, StrBuf **email, StrBuf **webpage) {
                HKEY("' mailing list.\n"
                     "\n"
                     "Please go here to confirm this request:\n  "), 0);
-       StrBufAppendBuf(cf_req, Line->Value[4], 0);
+       StrBufAppendBuf(cf_req, Line->Value[3], 0);
        StrBufAppendBufPlain(cf_req, HKEY("?room="), 0);
        StrBufAppendBuf(cf_req, UrlRoom, 0);
        StrBufAppendBufPlain(cf_req, HKEY("&token="), 0);
-       StrBufAppendBuf(cf_req, Line->Value[2], 0);
+       StrBufAppendBuf(cf_req, Line->Value[1], 0);
 
        StrBufAppendBufPlain(
                cf_req,
@@ -434,22 +428,22 @@ void do_unsubscribe(StrBuf **room, StrBuf **email, StrBuf **webpage) {
                HKEY("</B> mailing list.<BR><BR>\n"
                     "Please click here to confirm this request:<BR>\n"
                     "<A HREF=\""), 0);
-       StrBufAppendBuf(cf_req, Line->Value[4], 0);
+       StrBufAppendBuf(cf_req, Line->Value[3], 0);
 
        StrBufAppendBufPlain(cf_req, HKEY("?room="), 0);
        StrBufAppendBuf(cf_req, UrlRoom, 0);
 
        StrBufAppendBufPlain(cf_req, HKEY("&token="), 0);
-       StrBufAppendBuf(cf_req, Line->Value[2], 0);
+       StrBufAppendBuf(cf_req, Line->Value[1], 0);
 
        StrBufAppendBufPlain(cf_req, HKEY("&cmd=confirm\">"), 0);
-       StrBufAppendBuf(cf_req, Line->Value[4], 0);
+       StrBufAppendBuf(cf_req, Line->Value[3], 0);
 
        StrBufAppendBufPlain(cf_req, HKEY("?room="), 0);
        StrBufAppendBuf(cf_req, UrlRoom, 0);
 
        StrBufAppendBufPlain(cf_req, HKEY("&token="), 0);
-       StrBufAppendBuf(cf_req, Line->Value[2], 0);
+       StrBufAppendBuf(cf_req, Line->Value[1], 0);
 
 
        StrBufAppendBufPlain(
@@ -467,12 +461,14 @@ void do_unsubscribe(StrBuf **room, StrBuf **email, StrBuf **webpage) {
                     "\n"
                     "--__ctdlmultipart__--\n"), 0);
 
+       SaveRoomNetConfigFile(OneRNCfg, qrbuf.QRnumber);
+       FreeRoomNetworkStruct(&OneRNCfg);
        end_critical_section(S_NETCONFIGS);
 
        pcf_req = SmashStrBuf(&cf_req);
        quickie_message(        /* This delivers the message */
                "Citadel",
-               NULL,
+               EmailSender,
                ChrPtr(*email),
                NULL,
                pcf_req,
@@ -480,6 +476,8 @@ void do_unsubscribe(StrBuf **room, StrBuf **email, StrBuf **webpage) {
                "Please confirm your unsubscribe request"
        );
 
+       free(pcf_req);
+       FreeStrBuf(&UrlRoom);
        cprintf("%d Unubscription noted; confirmation request sent\n", CIT_OK);
 }
 
@@ -493,10 +491,12 @@ void do_confirm(StrBuf **room, StrBuf **token) {
        struct ctdlroom qrbuf;
        OneRoomNetCfg *OneRNCfg;
        RoomNetCfgLine *Line;
-       RoomNetCfgLine *ConfirmLine;
+       RoomNetCfgLine *ConfirmLine = NULL;
+       RoomNetCfgLine *RemoveLine = NULL;
        RoomNetCfgLine **PrevLine;
        int success = 0;
        RoomNetCfg ConfirmType;
+       const char *errmsg = "";
        int i;
        
        if (CtdlGetRoom(&qrbuf, ChrPtr(*room)) != 0) {
@@ -512,97 +512,134 @@ void do_confirm(StrBuf **room, StrBuf **token) {
                return;
        }
 
+
+       if (StrLength(*token) == 0) {
+               cprintf("%d empty token.\n", ERROR + ILLEGAL_VALUE);
+               return;
+       }
        /*
         * Now start scanning this room's netconfig file for the
         * specified token.
         */
        begin_critical_section(S_NETCONFIGS);
        OneRNCfg = CtdlGetNetCfgForRoom(qrbuf.QRnumber);
-       if (OneRNCfg==NULL) {
-////TODO
-       }
-
 
        ConfirmType = maxRoomNetCfg;
-       for (i = 0; i < sizeof (ConfirmSubscribers); i++)
+       if (OneRNCfg==NULL)
        {
+               errmsg = "no networking config found";
+       }
+       else for (i = 0; i < 2; i++)
+       {
+               int offset;
+
+               if (ConfirmSubscribers[i] == subpending)
+                       offset = 2;
+               else
+                       offset = 1;
                PrevLine = &OneRNCfg->NetConfigs[ConfirmSubscribers[i]];
                Line = *PrevLine;
                while (Line != NULL)
                {
                        if (!strcasecmp(ChrPtr(*token),
-                                       ChrPtr(Line->Value[2])))
+                                       ChrPtr(Line->Value[offset])))
                        {
-                               *PrevLine = Line->next; /* Remove it from the list */
                                ConfirmLine = Line;
+                               *PrevLine = Line->next; /* Remove it from the list */
                                ConfirmType = ConfirmSubscribers[i];
+                               ConfirmLine->next = NULL;
+
                                i += 100; 
                                break;
+
                        }
-                       PrevLine = &Line;
+                       PrevLine = &(*PrevLine)->next;
                        Line = Line->next;
                }
+               if (ConfirmType == maxRoomNetCfg)
+               {
+                       errmsg = "No active un/subscribe request found";
+               }
        }
 
-       if (ConfirmType == subpending) {
-               if (!strcasecmp(ChrPtr(ConfirmLine->Value[2]), 
-                               ("digest")))
+       if (ConfirmType == subpending)
+       {
+               if (CountThisSubscriber(OneRNCfg, ConfirmLine->Value[0]) == 0)
                {
-                       ConfirmType = digestrecp;
+                       if (!strcasecmp(ChrPtr(ConfirmLine->Value[2]), 
+                                       ("digest")))
+                       {
+                               ConfirmType = digestrecp;
+                       }
+                       else /* "list" */
+                       {
+                               ConfirmType = listrecp;
+                       }
+
+                       syslog(LOG_NOTICE, 
+                              "Mailing list: %s subscribed to %s with token %s\n", 
+                              ChrPtr(ConfirmLine->Value[0]), 
+                              qrbuf.QRname,
+                              ChrPtr(*token));
+
+                       FreeStrBuf(&ConfirmLine->Value[1]);
+                       FreeStrBuf(&ConfirmLine->Value[2]);
+                       FreeStrBuf(&ConfirmLine->Value[3]);
+                       FreeStrBuf(&ConfirmLine->Value[4]);
+                       ConfirmLine->nValues = 1;
+               
+                       AddRoomCfgLine(OneRNCfg, &qrbuf, ConfirmType, ConfirmLine);
+                       success = 1;
                }
                else
                {
-                       ConfirmType = listrecp;
+                       /* whipe duplicate subscribe entry... */
+                       errmsg = "already subscribed";
                }
-
-               syslog(LOG_NOTICE, 
-                      "Mailing list: %s subscribed to %s with token %s\n", 
-                      ChrPtr(ConfirmLine->Value[0]), 
-                      qrbuf.QRname,
-                      ChrPtr(*token));
-
-               FreeStrBuf(&ConfirmLine->Value[1]);
-               FreeStrBuf(&ConfirmLine->Value[2]);
-               FreeStrBuf(&ConfirmLine->Value[3]);
-               FreeStrBuf(&ConfirmLine->Value[4]);
-               ConfirmLine->nValues = 5;
-
-               AddRoomCfgLine(OneRNCfg, &qrbuf, ConfirmType, ConfirmLine);
-               success = 1;
        }
-       else if (ConfirmType == unsubpending) {
-               for (i = 0; i < sizeof (ActiveSubscribers); i++)
+       else if (ConfirmType == unsubpending)
+       {
+
+               for (i = 0; i < 2; i++)
                {
                        PrevLine = &OneRNCfg->NetConfigs[ActiveSubscribers[i]];
                        Line = *PrevLine;
                        while (Line != NULL)
                        {
                                if (!strcasecmp(ChrPtr(ConfirmLine->Value[0]),
-                                               ChrPtr(Line->Value[2])))
+                                               ChrPtr(Line->Value[0])))
                                {
+                                       success = 1;
+                                       RemoveLine = Line;
                                        *PrevLine = Line->next; /* Remove it from the list */
-                                       i += 100; 
-                                       break;
+                                       RemoveLine->next = NULL;
+                                       if (RemoveLine != NULL) 
+                                               DeleteGenericCfgLine(NULL/*TODO*/, &RemoveLine);
+                                       Line = *PrevLine;
+                                       continue;
                                }
-                               PrevLine = &Line;
+                               PrevLine = &(*PrevLine)->next;
                                Line = Line->next;
                        }
                }
 
-
-               syslog(LOG_NOTICE, 
-                      "Mailing list: %s unsubscribed to %s with token %s\n", 
-                      ChrPtr(ConfirmLine->Value[0]), 
-                      qrbuf.QRname,
-                      ChrPtr(*token));
-
-
-               if (Line != NULL) DeleteGenericCfgLine(NULL/*TODO*/, &Line);
+               if (success) 
+               {
+                       syslog(LOG_NOTICE, 
+                              "Mailing list: %s unsubscribed to %s with token %s\n", 
+                              ChrPtr(ConfirmLine->Value[0]), 
+                              qrbuf.QRname,
+                              ChrPtr(*token));
+               }
+               else
+               {
+                       errmsg = "no subscriber found for this unsubscription request";
+               }
                DeleteGenericCfgLine(NULL/*TODO*/, &ConfirmLine);
-               AddRoomCfgLine(OneRNCfg, &qrbuf, ConfirmType, NULL);
-               success = 1;
        }
 
+       SaveRoomNetConfigFile(OneRNCfg, qrbuf.QRnumber);
+       FreeRoomNetworkStruct(&OneRNCfg);
        end_critical_section(S_NETCONFIGS);
        
        /*
@@ -612,6 +649,8 @@ void do_confirm(StrBuf **room, StrBuf **token) {
                cprintf("%d %d operation(s) confirmed.\n", CIT_OK, success);
        }
        else {
+               syslog(LOG_NOTICE, "failed processing (un)subscribe request: %s",
+                      errmsg);
                cprintf("%d Invalid token.\n", ERROR + ILLEGAL_VALUE);
        }
 
@@ -634,6 +673,7 @@ void cmd_subs(char *cmdbuf)
        {
                Segments[i] = NewStrBufPlain(NULL, StrLength(Segments[0]));
                StrBufExtract_NextToken(Segments[i], Segments[0], &Pos, '|');
+               i++;
        }
 
        if (!strcasecmp(ChrPtr(Segments[1]), "subscribe")) {
@@ -655,6 +695,11 @@ void cmd_subs(char *cmdbuf)
        else {
                cprintf("%d Invalid command\n", ERROR + ILLEGAL_VALUE);
        }
+
+       for (; i>=0; i--)
+       {
+               FreeStrBuf(&Segments[i]);
+       }
 }