getmx() now uses our array class
[citadel.git] / citadel / netconfig.c
1 /*
2  * This module handles loading, saving, and parsing of room network configurations.
3  *
4  * Copyright (c) 2000-2021 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
16 #include "sysdep.h"
17 #include <stdio.h>
18 #include <sys/types.h>
19 #include <dirent.h>
20
21 #ifdef HAVE_SYSCALL_H
22 # include <syscall.h>
23 #else 
24 # if HAVE_SYS_SYSCALL_H
25 #  include <sys/syscall.h>
26 # endif
27 #endif
28 #include <dirent.h>
29 #include <assert.h>
30
31 #include <libcitadel.h>
32
33 #include "ctdl_module.h"
34 #include "serv_extensions.h"
35 #include "config.h"
36
37
38 /*
39  * Create a config key for a room's netconfig entry
40  */
41 void netcfg_keyname(char *keybuf, long roomnum) {
42         if (!keybuf) return;
43         sprintf(keybuf, "c_netconfig_%010ld", roomnum);
44 }
45
46
47 /*
48  * Given a room number and a textual netconfig, convert to base64 and write to the configdb
49  */
50 void SaveRoomNetConfigFile(long roomnum, const char *raw_netconfig) {
51         char keyname[25];
52         char *enc;
53         int enc_len;
54         int len;
55
56         len = strlen(raw_netconfig);
57         netcfg_keyname(keyname, roomnum);
58         enc = malloc(len * 2);
59
60         if (enc) {
61                 enc_len = CtdlEncodeBase64(enc, raw_netconfig, len, 0);
62                 if ((enc_len > 1) && (enc[enc_len-2] == 13)) enc[enc_len-2] = 0;
63                 if ((enc_len > 0) && (enc[enc_len-1] == 10)) enc[enc_len-1] = 0;
64                 enc[enc_len] = 0;
65                 syslog(LOG_DEBUG, "netconfig: writing key '%s' (length=%d)", keyname, enc_len);
66                 CtdlSetConfigStr(keyname, enc);
67                 free(enc);
68         }
69 }
70
71
72 /*
73  * Given a room number, attempt to load the netconfig configdb entry for that room.
74  * If it returns NULL, there is no netconfig.
75  * Otherwise the caller owns the returned memory and is responsible for freeing it.
76  */
77 char *LoadRoomNetConfigFile(long roomnum) {
78         char keyname[25];
79         char *encoded_netconfig = NULL;
80         char *decoded_netconfig = NULL;
81
82         netcfg_keyname(keyname, roomnum);
83         encoded_netconfig = CtdlGetConfigStr(keyname);
84         if (!encoded_netconfig) return NULL;
85
86         decoded_netconfig = malloc(strlen(encoded_netconfig));  // yeah, way bigger than it needs to be, but safe
87         CtdlDecodeBase64(decoded_netconfig, encoded_netconfig, strlen(encoded_netconfig));
88         return decoded_netconfig;
89 }
90
91
92 /*-----------------------------------------------------------------------------*
93  *              Per room network configs : exchange with client                *
94  *-----------------------------------------------------------------------------*/
95
96 void cmd_gnet(char *argbuf) {
97         if ( (CC->room.QRflags & QR_MAILBOX) && (CC->user.usernum == atol(CC->room.QRname)) ) {
98                 /* users can edit the netconfigs for their own mailbox rooms */
99         }
100         else if (CtdlAccessCheck(ac_room_aide)) return;
101         
102         cprintf("%d Network settings for room #%ld <%s>\n", LISTING_FOLLOWS, CC->room.QRnumber, CC->room.QRname);
103
104         char *c = LoadRoomNetConfigFile(CC->room.QRnumber);
105         if (c) {
106                 int len = strlen(c);
107                 client_write(c, len);                   // Can't use cprintf() here, it has a limit of 1024 bytes
108                 if (c[len] != '\n') {
109                         client_write(HKEY("\n"));
110                 }
111                 free(c);
112         }
113         cprintf("000\n");
114 }
115
116
117 void cmd_snet(char *argbuf) {
118         StrBuf *Line = NULL;
119         StrBuf *TheConfig = NULL;
120         int rc;
121
122         unbuffer_output();
123         Line = NewStrBuf();
124         TheConfig = NewStrBuf();
125         cprintf("%d send new netconfig now\n", SEND_LISTING);
126
127         while (rc = CtdlClientGetLine(Line), (rc >= 0)) {
128                 if ((rc == 3) && (strcmp(ChrPtr(Line), "000") == 0))
129                         break;
130
131                 StrBufAppendBuf(TheConfig, Line, 0);
132                 StrBufAppendBufPlain(TheConfig, HKEY("\n"), 0);
133         }
134         FreeStrBuf(&Line);
135
136         begin_critical_section(S_NETCONFIGS);
137         SaveRoomNetConfigFile(CC->room.QRnumber, ChrPtr(TheConfig));
138         end_critical_section(S_NETCONFIGS);
139         FreeStrBuf(&TheConfig);
140 }
141
142
143 /*
144  * Convert any legacy configuration files in the "netconfigs" directory
145  */
146 void convert_legacy_netcfg_files(void)
147 {
148         DIR *dh = NULL;
149         struct dirent *dit = NULL;
150         char filename[PATH_MAX];
151         long roomnum;
152         FILE *fp;
153         long len;
154         char *v;
155
156         dh = opendir(ctdl_netcfg_dir);
157         if (!dh) return;
158
159         syslog(LOG_INFO, "netconfig: legacy netconfig files exist - converting them!");
160
161         while (dit = readdir(dh), dit != NULL) {        // yes, we use the non-reentrant version; we're not in threaded mode yet
162                 roomnum = atol(dit->d_name);
163                 if (roomnum > 0) {
164                         snprintf(filename, sizeof filename, "%s/%ld", ctdl_netcfg_dir, roomnum);
165                         fp = fopen(filename, "r");
166                         if (fp) {
167                                 fseek(fp, 0L, SEEK_END);
168                                 len = ftell(fp);
169                                 if (len > 0) {
170                                         v = malloc(len);
171                                         if (v) {
172                                                 rewind(fp);
173                                                 if (fread(v, len, 1, fp)) {
174                                                         SaveRoomNetConfigFile(roomnum, v);
175                                                         unlink(filename);
176                                                 }
177                                                 free(v);
178                                         }
179                                 }
180                                 else {
181                                         unlink(filename);       // zero length netconfig, just delete it
182                                 }
183                                 fclose(fp);
184                         }
185                 }
186         }
187
188         closedir(dh);
189         rmdir(ctdl_netcfg_dir);
190 }
191
192
193 /*
194  * Module entry point
195  */
196 CTDL_MODULE_INIT(netconfig)
197 {
198         if (!threading)
199         {
200                 convert_legacy_netcfg_files();
201                 CtdlRegisterProtoHook(cmd_gnet, "GNET", "Get network config");
202                 CtdlRegisterProtoHook(cmd_snet, "SNET", "Set network config");
203         }
204         return "netconfig";
205 }