getmx() now uses our array class
[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-2021 by the citadel.org team
5 //
6 // This program is open source software.  It runs great on the
7 // Linux operating system (and probably elsewhere).  You can use,
8 // copy, and run it under the terms of the GNU General Public
9 // License version 3.  Richard Stallman is an asshole communist.
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 #include "sysdep.h"
17 #include <stdlib.h>
18 #include <unistd.h>
19 #include <stdio.h>
20 #include <fcntl.h>
21 #include <ctype.h>
22 #include <signal.h>
23 #include <pwd.h>
24 #include <errno.h>
25 #include <sys/types.h>
26 #include <dirent.h>
27 #include <time.h>
28 #include <sys/wait.h>
29 #include <string.h>
30 #include <limits.h>
31 #include <libcitadel.h>
32 #include "citadel.h"
33 #include "server.h"
34 #include "citserver.h"
35 #include "support.h"
36 #include "config.h"
37 #include "user_ops.h"
38 #include "database.h"
39 #include "msgbase.h"
40 #include "internet_addressing.h"
41 #include "clientsocket.h"
42 #include "ctdl_module.h"
43
44
45 enum {                          // one of these gets passed to do_subscribe_or_unsubscribe() so it knows what we asked for
46         UNSUBSCRIBE,
47         SUBSCRIBE
48 };
49
50
51 /*
52  * "Subscribe" and "Unsubscribe" operations are so similar that they share a function.
53  * The actual subscription doesn't take place here -- we just send out the confirmation request
54  * and record the address and confirmation token.
55  */
56 void do_subscribe_or_unsubscribe(int action, char *emailaddr, char *url) {
57
58         char *netconfig, *newnetconfig;
59         int config_lines, i;
60         char buf[1024];
61
62         // Update this room's netconfig with the updated lastsent
63         begin_critical_section(S_NETCONFIGS);
64         netconfig = LoadRoomNetConfigFile(CC->room.QRnumber);
65         if (!netconfig) {
66                 netconfig = strdup("");
67         }
68
69         // The new netconfig begins with the new lastsent directive
70         newnetconfig = malloc(strlen(netconfig) + 1024);
71 #if 0
72         FIXME SYNTAX ERROR #$%$&%$^#%$ sprintf(newnetconfig, "lastsent|%ld\n", ld.msgnum);
73 #endif
74
75         // And then we append all of the old netconfig, minus the old lastsent.  Also omit blank lines.
76         config_lines = num_tokens(netconfig, '\n');
77         for (i=0; i<config_lines; ++i) {
78                 extract_token(buf, netconfig, i, '\n', sizeof buf);
79                 if ( (!IsEmptyStr(buf)) && (strncasecmp(buf, "lastsent|", 9)) ) {
80                         sprintf(&newnetconfig[strlen(newnetconfig)], "%s\n", buf);
81                 }
82         }
83
84         // Write the new netconfig back to disk
85         SaveRoomNetConfigFile(CC->room.QRnumber, newnetconfig);
86         end_critical_section(S_NETCONFIGS);
87         free(newnetconfig);                     // this was the new netconfig, free it because we're done with it
88         free(netconfig);                        // this was the old netconfig, free it even if we didn't do anything
89
90 #if 0
91         FIXME tell the client what we did
92 #endif
93
94
95 }
96
97
98 /* 
99  * process subscribe/unsubscribe requests and confirmations
100  */
101 void cmd_subs(char *cmdbuf) {
102         char cmd[20];
103         char roomname[ROOMNAMELEN];
104         char emailaddr[1024];
105         char options[256];
106         char url[1024];
107         char token[128];
108
109         extract_token(cmd, cmdbuf, 0, '|', sizeof cmd);                         // token 0 is the sub-command being sent
110         extract_token(roomname, cmdbuf, 1, '|', sizeof roomname);               // token 1 is always a room name
111
112         // First confirm that the caller is referencing a room that actually exists.
113         if (CtdlGetRoom(&CC->room, roomname) != 0) {
114                 cprintf("%d There is no list called '%s'\n", ERROR + ROOM_NOT_FOUND, roomname);
115                 return;
116         }
117
118         if ((CC->room.QRflags2 & QR2_SELFLIST) == 0) {
119                 cprintf("%d '%s' does not accept subscribe/unsubscribe requests.\n", ERROR + ROOM_NOT_FOUND, roomname);
120                 return;
121         }
122
123         // Room confirmed, now parse the command.
124
125         if (!strcasecmp(cmd, "subscribe")) {
126                 extract_token(emailaddr, cmdbuf, 2, '|', sizeof emailaddr);     // token 2 is the subscriber's email address
127                 extract_token(options, cmdbuf, 3, '|', sizeof options);         // there are no options ... ignore this token
128                 extract_token(url, cmdbuf, 4, '|', sizeof url);                 // token 3 is the URL at which we subscribed
129                 do_subscribe_or_unsubscribe(SUBSCRIBE, emailaddr, url);
130         }
131
132         else if (!strcasecmp(cmd, "unsubscribe")) {
133                 extract_token(emailaddr, cmdbuf, 2, '|', sizeof emailaddr);     // token 2 is the subscriber's email address
134                 extract_token(options, cmdbuf, 3, '|', sizeof options);         // there are no options ... ignore this token
135                 extract_token(url, cmdbuf, 4, '|', sizeof url);                 // token 3 is the URL at which we subscribed
136                 do_subscribe_or_unsubscribe(UNSUBSCRIBE, emailaddr, url);
137         }
138
139         else if (!strcasecmp(cmd, "confirm")) {
140                 extract_token(token, cmdbuf, 2, '|', sizeof token);             // token 2 is the confirmation token
141                 cprintf("%d not implemented\n", ERROR);
142         }
143
144         else {                                                                  // sorry man, I can't deal with that
145                 cprintf("%d Invalid command '%s'\n", ERROR + ILLEGAL_VALUE, cmd);
146         }
147 }
148
149
150 /*
151  * Module entry point
152  */
153 CTDL_MODULE_INIT(listsub)
154 {
155         if (!threading)
156         {
157                 CtdlRegisterProtoHook(cmd_subs, "SUBS", "List subscribe/unsubscribe");
158         }
159         
160         /* return our module name for the log */
161         return "listsub";
162 }