c719615fbc986ce021751ed04785e3cd8ee66907
[citadel.git] / citadel / modules / listsub / serv_listsub.c
1 /*
2  * This module handles self-service subscription/unsubscription to mail lists.
3  *
4  * Copyright (c) 2002-2016 by the citadel.org team
5  *
6  * This program is open source software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 3.
8  *  
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  */
14
15 #include "sysdep.h"
16 #include <stdlib.h>
17 #include <unistd.h>
18 #include <stdio.h>
19 #include <fcntl.h>
20 #include <ctype.h>
21 #include <signal.h>
22 #include <pwd.h>
23 #include <errno.h>
24 #include <sys/types.h>
25 #include <dirent.h>
26 #if TIME_WITH_SYS_TIME
27 # include <sys/time.h>
28 # include <time.h>
29 #else
30 # if HAVE_SYS_TIME_H
31 #  include <sys/time.h>
32 # else
33 #  include <time.h>
34 # endif
35 #endif
36
37 #include <sys/wait.h>
38 #include <string.h>
39 #include <limits.h>
40 #include <libcitadel.h>
41 #include "citadel.h"
42 #include "server.h"
43 #include "citserver.h"
44 #include "support.h"
45 #include "config.h"
46 #include "user_ops.h"
47 #include "database.h"
48 #include "msgbase.h"
49 #include "internet_addressing.h"
50 #include "clientsocket.h"
51 #include "ctdl_module.h"
52
53 /*
54  * Generate a randomizationalisticized token to use for authentication of
55  * a subscribe or unsubscribe request.
56  */
57 void listsub_generate_token(char *buf) {
58         char sourcebuf[SIZ];
59         static int seq = 0;
60         size_t len;
61
62         /* Theo, please sit down and shut up.  This key doesn't have to be
63          * tinfoil-hat secure, it just needs to be reasonably unguessable
64          * and unique.
65          */
66         len = sprintf(sourcebuf, "%lx", (long) (++seq + getpid() + time(NULL)));
67
68         /* Convert it to base64 so it looks cool */     
69         len = CtdlEncodeBase64(buf, sourcebuf, len, 0);
70         if (buf[len - 1] == '\n') {
71                 buf[len - 1] = '\0';
72         }
73 }
74
75
76 const RoomNetCfg ActiveSubscribers[] = {listrecp, digestrecp};
77
78 int CountThisSubscriber(OneRoomNetCfg *OneRNCfg, StrBuf *email)
79 {
80         RoomNetCfgLine *Line;
81         int found_sub = 0;
82         int i;
83
84         for (i = 0; i < 2; i++)
85         {
86                 Line = OneRNCfg->NetConfigs[ActiveSubscribers[i]];
87                 while (Line != NULL)
88                 {
89                         if (!strcmp(ChrPtr(email),
90                                     ChrPtr(Line->Value[0])))
91                         {
92                                 ++found_sub;
93                                 break;                                  
94                         }
95                         Line = Line->next;
96                 }
97         }
98         return found_sub;
99 }
100
101 /*
102  * Enter a subscription request
103  */
104 void do_subscribe(StrBuf **room, StrBuf **email, StrBuf **subtype, StrBuf **webpage) {
105         struct ctdlroom qrbuf;
106         char token[256];
107         char *pcf_req;
108         StrBuf *cf_req;
109         StrBuf *UrlRoom;
110         int found_sub = 0;
111         const char *RoomMailAddress;
112         OneRoomNetCfg *OneRNCfg;
113         RoomNetCfgLine *Line;
114         const char *EmailSender = NULL;
115         long RoomMailAddressLen;
116
117         if (CtdlGetRoom(&qrbuf, ChrPtr(*room)) != 0) {
118                 cprintf("%d There is no list called '%s'\n", ERROR + ROOM_NOT_FOUND, ChrPtr(*room));
119                 return;
120         }
121
122         if ((qrbuf.QRflags2 & QR2_SELFLIST) == 0) {
123                 cprintf("%d '%s' "
124                         "does not accept subscribe/unsubscribe requests.\n",
125                         ERROR + HIGHER_ACCESS_REQUIRED, qrbuf.QRname);
126                 return;
127         }
128
129         /* 
130          * Make sure the requested address isn't already subscribed
131          */
132         begin_critical_section(S_NETCONFIGS);
133
134         RoomMailAddress = qrbuf.QRname;
135         OneRNCfg = CtdlGetNetCfgForRoom(qrbuf.QRnumber);
136         if (OneRNCfg != NULL) {
137                 found_sub = CountThisSubscriber(OneRNCfg, *email);
138                 if (StrLength(OneRNCfg->Sender) > 0) {
139                        EmailSender = RoomMailAddress = ChrPtr(OneRNCfg->Sender);
140                 }
141         }
142
143         if (found_sub != 0) {
144                 cprintf("%d '%s' is already subscribed to '%s'.\n",
145                         ERROR + ALREADY_EXISTS,
146                         ChrPtr(*email),
147                         RoomMailAddress);
148
149                 FreeRoomNetworkStruct(&OneRNCfg);
150                 end_critical_section(S_NETCONFIGS);
151                 return;
152         }
153
154         /*
155          * Now add it to the config
156          */     
157         
158         RoomMailAddressLen = strlen(RoomMailAddress);
159         listsub_generate_token(token);
160         Line = (RoomNetCfgLine*)malloc(sizeof(RoomNetCfgLine));
161         memset(Line, 0, sizeof(RoomNetCfgLine));
162
163         Line->Value = (StrBuf**) malloc(sizeof(StrBuf*) * 5);
164         
165         Line->Value[0] = NewStrBufDup(*email);
166         Line->Value[1] = *subtype; *subtype = NULL;
167         Line->Value[2] = NewStrBufPlain(token, -1);
168         Line->Value[3] = NewStrBufPlain(NULL, 10);
169         StrBufPrintf(Line->Value[3], "%ld", time(NULL));
170         Line->Value[4] = *webpage; *webpage = NULL;
171         Line->nValues = 5;
172
173         AddRoomCfgLine(OneRNCfg, &qrbuf, subpending, Line);
174
175         /* Generate and send the confirmation request */
176         UrlRoom = NewStrBuf();
177         StrBufUrlescAppend(UrlRoom, NULL, qrbuf.QRname);
178
179         cf_req = NewStrBufPlain(NULL, 2048);
180         StrBufAppendBufPlain(
181                 cf_req,
182                 HKEY("MIME-Version: 1.0\n"
183                      "Content-Type: multipart/alternative; boundary=\"__ctdlmultipart__\"\n"
184                      "\n"
185                      "This is a multipart message in MIME format.\n"
186                      "\n"
187                      "--__ctdlmultipart__\n"
188                      "Content-type: text/plain\n"
189                      "\n"
190                      "Someone (probably you) has submitted a request to subscribe\n"
191                      "<"), 0);
192         StrBufAppendBuf(cf_req, Line->Value[0], 0);
193
194         StrBufAppendBufPlain(cf_req, HKEY("> to the '"), 0);
195         StrBufAppendBufPlain(cf_req, RoomMailAddress, RoomMailAddressLen, 0);
196
197         StrBufAppendBufPlain(
198                 cf_req,
199                 HKEY("' mailing list.\n"
200                      "\n"
201                      "Please go here to confirm this request:\n"
202                      "  "), 0);
203         StrBufAppendBuf(cf_req, Line->Value[4], 0);
204
205         StrBufAppendBufPlain(cf_req, HKEY("?room="), 0);
206         StrBufAppendBuf(cf_req, UrlRoom, 0);
207
208         StrBufAppendBufPlain(cf_req, HKEY("&token="), 0);
209         StrBufAppendBuf(cf_req, Line->Value[2], 0);
210
211         StrBufAppendBufPlain(
212                 cf_req,
213                 HKEY("&cmd=confirm  \n"
214                      "\n"
215                      "If this request has been submitted in error and you do not\n"
216                      "wish to receive the '"), 0);
217         StrBufAppendBufPlain(cf_req, RoomMailAddress, RoomMailAddressLen, 0);
218
219         StrBufAppendBufPlain(
220                 cf_req,
221                 HKEY("' mailing list, simply do nothing,\n"
222                      "and you will not receive any further mailings.\n"
223                      "\n"
224                      "--__ctdlmultipart__\n"
225                      "Content-type: text/html\n"
226                      "\n"
227                      "<HTML><BODY>\n"
228                      "Someone (probably you) has submitted a request to subscribe\n"
229                      "&lt;"), 0);
230         StrBufAppendBuf(cf_req, Line->Value[0], 0);
231
232         StrBufAppendBufPlain(cf_req, HKEY( "&gt; to the <B>"), 0);
233
234         StrBufAppendBufPlain(cf_req, RoomMailAddress, RoomMailAddressLen, 0);
235
236         StrBufAppendBufPlain(
237                 cf_req,
238                 HKEY("'</B> mailing list.<BR><BR>\n"
239                      "Please click here to confirm this request:<BR>\n"
240                      "<A HREF=\""), 0);
241         StrBufAppendBuf(cf_req, Line->Value[4], 0);
242
243         StrBufAppendBufPlain(cf_req, HKEY("?room="), 0);
244         StrBufAppendBuf(cf_req, UrlRoom, 0);
245
246         StrBufAppendBufPlain(cf_req, HKEY("&token="), 0);
247         StrBufAppendBuf(cf_req, Line->Value[2], 0);
248
249         StrBufAppendBufPlain(cf_req, HKEY("&cmd=confirm\">"), 0);
250         StrBufAppendBuf(cf_req, Line->Value[4], 0);
251
252         StrBufAppendBufPlain(cf_req, HKEY("?room="), 0);
253         StrBufAppendBuf(cf_req, UrlRoom, 0);
254
255         StrBufAppendBufPlain(cf_req, HKEY("&token="), 0);
256         StrBufAppendBuf(cf_req, Line->Value[2], 0);
257
258         StrBufAppendBufPlain(
259                 cf_req,
260                 HKEY("&cmd=confirm</A><BR><BR>\n"
261                      "If this request has been submitted in error and you do not\n"
262                      "wish to receive the '"), 0);
263         StrBufAppendBufPlain(cf_req, RoomMailAddress, RoomMailAddressLen, 0);
264         
265         StrBufAppendBufPlain(
266                 cf_req,
267                 HKEY("' mailing list, simply do nothing,\n"
268                      "and you will not receive any further mailings.\n"
269                      "</BODY></HTML>\n"
270                      "\n"
271                      "--__ctdlmultipart__--\n"), 0);
272
273         SaveRoomNetConfigFile(OneRNCfg, qrbuf.QRnumber);
274         FreeRoomNetworkStruct(&OneRNCfg);
275         end_critical_section(S_NETCONFIGS);
276
277         pcf_req = SmashStrBuf(&cf_req);
278         quickie_message(        /* This delivers the message */
279                 "Citadel",
280                 EmailSender,
281                 ChrPtr(*email),
282                 NULL,
283                 pcf_req,
284                 FMT_RFC822,
285                 "Please confirm your list subscription"
286                 );
287         free(pcf_req);
288         cprintf("%d Subscription entered; confirmation request sent\n", CIT_OK);
289
290         FreeStrBuf(&UrlRoom);
291 }
292
293
294 /*
295  * Enter an unsubscription request
296  */
297 void do_unsubscribe(StrBuf **room, StrBuf **email, StrBuf **webpage) {
298         struct ctdlroom qrbuf;
299         const char *EmailSender = NULL;
300         char token[256];
301         char *pcf_req;
302         StrBuf *cf_req;
303         StrBuf *UrlRoom;
304         int found_sub = 0;
305         const char *RoomMailAddress;
306         OneRoomNetCfg *OneRNCfg;
307         RoomNetCfgLine *Line;
308         long RoomMailAddressLen;
309
310         if (CtdlGetRoom(&qrbuf, ChrPtr(*room)) != 0) {
311                 cprintf("%d There is no list called '%s'\n",
312                         ERROR + ROOM_NOT_FOUND, ChrPtr(*room));
313                 return;
314         }
315
316         if ((qrbuf.QRflags2 & QR2_SELFLIST) == 0) {
317                 cprintf("%d '%s' "
318                         "does not accept subscribe/unsubscribe requests.\n",
319                         ERROR + HIGHER_ACCESS_REQUIRED, qrbuf.QRname);
320                 return;
321         }
322
323         listsub_generate_token(token);
324
325         /* 
326          * Make sure there's actually a subscription there to remove
327          */
328         begin_critical_section(S_NETCONFIGS);
329         RoomMailAddress = qrbuf.QRname;
330         OneRNCfg = CtdlGetNetCfgForRoom(qrbuf.QRnumber);
331         if (OneRNCfg!=NULL) {
332                 found_sub = CountThisSubscriber(OneRNCfg, *email);
333                 if (StrLength(OneRNCfg->Sender) > 0)
334                         EmailSender = RoomMailAddress = ChrPtr(OneRNCfg->Sender);
335         }
336
337         if (found_sub == 0) {
338                 cprintf("%d '%s' is not subscribed to '%s'.\n", ERROR + NO_SUCH_USER, ChrPtr(*email), qrbuf.QRname);
339                 FreeRoomNetworkStruct(&OneRNCfg);
340                 end_critical_section(S_NETCONFIGS);
341                 return;
342         }
343         
344         /* 
345          * Ok, now enter the unsubscribe-pending entry.
346          */
347         RoomMailAddressLen = strlen(RoomMailAddress);
348         listsub_generate_token(token);
349         Line = (RoomNetCfgLine*)malloc(sizeof(RoomNetCfgLine));
350         memset(Line, 0, sizeof(RoomNetCfgLine));
351
352         Line->Value = (StrBuf**) malloc(sizeof(StrBuf*) * 4);
353         
354         Line->Value[0] = NewStrBufDup(*email);
355         Line->Value[1] = NewStrBufPlain(token, -1);
356         Line->Value[2] = NewStrBufPlain(NULL, 10);
357         StrBufPrintf(Line->Value[2], "%ld", time(NULL));
358         Line->Value[3] = *webpage; *webpage = NULL;
359         Line->nValues = 4;
360
361         AddRoomCfgLine(OneRNCfg, &qrbuf, unsubpending, Line);
362
363         /* Generate and send the confirmation request */
364         UrlRoom = NewStrBuf();
365         StrBufUrlescAppend(UrlRoom, NULL, qrbuf.QRname);
366
367         cf_req = NewStrBufPlain(NULL, 2048);
368
369         StrBufAppendBufPlain(
370                 cf_req,
371                 HKEY("MIME-Version: 1.0\n"
372                      "Content-Type: multipart/alternative; boundary=\"__ctdlmultipart__\"\n"
373                      "\n"
374                      "This is a multipart message in MIME format.\n"
375                      "\n"
376                      "--__ctdlmultipart__\n"
377                      "Content-type: text/plain\n"
378                      "\n"
379                      "Someone (probably you) has submitted a request to unsubscribe\n"
380                      "<"), 0);
381         StrBufAppendBuf(cf_req, Line->Value[0], 0);
382
383
384         StrBufAppendBufPlain(
385                 cf_req,
386                 HKEY("> from the '"), 0);
387         StrBufAppendBufPlain(cf_req, RoomMailAddress, RoomMailAddressLen, 0);
388
389         StrBufAppendBufPlain(
390                 cf_req,
391                 HKEY("' mailing list.\n"
392                      "\n"
393                      "Please go here to confirm this request:\n  "), 0);
394         StrBufAppendBuf(cf_req, Line->Value[3], 0);
395         StrBufAppendBufPlain(cf_req, HKEY("?room="), 0);
396         StrBufAppendBuf(cf_req, UrlRoom, 0);
397         StrBufAppendBufPlain(cf_req, HKEY("&token="), 0);
398         StrBufAppendBuf(cf_req, Line->Value[1], 0);
399
400         StrBufAppendBufPlain(
401                 cf_req,
402                 HKEY("&cmd=confirm  \n"
403                      "\n"
404                      "If this request has been submitted in error and you do not\n"
405                      "wish to unsubscribe from the '"), 0);
406
407         StrBufAppendBufPlain(cf_req, RoomMailAddress, RoomMailAddressLen, 0);
408
409         StrBufAppendBufPlain(
410                 cf_req,
411                 HKEY("' mailing list, simply do nothing,\n"
412                      "and the request will not be processed.\n"
413                      "\n"
414                      "--__ctdlmultipart__\n"
415                      "Content-type: text/html\n"
416                      "\n"
417                      "<HTML><BODY>\n"
418                      "Someone (probably you) has submitted a request to unsubscribe\n"
419                      "&lt;"), 0);
420         StrBufAppendBuf(cf_req, Line->Value[0], 0);
421
422         StrBufAppendBufPlain(cf_req, HKEY("&gt; from the <B>"), 0);
423         StrBufAppendBufPlain(cf_req, RoomMailAddress, RoomMailAddressLen, 0);
424
425         StrBufAppendBufPlain(
426                 cf_req,
427                 HKEY("</B> mailing list.<BR><BR>\n"
428                      "Please click here to confirm this request:<BR>\n"
429                      "<A HREF=\""), 0);
430         StrBufAppendBuf(cf_req, Line->Value[3], 0);
431
432         StrBufAppendBufPlain(cf_req, HKEY("?room="), 0);
433         StrBufAppendBuf(cf_req, UrlRoom, 0);
434
435         StrBufAppendBufPlain(cf_req, HKEY("&token="), 0);
436         StrBufAppendBuf(cf_req, Line->Value[1], 0);
437
438         StrBufAppendBufPlain(cf_req, HKEY("&cmd=confirm\">"), 0);
439         StrBufAppendBuf(cf_req, Line->Value[3], 0);
440
441         StrBufAppendBufPlain(cf_req, HKEY("?room="), 0);
442         StrBufAppendBuf(cf_req, UrlRoom, 0);
443
444         StrBufAppendBufPlain(cf_req, HKEY("&token="), 0);
445         StrBufAppendBuf(cf_req, Line->Value[1], 0);
446
447
448         StrBufAppendBufPlain(
449                 cf_req,
450                 HKEY("&cmd=confirm</A><BR><BR>\n"
451                      "If this request has been submitted in error and you do not\n"
452                      "wish to unsubscribe from the '"), 0);
453         StrBufAppendBufPlain(cf_req, RoomMailAddress, RoomMailAddressLen, 0);
454
455         StrBufAppendBufPlain(
456                 cf_req,
457                 HKEY("' mailing list, simply do nothing,\n"
458                      "and the request will not be processed.\n"
459                      "</BODY></HTML>\n"
460                      "\n"
461                      "--__ctdlmultipart__--\n"), 0);
462
463         SaveRoomNetConfigFile(OneRNCfg, qrbuf.QRnumber);
464         FreeRoomNetworkStruct(&OneRNCfg);
465         end_critical_section(S_NETCONFIGS);
466
467         pcf_req = SmashStrBuf(&cf_req);
468         quickie_message(        /* This delivers the message */
469                 "Citadel",
470                 EmailSender,
471                 ChrPtr(*email),
472                 NULL,
473                 pcf_req,
474                 FMT_RFC822,
475                 "Please confirm your unsubscribe request"
476         );
477
478         free(pcf_req);
479         FreeStrBuf(&UrlRoom);
480         cprintf("%d Unubscription noted; confirmation request sent\n", CIT_OK);
481 }
482
483
484 const RoomNetCfg ConfirmSubscribers[] = {subpending, unsubpending};
485
486 /*
487  * Confirm a subscribe/unsubscribe request.
488  */
489 void do_confirm(StrBuf **room, StrBuf **token) {
490         struct ctdlroom qrbuf;
491         OneRoomNetCfg *OneRNCfg;
492         RoomNetCfgLine *Line;
493         RoomNetCfgLine *ConfirmLine = NULL;
494         RoomNetCfgLine *RemoveLine = NULL;
495         RoomNetCfgLine **PrevLine;
496         int success = 0;
497         RoomNetCfg ConfirmType;
498         const char *errmsg = "";
499         int i;
500         
501         if (CtdlGetRoom(&qrbuf, ChrPtr(*room)) != 0) {
502                 cprintf("%d There is no list called '%s'\n",
503                         ERROR + ROOM_NOT_FOUND, ChrPtr(*room));
504                 return;
505         }
506
507         if ((qrbuf.QRflags2 & QR2_SELFLIST) == 0) {
508                 cprintf("%d '%s' "
509                         "does not accept subscribe/unsubscribe requests.\n",
510                         ERROR + HIGHER_ACCESS_REQUIRED, qrbuf.QRname);
511                 return;
512         }
513
514
515         if (StrLength(*token) == 0) {
516                 cprintf("%d empty token.\n", ERROR + ILLEGAL_VALUE);
517                 return;
518         }
519         /*
520          * Now start scanning this room's netconfig file for the
521          * specified token.
522          */
523         begin_critical_section(S_NETCONFIGS);
524         OneRNCfg = CtdlGetNetCfgForRoom(qrbuf.QRnumber);
525
526         ConfirmType = maxRoomNetCfg;
527         if (OneRNCfg==NULL)
528         {
529                 errmsg = "no networking config found";
530         }
531         else for (i = 0; i < 2; i++)
532         {
533                 int offset;
534
535                 if (ConfirmSubscribers[i] == subpending)
536                         offset = 2;
537                 else
538                         offset = 1;
539                 PrevLine = &OneRNCfg->NetConfigs[ConfirmSubscribers[i]];
540                 Line = *PrevLine;
541                 while (Line != NULL)
542                 {
543                         if (!strcasecmp(ChrPtr(*token),
544                                         ChrPtr(Line->Value[offset])))
545                         {
546                                 ConfirmLine = Line;
547                                 *PrevLine = Line->next; /* Remove it from the list */
548                                 ConfirmType = ConfirmSubscribers[i];
549                                 ConfirmLine->next = NULL;
550
551                                 i += 100; 
552                                 break;
553
554                         }
555                         PrevLine = &(*PrevLine)->next;
556                         Line = Line->next;
557                 }
558                 if (ConfirmType == maxRoomNetCfg)
559                 {
560                         errmsg = "No active un/subscribe request found";
561                 }
562         }
563
564         if (ConfirmType == subpending)
565         {
566                 if (CountThisSubscriber(OneRNCfg, ConfirmLine->Value[0]) == 0)
567                 {
568                         if (!strcasecmp(ChrPtr(ConfirmLine->Value[2]), 
569                                         ("digest")))
570                         {
571                                 ConfirmType = digestrecp;
572                         }
573                         else /* "list" */
574                         {
575                                 ConfirmType = listrecp;
576                         }
577
578                         syslog(LOG_NOTICE, 
579                                "Mailing list: %s subscribed to %s with token %s\n", 
580                                ChrPtr(ConfirmLine->Value[0]), 
581                                qrbuf.QRname,
582                                ChrPtr(*token));
583
584                         FreeStrBuf(&ConfirmLine->Value[1]);
585                         FreeStrBuf(&ConfirmLine->Value[2]);
586                         FreeStrBuf(&ConfirmLine->Value[3]);
587                         FreeStrBuf(&ConfirmLine->Value[4]);
588                         ConfirmLine->nValues = 1;
589                 
590                         AddRoomCfgLine(OneRNCfg, &qrbuf, ConfirmType, ConfirmLine);
591                         success = 1;
592                 }
593                 else
594                 {
595                         /* whipe duplicate subscribe entry... */
596                         errmsg = "already subscribed";
597                 }
598         }
599         else if (ConfirmType == unsubpending)
600         {
601
602                 for (i = 0; i < 2; i++)
603                 {
604                         PrevLine = &OneRNCfg->NetConfigs[ActiveSubscribers[i]];
605                         Line = *PrevLine;
606                         while (Line != NULL)
607                         {
608                                 if (!strcasecmp(ChrPtr(ConfirmLine->Value[0]),
609                                                 ChrPtr(Line->Value[0])))
610                                 {
611                                         success = 1;
612                                         RemoveLine = Line;
613                                         *PrevLine = Line->next; /* Remove it from the list */
614                                         RemoveLine->next = NULL;
615                                         if (RemoveLine != NULL) 
616                                                 DeleteGenericCfgLine(NULL/*TODO*/, &RemoveLine);
617                                         Line = *PrevLine;
618                                         continue;
619                                 }
620                                 PrevLine = &(*PrevLine)->next;
621                                 Line = Line->next;
622                         }
623                 }
624
625                 if (success) 
626                 {
627                         syslog(LOG_NOTICE, 
628                                "Mailing list: %s unsubscribed to %s with token %s\n", 
629                                ChrPtr(ConfirmLine->Value[0]), 
630                                qrbuf.QRname,
631                                ChrPtr(*token));
632                 }
633                 else
634                 {
635                         errmsg = "no subscriber found for this unsubscription request";
636                 }
637                 DeleteGenericCfgLine(NULL/*TODO*/, &ConfirmLine);
638         }
639
640         SaveRoomNetConfigFile(OneRNCfg, qrbuf.QRnumber);
641         FreeRoomNetworkStruct(&OneRNCfg);
642         end_critical_section(S_NETCONFIGS);
643         
644         /*
645          * Did we do anything useful today?
646          */
647         if (success) {
648                 cprintf("%d %d operation(s) confirmed.\n", CIT_OK, success);
649         }
650         else {
651                 syslog(LOG_NOTICE, "failed processing (un)subscribe request: %s",
652                        errmsg);
653                 cprintf("%d Invalid token.\n", ERROR + ILLEGAL_VALUE);
654         }
655
656 }
657
658
659
660 /* 
661  * process subscribe/unsubscribe requests and confirmations
662  */
663 void cmd_subs(char *cmdbuf)
664 {
665         const char *Pos = NULL;
666         StrBuf *Segments[20];
667         int i=1;
668
669         memset(Segments, 0, sizeof(StrBuf*) * 20);
670         Segments[0] = NewStrBufPlain(cmdbuf, -1);
671         while ((Pos != StrBufNOTNULL) && (i < 20))
672         {
673                 Segments[i] = NewStrBufPlain(NULL, StrLength(Segments[0]));
674                 StrBufExtract_NextToken(Segments[i], Segments[0], &Pos, '|');
675                 i++;
676         }
677
678         if (!strcasecmp(ChrPtr(Segments[1]), "subscribe")) {
679                 if ( (strcasecmp(ChrPtr(Segments[4]), "list"))
680                    && (strcasecmp(ChrPtr(Segments[4]), "digest")) ) {
681                         cprintf("%d Invalid subscription type '%s'\n",
682                                 ERROR + ILLEGAL_VALUE, ChrPtr(Segments[4]));
683                 }
684                 else {
685                         do_subscribe(&Segments[2], &Segments[3], &Segments[4], &Segments[5]);
686                 }
687         }
688         else if (!strcasecmp(ChrPtr(Segments[1]), "unsubscribe")) {
689                 do_unsubscribe(&Segments[2], &Segments[3], &Segments[4]);
690         }
691         else if (!strcasecmp(ChrPtr(Segments[1]), "confirm")) {
692                 do_confirm(&Segments[2], &Segments[3]);
693         }
694         else {
695                 cprintf("%d Invalid command\n", ERROR + ILLEGAL_VALUE);
696         }
697
698         for (; i>=0; i--)
699         {
700                 FreeStrBuf(&Segments[i]);
701         }
702 }
703
704
705 /*
706  * Module entry point
707  */
708 CTDL_MODULE_INIT(listsub)
709 {
710         if (!threading)
711         {
712                 CtdlRegisterProtoHook(cmd_subs, "SUBS", "List subscribe/unsubscribe");
713         }
714         
715         /* return our module name for the log */
716         return "listsub";
717 }