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