2 * This module handles shared rooms, inter-Citadel mail, and outbound
3 * mailing list processing.
5 * Copyright (c) 2000-2012 by the citadel.org team
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.
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.
23 # if HAVE_SYS_SYSCALL_H
24 # include <sys/syscall.h>
29 #include <libcitadel.h>
31 #include "include/ctdl_module.h"
32 HashList *CfgTypeHash = NULL;
33 HashList *RoomConfigs = NULL;
34 /*-----------------------------------------------------------------------------*
35 * Per room network configs *
36 *-----------------------------------------------------------------------------*/
37 void RegisterRoomCfgType(const char* Name, long len, RoomNetCfg eCfg, CfgLineParser p, int uniq, int nSegments, CfgLineSerializer s, CfgLineDeAllocator d)
41 pCfg = (CfgLineType*) malloc(sizeof(CfgLineType));
47 pCfg->IsSingleLine = uniq;
48 pCfg->nSegments = nSegments;
49 if (CfgTypeHash == NULL)
50 CfgTypeHash = NewHash(1, NULL);
51 Put(CfgTypeHash, Name, len, pCfg, NULL);
55 const CfgLineType *GetCfgTypeByStr(const char *Key, long len)
59 if (GetHash(CfgTypeHash, Key, len, &pv) && (pv != NULL))
61 return (const CfgLineType *) pv;
69 const CfgLineType *GetCfgTypeByEnum(RoomNetCfg eCfg, HashPos *It)
76 RewindHashPos(CfgTypeHash, It, 1);
77 while (GetNextHashPos(CfgTypeHash, It, &len, &Key, &pv) && (pv != NULL))
79 pCfg = (CfgLineType*) pv;
85 void ParseGeneric(const CfgLineType *ThisOne, StrBuf *Line, const char *LinePos, OneRoomNetCfg *OneRNCFG)
90 nptr = (RoomNetCfgLine *)
91 malloc(sizeof(RoomNetCfgLine));
92 nptr->next = OneRNCFG->NetConfigs[ThisOne->C];
93 nptr->Value = malloc(sizeof(StrBuf*) * ThisOne->nSegments);
94 memset(nptr->Value, 0, sizeof(StrBuf*) * ThisOne->nSegments);
95 if (ThisOne->nSegments == 1)
97 nptr->Value[0] = NewStrBufPlain(LinePos, StrLength(Line) - ( LinePos - ChrPtr(Line)) );
99 else for (i = 0; i < ThisOne->nSegments; i++)
101 nptr->Value[i] = NewStrBufPlain(NULL, StrLength(Line) - ( LinePos - ChrPtr(Line)) );
102 StrBufExtract_NextToken(nptr->Value[i], Line, &LinePos, '|');
105 OneRNCFG->NetConfigs[ThisOne->C] = nptr;
108 void SerializeGeneric(const CfgLineType *ThisOne, StrBuf *OutputBuffer, OneRoomNetCfg *OneRNCFG, RoomNetCfgLine *data)
112 StrBufAppendBufPlain(OutputBuffer, CKEY(ThisOne->Str), 0);
113 for (i = 0; i < ThisOne->nSegments; i++)
115 StrBufAppendBuf(OutputBuffer, data->Value[i], 0);
116 if (i + 1 < ThisOne->nSegments)
117 StrBufAppendBufPlain(OutputBuffer, HKEY("|"), 0);
119 StrBufAppendBufPlain(OutputBuffer, HKEY("\n"), 0);
122 void DeleteGenericCfgLine(const CfgLineType *ThisOne, RoomNetCfgLine **data)
126 for (i = 0; i < ThisOne->nSegments; i++)
128 FreeStrBuf(&(*data)->Value[i]);
130 free ((*data)->Value);
134 RoomNetCfgLine *DuplicateOneGenericCfgLine(const RoomNetCfgLine *data)
136 RoomNetCfgLine *NewData;
138 NewData = (RoomNetCfgLine*)malloc(sizeof(RoomNetCfgLine));
140 NewData->Value = (StrBuf **)malloc(sizeof(StrBuf*) * data->nValues);
142 for (i = 0; i < data->nValues; i++)
144 NewData->Value[i] = NewStrBufDup(data->Value[i]);
148 int ReadRoomNetConfigFile(OneRoomNetCfg **pOneRNCFG, char *filename)
151 const char *ErrStr = NULL;
153 const CfgLineType *pCfg;
156 OneRoomNetCfg *OneRNCFG;
158 fd = open(filename, O_NONBLOCK|O_RDONLY);
163 OneRNCFG = malloc(sizeof(OneRoomNetCfg));
164 memset(OneRNCFG, 0, sizeof(OneRoomNetCfg));
165 *pOneRNCFG = OneRNCFG;
168 while (StrBufTCP_read_line(Line, &fd, 0, &ErrStr) >= 0) {
169 if (StrLength(Line) == 0)
172 InStr = NewStrBufPlain(NULL, StrLength(Line));
173 StrBufExtract_NextToken(InStr, Line, &Pos, '|');
175 pCfg = GetCfgTypeByStr(SKEY(InStr));
178 pCfg->Parser(pCfg, Line, Pos, OneRNCFG);
182 if (OneRNCFG->misc == NULL)
184 OneRNCFG->misc = NewStrBufDup(Line);
188 if(StrLength(OneRNCFG->misc) > 0)
189 StrBufAppendBufPlain(OneRNCFG->misc, HKEY("\n"), 0);
190 StrBufAppendBuf(OneRNCFG->misc, Line, 0);
201 int SaveRoomNetConfigFile(OneRoomNetCfg *OneRNCFG, char *filename)
205 StrBuf *OutBuffer = NULL;
206 char tempfilename[PATH_MAX];
211 long reltid; /* if we don't have SYS_gettid, use "random" value */
215 len = strlen(filename);
216 memcpy(tempfilename, filename, len + 1);
218 #if defined(HAVE_SYSCALL_H) && defined (SYS_gettid)
219 reltid = syscall(SYS_gettid);
221 gettimeofday(&tv, NULL);
222 /* Promote to time_t; types differ on some OSes (like darwin) */
223 unixtime = tv.tv_sec;
225 sprintf(tempfilename + len, ".%ld-%ld", reltid, unixtime);
227 TmpFD = open(tempfilename, O_CREAT|O_EXCL|O_RDWR, S_IRUSR|S_IWUSR);
229 if ((TmpFD < 0) || (errno != 0)) {
230 syslog(LOG_CRIT, "ERROR: cannot open %s: %s\n",
231 filename, strerror(errno));
232 unlink(tempfilename);
237 OutBuffer = NewStrBuf();
238 CfgIt = GetNewHashPos(CfgTypeHash, 1);
239 fchown(TmpFD, config.c_ctdluid, 0);
240 for (eCfg = subpending; eCfg < maxRoomNetCfg; eCfg ++)
242 const CfgLineType *pCfg;
243 pCfg = GetCfgTypeByEnum(eCfg, CfgIt);
244 if (pCfg->IsSingleLine)
246 pCfg->Serializer(pCfg, OutBuffer, OneRNCFG, NULL);
250 RoomNetCfgLine *pName = OneRNCFG->NetConfigs[pCfg->C];
251 while (pName != NULL)
253 pCfg->Serializer(pCfg, OutBuffer, OneRNCFG, pName);
261 DeleteHashPos(&CfgIt);
264 if (OneRNCFG->misc != NULL) {
265 StrBufAppendBuf(OutBuffer, OneRNCFG->misc, 0);
268 rc = write(TmpFD, ChrPtr(OutBuffer), StrLength(OutBuffer));
269 if ((rc >=0 ) && (rc == StrLength(OutBuffer)))
273 rename(tempfilename, filename);
278 "unable to write %s; [%s]; not enough space on the disk?\n",
282 unlink(tempfilename);
285 FreeStrBuf(&OutBuffer);
292 void SaveModifiedRooms(struct ctdlroom *qrbuf, void *data, OneRoomNetCfg *OneRNCfg)
294 char filename[PATH_MAX];
296 if (OneRNCfg->changed)
298 assoc_file_name(filename, sizeof filename, qrbuf, ctdl_netcfg_dir);
299 SaveRoomNetConfigFile(OneRNCfg, filename);
300 OneRNCfg->changed = 0;
303 void SaveChangedConfigs(void)
305 CtdlForEachNetCfgRoom(SaveModifiedRooms,
311 void vFreeRoomNetworkStruct(void *vOneRoomNetCfg)
315 OneRoomNetCfg *OneRNCFG;
317 OneRNCFG = (OneRoomNetCfg*)vOneRoomNetCfg;
318 CfgIt = GetNewHashPos(CfgTypeHash, 1);
319 for (eCfg = subpending; eCfg < maxRoomNetCfg; eCfg ++)
321 const CfgLineType *pCfg;
322 RoomNetCfgLine *pNext, *pName;
324 pCfg = GetCfgTypeByEnum(eCfg, CfgIt);
325 pName= OneRNCFG->NetConfigs[pCfg->C];
326 while (pName != NULL)
329 pCfg->DeAllocator(pCfg, &pName);
333 DeleteHashPos(&CfgIt);
335 FreeStrBuf(&OneRNCFG->Sender);
336 FreeStrBuf(&OneRNCFG->RoomInfo);
337 FreeStrBuf(&OneRNCFG->misc);
340 void FreeRoomNetworkStruct(OneRoomNetCfg **pOneRNCFG)
342 vFreeRoomNetworkStruct(*pOneRNCFG);
346 OneRoomNetCfg* CtdlGetNetCfgForRoom(long QRNumber)
349 GetHash(RoomConfigs, LKEY(QRNumber), &pv);
350 return (OneRoomNetCfg*)pv;
354 void LoadAllNetConfigs(void)
358 struct dirent *filedir_entry;
362 OneRoomNetCfg *OneRNCFG;
367 RoomConfigs = NewHash(1, NULL);
368 filedir = opendir (ctdl_netcfg_dir);
369 if (filedir == NULL) {
370 return ; /// todo: panic!
373 d = (struct dirent *)malloc(offsetof(struct dirent, d_name) + PATH_MAX + 1);
379 while ((readdir_r(filedir, d, &filedir_entry) == 0) &&
380 (filedir_entry != NULL))
382 #ifdef _DIRENT_HAVE_D_NAMLEN
383 d_namelen = filedir_entry->d_namelen;
385 d_namelen = strlen(filedir_entry->d_name);
388 #ifdef _DIRENT_HAVE_D_TYPE
389 d_type = filedir_entry->d_type;
398 #define IFTODT(mode) (((mode) & 0170000) >> 12)
399 #define DTTOIF(dirtype) ((dirtype) << 12)
403 if ((d_namelen > 1) && filedir_entry->d_name[d_namelen - 1] == '~')
404 continue; /* Ignore backup files... */
406 if ((d_namelen == 1) &&
407 (filedir_entry->d_name[0] == '.'))
410 if ((d_namelen == 2) &&
411 (filedir_entry->d_name[0] == '.') &&
412 (filedir_entry->d_name[1] == '.'))
415 snprintf(path, PATH_MAX, "%s/%s",
416 ctdl_netcfg_dir, filedir_entry->d_name);
418 if (d_type == DT_UNKNOWN) {
420 if (lstat(path, &s) == 0) {
421 d_type = IFTODT(s.st_mode);
429 case DT_LNK: /* TODO: check whether its a file or a directory */
432 pch = filedir_entry->d_name;
443 RoomNumber = atol(filedir_entry->d_name);
444 ReadRoomNetConfigFile(&OneRNCFG, path);
446 if (OneRNCFG != NULL)
447 Put(RoomConfigs, LKEY(RoomNumber), OneRNCFG, vFreeRoomNetworkStruct);
449 /* syslog(9, "[%s | %s]\n", ChrPtr(OneWebName), ChrPtr(FileName)); */
463 /*-----------------------------------------------------------------------------*
464 * Per room network configs : exchange with client *
465 *-----------------------------------------------------------------------------*/
466 void cmd_gnet(char *argbuf)
468 char filename[PATH_MAX];
473 if (!IsEmptyStr(argbuf))
475 if (CtdlAccessCheck(ac_aide)) return;
476 if (strcmp(argbuf, FILE_MAILALIAS))
478 cprintf("%d No such file or directory\n",
479 ERROR + INTERNAL_ERROR);
482 safestrncpy(filename, file_mail_aliases, sizeof(filename));
483 cprintf("%d Settings for <%s>\n",
489 if ( (CC->room.QRflags & QR_MAILBOX) && (CC->user.usernum == atol(CC->room.QRname)) ) {
490 /* users can edit the netconfigs for their own mailbox rooms */
492 else if (CtdlAccessCheck(ac_room_aide)) return;
494 assoc_file_name(filename, sizeof filename, &CC->room, ctdl_netcfg_dir);
495 cprintf("%d Network settings for room #%ld <%s>\n",
497 CC->room.QRnumber, CC->room.QRname);
500 fp = fopen(filename, "r");
502 while (fgets(buf, sizeof buf, fp) != NULL) {
503 buf[strlen(buf)-1] = 0;
504 cprintf("%s\n", buf);
512 #define nForceAliases 5
513 const ConstStr ForceAliases[nForceAliases] = {
517 {HKEY("postmaster,")},
521 void cmd_snet(char *argbuf) {
522 char tempfilename[PATH_MAX];
523 char filename[PATH_MAX];
530 int MailAliasesFound[nForceAliases];
534 if (!IsEmptyStr(argbuf))
536 if (CtdlAccessCheck(ac_aide)) return;
537 if (strcmp(argbuf, FILE_MAILALIAS))
539 cprintf("%d No such file or directory\n",
540 ERROR + INTERNAL_ERROR);
543 len = safestrncpy(filename, file_mail_aliases, sizeof(filename));
544 memset(MailAliasesFound, 0, sizeof(MailAliasesFound));
545 memcpy(tempfilename, filename, len + 1);
550 if ( (CC->room.QRflags & QR_MAILBOX) && (CC->user.usernum == atol(CC->room.QRname)) ) {
551 /* users can edit the netconfigs for their own mailbox rooms */
553 else if (CtdlAccessCheck(ac_room_aide)) return;
555 len = assoc_file_name(filename, sizeof filename, &CC->room, ctdl_netcfg_dir);
556 memcpy(tempfilename, filename, len + 1);
558 memset(&StatBuf, 0, sizeof(struct stat));
559 if ((stat(filename, &StatBuf) == -1) || (StatBuf.st_size == 0))
560 StatBuf.st_size = 80; /* Not there or empty? guess 80 chars line. */
562 sprintf(tempfilename + len, ".%d", CC->cs_pid);
564 TmpFD = open(tempfilename, O_CREAT|O_EXCL|O_RDWR, S_IRUSR|S_IWUSR);
566 if ((TmpFD > 0) && (errno == 0))
568 char *tmp = malloc(StatBuf.st_size * 2);
569 memset(tmp, ' ', StatBuf.st_size * 2);
570 rc = write(TmpFD, tmp, StatBuf.st_size * 2);
572 if ((rc <= 0) || (rc != StatBuf.st_size * 2))
575 cprintf("%d Unable to allocate the space required for %s: %s\n",
576 ERROR + INTERNAL_ERROR,
579 unlink(tempfilename);
582 lseek(TmpFD, SEEK_SET, 0);
585 cprintf("%d Unable to allocate the space required for %s: %s\n",
586 ERROR + INTERNAL_ERROR,
589 unlink(tempfilename);
594 cprintf("%d %s\n", SEND_LISTING, tempfilename);
597 while (rc = CtdlClientGetLine(Line),
600 if ((rc == 3) && (strcmp(ChrPtr(Line), "000") == 0))
606 for (i = 0; i < nForceAliases; i++)
608 if ((!MailAliasesFound[i]) &&
609 (strncmp(ForceAliases[i].Key,
611 ForceAliases[i].len) == 0)
614 MailAliasesFound[i] = 1;
620 StrBufAppendBufPlain(Line, HKEY("\n"), 0);
621 write(TmpFD, ChrPtr(Line), StrLength(Line));
622 len += StrLength(Line);
625 ftruncate(TmpFD, len);
632 * Sanity check whether all aliases required by the RFCs were set
636 for (i = 0; i < nForceAliases; i++)
638 if (!MailAliasesFound[i])
643 cprintf("%d won't do this - you're missing an RFC required alias.\n",
644 ERROR + INTERNAL_ERROR);
645 unlink(tempfilename);
650 /* Now copy the temp file to its permanent location.
651 * (We copy instead of link because they may be on different filesystems)
653 begin_critical_section(S_NETCONFIGS);
654 rename(tempfilename, filename);
655 end_critical_section(S_NETCONFIGS);
659 /*-----------------------------------------------------------------------------*
660 * Per node network configs *
661 *-----------------------------------------------------------------------------*/
662 void DeleteCtdlNodeConf(void *vNode)
664 CtdlNodeConf *Node = (CtdlNodeConf*) vNode;
665 FreeStrBuf(&Node->NodeName);
666 FreeStrBuf(&Node->Secret);
667 FreeStrBuf(&Node->Host);
668 FreeStrBuf(&Node->Port);
672 CtdlNodeConf *NewNode(StrBuf *SerializedNode)
674 const char *Pos = NULL;
677 /* we need at least 4 pipes and some other text so its invalid. */
678 if (StrLength(SerializedNode) < 8)
680 Node = (CtdlNodeConf *) malloc(sizeof(CtdlNodeConf));
684 Node->NodeName=NewStrBuf();
685 StrBufExtract_NextToken(Node->NodeName, SerializedNode, &Pos, '|');
687 Node->Secret=NewStrBuf();
688 StrBufExtract_NextToken(Node->Secret, SerializedNode, &Pos, '|');
690 Node->Host=NewStrBuf();
691 StrBufExtract_NextToken(Node->Host, SerializedNode, &Pos, '|');
693 Node->Port=NewStrBuf();
694 StrBufExtract_NextToken(Node->Port, SerializedNode, &Pos, '|');
700 * Load or refresh the Citadel network (IGnet) configuration for this node.
702 HashList* CtdlLoadIgNetCfg(void)
711 Cfg = CtdlGetSysConfig(IGNETCFG);
712 if ((Cfg == NULL) || IsEmptyStr(Cfg)) {
718 Hash = NewHash(1, NULL);
719 Buf = NewStrBufPlain(Cfg, -1);
721 LineBuf = NewStrBufPlain(NULL, StrLength(Buf));
725 StrBufSipLine(LineBuf, Buf, &LinePos);
726 if (StrLength(LineBuf) != 0) {
727 Node = NewNode(LineBuf);
729 Put(Hash, SKEY(Node->NodeName), Node, DeleteCtdlNodeConf);
732 } while (LinePos != StrBufNOTNULL);
734 FreeStrBuf(&LineBuf);
739 int is_recipient(OneRoomNetCfg *RNCfg, const char *Name)
741 const RoomNetCfg RecipientCfgs[] = {
748 RoomNetCfgLine *nptr;
753 while (RecipientCfgs[i] != maxRoomNetCfg)
755 nptr = RNCfg->NetConfigs[RecipientCfgs[i]];
759 if ((StrLength(nptr->Value[0]) == len) &&
760 (!strcmp(Name, ChrPtr(nptr->Value[0]))))
772 int CtdlNetconfigCheckRoomaccess(
775 const char* RemoteIdentifier)
777 OneRoomNetCfg *RNCfg;
781 if (RemoteIdentifier == NULL)
783 snprintf(errmsgbuf, n, "Need sender to permit access.");
784 return (ERROR + USERNAME_REQUIRED);
787 assoc_file_name(filename, sizeof filename, &CC->room, ctdl_netcfg_dir);
788 begin_critical_section(S_NETCONFIGS);
789 if (!ReadRoomNetConfigFile(&RNCfg, filename))
791 end_critical_section(S_NETCONFIGS);
792 snprintf(errmsgbuf, n,
793 "This mailing list only accepts posts from subscribers.");
794 return (ERROR + NO_SUCH_USER);
796 end_critical_section(S_NETCONFIGS);
797 found = is_recipient (RNCfg, RemoteIdentifier);
798 vFreeRoomNetworkStruct(&RNCfg);
803 snprintf(errmsgbuf, n,
804 "This mailing list only accepts posts from subscribers.");
805 return (ERROR + NO_SUCH_USER);
812 * cmd_netp() - authenticate to the server as another Citadel node polling
813 * for network traffic
815 void cmd_netp(char *cmdbuf)
817 struct CitContext *CCC = CC;
818 HashList *working_ignetcfg;
826 const StrBuf *secret = NULL;
827 const StrBuf *nexthop = NULL;
828 char err_buf[SIZ] = "";
831 node = CCC->curr_user;
832 nodelen = extract_token(CCC->curr_user, cmdbuf, 0, '|', sizeof CCC->curr_user);
833 NodeStr = NewStrBufPlain(node, nodelen);
834 /* load the IGnet Configuration to check node validity */
835 working_ignetcfg = CtdlLoadIgNetCfg();
836 v = CtdlIsValidNode(&nexthop, &secret, NodeStr, working_ignetcfg, NULL);
838 snprintf(err_buf, sizeof err_buf,
839 "An unknown Citadel server called \"%s\" attempted to connect from %s [%s].\n",
840 node, CCC->cs_host, CCC->cs_addr
842 syslog(LOG_WARNING, "%s", err_buf);
843 cprintf("%d authentication failed\n", ERROR + PASSWORD_REQUIRED);
845 strs[0] = CCC->cs_addr;
846 lens[0] = strlen(CCC->cs_addr);
848 strs[1] = "SRV_UNKNOWN";
849 lens[1] = sizeof("SRV_UNKNOWN" - 1);
854 2, strs, (long*) &lens);
856 DeleteHash(&working_ignetcfg);
857 FreeStrBuf(&NodeStr);
861 extract_token(CCC->user.password, cmdbuf, 1, '|', sizeof CCC->user.password);
862 if (strcasecmp(CCC->user.password, ChrPtr(secret))) {
863 snprintf(err_buf, sizeof err_buf,
864 "A Citadel server at %s [%s] failed to authenticate as network node \"%s\".\n",
865 CCC->cs_host, CCC->cs_addr, node
867 syslog(LOG_WARNING, "%s", err_buf);
868 cprintf("%d authentication failed\n", ERROR + PASSWORD_REQUIRED);
870 strs[0] = CCC->cs_addr;
871 lens[0] = strlen(CCC->cs_addr);
874 lens[1] = sizeof("SRV_PW" - 1);
879 2, strs, (long*) &lens);
881 DeleteHash(&working_ignetcfg);
882 FreeStrBuf(&NodeStr);
886 if (CtdlNetworkTalkingTo(node, nodelen, NTT_CHECK)) {
887 syslog(LOG_WARNING, "Duplicate session for network node <%s>", node);
888 cprintf("%d Already talking to %s right now\n", ERROR + RESOURCE_BUSY, node);
889 DeleteHash(&working_ignetcfg);
890 FreeStrBuf(&NodeStr);
893 nodelen = safestrncpy(CCC->net_node, node, sizeof CCC->net_node);
894 CtdlNetworkTalkingTo(CCC->net_node, nodelen, NTT_ADD);
895 syslog(LOG_NOTICE, "Network node <%s> logged in from %s [%s]\n",
896 CCC->net_node, CCC->cs_host, CCC->cs_addr
898 cprintf("%d authenticated as network node '%s'\n", CIT_OK, CCC->net_node);
899 DeleteHash(&working_ignetcfg);
900 FreeStrBuf(&NodeStr);
904 /*-----------------------------------------------------------------------------*
905 * Network maps: evaluate other nodes *
906 *-----------------------------------------------------------------------------*/
908 void DeleteNetMap(void *vNetMap)
910 CtdlNetMap *TheNetMap = (CtdlNetMap*) vNetMap;
911 FreeStrBuf(&TheNetMap->NodeName);
912 FreeStrBuf(&TheNetMap->NextHop);
916 CtdlNetMap *NewNetMap(StrBuf *SerializedNetMap)
918 const char *Pos = NULL;
921 /* we need at least 3 pipes and some other text so its invalid. */
922 if (StrLength(SerializedNetMap) < 6)
924 NM = (CtdlNetMap *) malloc(sizeof(CtdlNetMap));
926 NM->NodeName=NewStrBuf();
927 StrBufExtract_NextToken(NM->NodeName, SerializedNetMap, &Pos, '|');
929 NM->lastcontact = StrBufExtractNext_long(SerializedNetMap, &Pos, '|');
931 NM->NextHop=NewStrBuf();
932 StrBufExtract_NextToken(NM->NextHop, SerializedNetMap, &Pos, '|');
937 HashList* CtdlReadNetworkMap(void)
944 CtdlNetMap *TheNetMap;
946 Hash = NewHash(1, NULL);
947 Cfg = CtdlGetSysConfig(IGNETMAP);
948 if ((Cfg == NULL) || IsEmptyStr(Cfg)) {
954 Buf = NewStrBufPlain(Cfg, -1);
956 LineBuf = NewStrBufPlain(NULL, StrLength(Buf));
958 while (StrBufSipLine(Buf, LineBuf, &LinePos))
960 TheNetMap = NewNetMap(LineBuf);
961 if (TheNetMap != NULL) { /* TODO: is the NodeName Uniq? */
962 Put(Hash, SKEY(TheNetMap->NodeName), TheNetMap, DeleteNetMap);
966 FreeStrBuf(&LineBuf);
970 StrBuf *CtdlSerializeNetworkMap(HashList *Map)
975 StrBuf *Ret = NewStrBuf();
976 HashPos *Pos = GetNewHashPos(Map, 0);
978 while (GetNextHashPos(Map, Pos, &len, &key, &vMap))
980 CtdlNetMap *pMap = (CtdlNetMap*) vMap;
981 StrBufAppendBuf(Ret, pMap->NodeName, 0);
982 StrBufAppendBufPlain(Ret, HKEY("|"), 0);
984 StrBufAppendPrintf(Ret, "%ld", pMap->lastcontact, 0);
985 StrBufAppendBufPlain(Ret, HKEY("|"), 0);
987 StrBufAppendBuf(Ret, pMap->NextHop, 0);
988 StrBufAppendBufPlain(Ret, HKEY("\n"), 0);
996 * Learn topology from path fields
998 void NetworkLearnTopology(char *node, char *path, HashList *the_netmap, int *netmap_changed)
1000 CtdlNetMap *pNM = NULL;
1005 if (GetHash(the_netmap, node, strlen(node), &vptr) &&
1006 (vptr != NULL))/* TODO: is the NodeName Uniq? */
1008 pNM = (CtdlNetMap*)vptr;
1009 extract_token(nexthop, path, 0, '!', sizeof nexthop);
1010 if (!strcmp(nexthop, ChrPtr(pNM->NextHop))) {
1011 pNM->lastcontact = time(NULL);
1012 (*netmap_changed) ++;
1017 /* If we got here then it's not in the map, so add it. */
1018 nmptr = (CtdlNetMap *) malloc(sizeof (CtdlNetMap));
1019 nmptr->NodeName = NewStrBufPlain(node, -1);
1020 nmptr->lastcontact = time(NULL);
1021 nmptr->NextHop = NewStrBuf ();
1022 StrBufExtract_tokenFromStr(nmptr->NextHop, path, strlen(path), 0, '!');
1023 /* TODO: is the NodeName Uniq? */
1024 Put(the_netmap, SKEY(nmptr->NodeName), nmptr, DeleteNetMap);
1025 (*netmap_changed) ++;
1030 * Check the network map and determine whether the supplied node name is
1031 * valid. If it is not a neighbor node, supply the name of a neighbor node
1032 * which is the next hop. If it *is* a neighbor node, we also fill in the
1035 int CtdlIsValidNode(const StrBuf **nexthop,
1036 const StrBuf **secret,
1039 HashList *the_netmap)
1043 CtdlNodeConf *TheNode;
1044 CtdlNetMap *TheNetMap;
1046 if (StrLength(node) == 0) {
1051 * First try the neighbor nodes
1053 if (GetCount(IgnetCfg) == 0) {
1054 syslog(LOG_INFO, "IgnetCfg is empty!\n");
1055 if (nexthop != NULL) {
1061 /* try to find a neigbour with the name 'node' */
1062 if (GetHash(IgnetCfg, SKEY(node), &vNodeConf) &&
1063 (vNodeConf != NULL))
1065 TheNode = (CtdlNodeConf*)vNodeConf;
1067 *secret = TheNode->Secret;
1068 return 0; /* yup, it's a direct neighbor */
1072 * If we get to this point we have to see if we know the next hop
1073 *//* TODO: is the NodeName Uniq? */
1074 if ((GetCount(the_netmap) > 0) &&
1075 (GetHash(the_netmap, SKEY(node), &vNetMap)))
1077 TheNetMap = (CtdlNetMap*)vNetMap;
1078 if (nexthop != NULL)
1079 *nexthop = TheNetMap->NextHop;
1084 * If we get to this point, the supplied node name is bogus.
1086 syslog(LOG_ERR, "Invalid node name <%s>\n", ChrPtr(node));
1094 * Module entry point
1096 CTDL_MODULE_INIT(netconfig)
1100 LoadAllNetConfigs ();
1101 CtdlRegisterProtoHook(cmd_gnet, "GNET", "Get network config");
1102 CtdlRegisterProtoHook(cmd_snet, "SNET", "Set network config");
1103 CtdlRegisterProtoHook(cmd_netp, "NETP", "Identify as network poller");