3c20541c0f7fd51714b0a750e96ae78506ddd030
[citadel.git] / citadel / netconfig.c
1 /*
2  * This module handles shared rooms, inter-Citadel mail, and outbound
3  * mailing list processing.
4  *
5  * Copyright (c) 2000-2012 by the citadel.org team
6  *
7  *  This program is open source software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License, version 3.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  */
16
17 #include "sysdep.h"
18 #include <stdio.h>
19
20 #ifdef HAVE_SYSCALL_H
21 # include <syscall.h>
22 #else 
23 # if HAVE_SYS_SYSCALL_H
24 #  include <sys/syscall.h>
25 # endif
26 #endif
27
28 #include <libcitadel.h>
29
30 #include "include/ctdl_module.h"
31 HashList *CfgTypeHash = NULL;
32
33
34
35 void RegisterRoomCfgType(const char* Name, long len, RoomNetCfg eCfg, CfgLineParser p, int uniq, CfgLineSerializer s, CfgLineDeAllocator d)
36 {
37         CfgLineType *pCfg;
38
39         pCfg = (CfgLineType*) malloc(sizeof(CfgLineType));
40         pCfg->Parser = p;
41         pCfg->Serializer = s;
42         pCfg->C = eCfg;
43         pCfg->Str.Key = Name;
44         pCfg->Str.len = len;
45         pCfg->IsSingleLine = uniq;
46
47         if (CfgTypeHash == NULL)
48                 CfgTypeHash = NewHash(1, NULL);
49         Put(CfgTypeHash, Name, len, pCfg, NULL);
50 }
51
52
53 const CfgLineType *GetCfgTypeByStr(const char *Key, long len)
54 {
55         void *pv;
56         
57         if (GetHash(CfgTypeHash, Key, len, &pv) && (pv != NULL))
58         {
59                 return (const CfgLineType *) pv;
60         }
61         else
62         {
63                 return NULL;
64         }
65 }
66
67 const CfgLineType *GetCfgTypeByEnum(RoomNetCfg eCfg, HashPos *It)
68 {
69         const char *Key;
70         long len;
71         void *pv;
72         CfgLineType *pCfg;
73
74         RewindHashPos(CfgTypeHash, It, 1);
75         while (GetNextHashPos(CfgTypeHash, It, &len, &Key, &pv) && (pv != NULL))
76         {
77                 pCfg = (CfgLineType*) pv;
78                 if (pCfg->C == eCfg)
79                         return pCfg;
80         }
81         return NULL;
82 }
83 void ParseGeneric(const CfgLineType *ThisOne, StrBuf *Line, const char *LinePos, OneRoomNetCfg *OneRNCFG)
84 {
85         RoomNetCfgLine *nptr;
86
87         nptr = (RoomNetCfgLine *)
88                 malloc(sizeof(RoomNetCfgLine));
89         nptr->next = OneRNCFG->NetConfigs[ThisOne->C];
90         nptr->Value = NewStrBufPlain(LinePos, StrLength(Line) - ( LinePos - ChrPtr(Line)) );
91         OneRNCFG->NetConfigs[ThisOne->C] = nptr;
92 }
93
94 void SerializeGeneric(const CfgLineType *ThisOne, StrBuf *OutputBuffer, OneRoomNetCfg *OneRNCFG, RoomNetCfgLine *data)
95 {
96         StrBufAppendBufPlain(OutputBuffer, CKEY(ThisOne->Str), 0);
97         StrBufAppendBuf(OutputBuffer, data->Value, 0);
98         StrBufAppendBufPlain(OutputBuffer, HKEY("\n"), 0);
99 }
100
101 void DeleteGenericCfgLine(const CfgLineType *ThisOne, RoomNetCfgLine **data)
102 {
103         FreeStrBuf(&(*data)->Value);
104         free(*data);
105         *data = NULL;
106 }
107 int read_spoolcontrol_file(OneRoomNetCfg **pOneRNCFG, char *filename)
108 {
109         int fd;
110         const char *ErrStr = NULL;
111         const char *Pos;
112         const CfgLineType *pCfg;
113         StrBuf *Line;
114         StrBuf *InStr;
115         OneRoomNetCfg *OneRNCFG;
116
117         fd = open(filename, O_NONBLOCK|O_RDONLY);
118         if (fd == -1) {
119                 *pOneRNCFG = NULL;
120                 return 0;
121         }
122         OneRNCFG = malloc(sizeof(OneRoomNetCfg));
123         memset(OneRNCFG, 0, sizeof(OneRoomNetCfg));
124         *pOneRNCFG = OneRNCFG;
125
126         while (StrBufTCP_read_line(Line, &fd, 0, &ErrStr) >= 0) {
127                 if (StrLength(Line) == 0)
128                         continue;
129                 Pos = NULL;
130                 InStr = NewStrBufPlain(NULL, StrLength(Line));
131                 StrBufExtract_NextToken(InStr, Line, &Pos, '|');
132
133                 pCfg = GetCfgTypeByStr(SKEY(InStr));
134                 if (pCfg != NULL)
135                 {
136                         pCfg->Parser(pCfg, Line, Pos, OneRNCFG);
137                 }
138                 else
139                 {
140                         if (OneRNCFG->misc == NULL)
141                         {
142                                 OneRNCFG->misc = NewStrBufDup(Line);
143                         }
144                         else
145                         {
146                                 if(StrLength(OneRNCFG->misc) > 0)
147                                         StrBufAppendBufPlain(OneRNCFG->misc, HKEY("\n"), 0);
148                                 StrBufAppendBuf(OneRNCFG->misc, Line, 0);
149                         }
150                 }
151         }
152         if (fd > 0)
153                 close(fd);
154         FreeStrBuf(&InStr);
155         FreeStrBuf(&Line);
156         return 1;
157 }
158
159 int save_spoolcontrol_file(OneRoomNetCfg *OneRNCFG, char *filename)
160 {
161         RoomNetCfg eCfg;
162         StrBuf *Cfg;
163         char tempfilename[PATH_MAX];
164         int TmpFD;
165         long len;
166         time_t unixtime;
167         struct timeval tv;
168         long reltid; /* if we don't have SYS_gettid, use "random" value */
169         StrBuf *OutBuffer;
170         int rc;
171         HashPos *CfgIt;
172
173         len = strlen(filename);
174         memcpy(tempfilename, filename, len + 1);
175
176 #if defined(HAVE_SYONERNCFGALL_H) && defined (SYS_gettid)
177         reltid = syOneRNCFGall(SYS_gettid);
178 #endif
179         gettimeofday(&tv, NULL);
180         /* Promote to time_t; types differ on some OSes (like darwin) */
181         unixtime = tv.tv_sec;
182
183         sprintf(tempfilename + len, ".%ld-%ld", reltid, unixtime);
184         errno = 0;
185         TmpFD = open(tempfilename, O_CREAT|O_EXCL|O_RDWR, S_IRUSR|S_IWUSR);
186         Cfg = NewStrBuf();
187         if ((TmpFD < 0) || (errno != 0)) {
188                 syslog(LOG_CRIT, "ERROR: cannot open %s: %s\n",
189                         filename, strerror(errno));
190                 unlink(tempfilename);
191                 return 0;
192         }
193         else {
194                 CfgIt = GetNewHashPos(CfgTypeHash, 1);
195                 fchown(TmpFD, config.c_ctdluid, 0);
196                 for (eCfg = subpending; eCfg < maxRoomNetCfg; eCfg ++)
197                 {
198                         const CfgLineType *pCfg;
199                         pCfg = GetCfgTypeByEnum(eCfg, CfgIt);
200                         if (pCfg->IsSingleLine)
201                         {
202                                 pCfg->Serializer(pCfg, OutBuffer, OneRNCFG, NULL);
203                         }
204                         else
205                         {
206                                 RoomNetCfgLine *pName = OneRNCFG->NetConfigs[pCfg->C];
207                                 while (pName != NULL)
208                                 {
209                                         pCfg->Serializer(pCfg, OutBuffer, OneRNCFG, pName);
210                                         pName = pName->next;
211                                 }
212                                 
213                                 
214                         }
215
216                 }
217                 DeleteHashPos(&CfgIt);
218
219
220                 if (OneRNCFG->misc != NULL) {
221                         StrBufAppendBuf(OutBuffer, OneRNCFG->misc, 0);
222                 }
223
224                 rc = write(TmpFD, ChrPtr(OutBuffer), StrLength(OutBuffer));
225                 if ((rc >=0 ) && (rc == StrLength(Cfg))) 
226                 {
227                         close(TmpFD);
228                         rename(tempfilename, filename);
229                         rc = 1;
230                 }
231                 else {
232                         syslog(LOG_EMERG, 
233                                       "unable to write %s; [%s]; not enough space on the disk?\n", 
234                                       tempfilename, 
235                                       strerror(errno));
236                         close(TmpFD);
237                         unlink(tempfilename);
238                         rc = 0;
239                 }
240                 FreeStrBuf(&OutBuffer);
241                 
242         }
243         return rc;
244 }
245
246
247
248 void free_spoolcontrol_struct(OneRoomNetCfg **pOneRNCFG)
249 {
250         RoomNetCfg eCfg;
251         HashPos *CfgIt;
252         OneRoomNetCfg *OneRNCFG;
253
254         OneRNCFG = *pOneRNCFG;
255         CfgIt = GetNewHashPos(CfgTypeHash, 1);
256         for (eCfg = subpending; eCfg < maxRoomNetCfg; eCfg ++)
257         {
258                 const CfgLineType *pCfg;
259                 RoomNetCfgLine *pNext, *pName;
260                 
261                 pCfg = GetCfgTypeByEnum(eCfg, CfgIt);
262                 pName= OneRNCFG->NetConfigs[pCfg->C];
263                 while (pName != NULL)
264                 {
265                         pNext = pName->next;
266                         pCfg->DeAllocator(pCfg, &pName);
267                         pName = pNext;
268                 }
269         }
270         DeleteHashPos(&CfgIt);
271
272         FreeStrBuf(&OneRNCFG->Sender);
273         FreeStrBuf(&OneRNCFG->RoomInfo);
274         FreeStrBuf(&OneRNCFG->misc);
275         free(OneRNCFG);
276         *pOneRNCFG=NULL;
277 }
278