2 * Citadel/UX Intelligent Network Processor for IGnet/Open networks
3 * See copyright.txt for copyright information
7 /* How long it takes for an old node to drop off the network map */
8 #define EXPIRY_TIME (2592000L)
10 /* Where do we keep our lock file? */
11 #define LOCKFILE "/var/lock/LCK.netproc"
13 /* Path to the 'uudecode' utility (needed for network file transfers) */
14 #define UUDECODE "/usr/bin/uudecode"
16 /* Uncomment the DEBUG def to see noisy traces */
23 #include <sys/types.h>
37 /* A list of users you wish to filter out of incoming traffic can be kept
38 * in ./network/filterlist -- messages from these users will be automatically
39 * moved to FILTERROOM. Normally this will be the same as TWITROOM (the
40 * room problem user messages are moved to) but you can override this by
41 * specifying a different room name here.
44 #define FILTERROOM TWITROOM
50 char m_rmname[ROOMNAMELEN];
55 char rm_name[ROOMNAMELEN];
60 struct filterlist *next;
77 void attach_to_server(int argc, char **argv);
78 void serv_read(char *buf, int bytes);
79 void serv_write(char *buf, int nbytes);
80 void get_config(void);
82 struct filterlist *filter = NULL;
83 struct syslist *slist = NULL;
86 extern char bbs_home_directory[];
87 extern int home_specified;
92 * replacement strerror() for systems that don't have it
98 sprintf(buf, "errno = %d", e);
104 void strip_trailing_whitespace(char *buf)
106 while (isspace(buf[strlen(buf) - 1]))
107 buf[strlen(buf) - 1] = 0;
112 * we also load the network/mail.sysinfo table into memory, make changes
113 * as we learn more about the network from incoming messages, and write
114 * the table back to disk when we're done.
116 int load_syslist(void)
119 struct syslist *stemp;
123 fp = fopen("network/mail.sysinfo", "r");
128 if (fgets(buf, 128, fp) == NULL) {
132 buf[strlen(buf) - 1] = 0;
133 while (isspace(buf[0]))
134 strcpy(buf, &buf[1]);
137 if ((insys == 0) && (strlen(buf) != 0)) {
139 stemp = (struct syslist *) malloc(sizeof(struct syslist));
142 strcpy(slist->s_name, buf);
143 strcpy(slist->s_type, "bin");
144 strcpy(slist->s_nexthop, "Mail");
145 slist->s_lastcontact = 0L;
146 strcpy(slist->s_humannode, "");
147 strcpy(slist->s_phonenum, "");
148 strcpy(slist->s_gdom, "");
149 } else if ((insys == 1) && (strlen(buf) == 0)) {
151 } else if ((insys == 1) && (!strncasecmp(buf, "bin", 3))) {
152 strcpy(slist->s_type, "bin");
153 strcpy(slist->s_nexthop, &buf[4]);
154 } else if ((insys == 1) && (!strncasecmp(buf, "use", 3))) {
155 strcpy(slist->s_type, "use");
156 strcpy(slist->s_nexthop, &buf[4]);
157 } else if ((insys == 1) && (!strncasecmp(buf, "uum", 3))) {
158 strcpy(slist->s_type, "uum");
159 strcpy(slist->s_nexthop, &buf[4]);
160 } else if ((insys == 1) && (!strncasecmp(buf, "lastcontact", 11))) {
162 sscanf(&buf[12], "%ld", &foo);
163 slist->s_lastcontact = foo;
164 } else if ((insys == 1) && (!strncasecmp(buf, "humannode", 9))) {
165 strcpy(slist->s_humannode, &buf[10]);
166 } else if ((insys == 1) && (!strncasecmp(buf, "phonenum", 8))) {
167 strcpy(slist->s_phonenum, &buf[9]);
168 } else if ((insys == 1) && (!strncasecmp(buf, "gdom", 4))) {
169 strcpy(slist->s_gdom, &buf[5]);
174 /* now we have to set up two "special" nodes on the list: one
175 * for the local node, and one for an Internet gateway
177 void setup_special_nodes(void)
179 struct syslist *stemp, *slocal;
182 for (stemp = slist; stemp != NULL; stemp = stemp->next) {
183 if (!strcasecmp(stemp->s_name, config.c_nodename))
186 if (slocal == NULL) {
187 slocal = (struct syslist *) malloc(sizeof(struct syslist));
188 slocal->next = slist;
191 strcpy(slocal->s_name, config.c_nodename);
192 strcpy(slocal->s_type, "bin");
193 strcpy(slocal->s_nexthop, "Mail");
194 time(&slocal->s_lastcontact);
195 strcpy(slocal->s_humannode, config.c_humannode);
196 strcpy(slocal->s_phonenum, config.c_phonenum);
199 for (stemp = slist; stemp != NULL; stemp = stemp->next) {
200 if (!strcasecmp(stemp->s_name, "internet"))
203 if (slocal == NULL) {
204 slocal = (struct syslist *) malloc(sizeof(struct syslist));
205 slocal->next = slist;
208 strcpy(slocal->s_name, "internet");
209 strcpy(slocal->s_type, "uum");
210 strcpy(slocal->s_nexthop, "%s");
211 time(&slocal->s_lastcontact);
212 strcpy(slocal->s_humannode, "Internet Gateway");
213 strcpy(slocal->s_phonenum, "");
214 strcpy(slocal->s_gdom, "");
219 * here's the routine to write the table back to disk.
221 void rewrite_syslist(void)
223 struct syslist *stemp;
228 newfp = fopen("network/mail.sysinfo", "w");
229 for (stemp = slist; stemp != NULL; stemp = stemp->next) {
230 if (!strcasecmp(stemp->s_name, config.c_nodename)) {
231 time(&stemp->s_lastcontact);
232 strcpy(stemp->s_type, "bin");
233 strcpy(stemp->s_humannode, config.c_humannode);
234 strcpy(stemp->s_phonenum, config.c_phonenum);
236 /* remove systems we haven't heard from in a while */
237 if ((stemp->s_lastcontact == 0L)
238 || (now - stemp->s_lastcontact < EXPIRY_TIME)) {
239 fprintf(newfp, "%s\n%s %s\n",
240 stemp->s_name, stemp->s_type, stemp->s_nexthop);
241 if (strlen(stemp->s_phonenum) > 0)
242 fprintf(newfp, "phonenum %s\n", stemp->s_phonenum);
243 if (strlen(stemp->s_gdom) > 0)
244 fprintf(newfp, "gdom %s\n", stemp->s_gdom);
245 if (strlen(stemp->s_humannode) > 0)
246 fprintf(newfp, "humannode %s\n", stemp->s_humannode);
247 if (stemp->s_lastcontact > 0L)
248 fprintf(newfp, "lastcontact %ld %s",
249 (long) stemp->s_lastcontact,
250 asctime(localtime(&stemp->s_lastcontact)));
251 fprintf(newfp, "\n");
255 /* now free the list */
256 while (slist != NULL) {
264 /* call this function with the node name of a system and it returns a pointer
265 * to its syslist structure.
267 struct syslist *get_sys_ptr(char *sysname)
269 static char sysnambuf[16];
270 static struct syslist *sysptrbuf = NULL;
271 struct syslist *stemp;
273 if ((!strcmp(sysname, sysnambuf))
274 && (sysptrbuf != NULL))
277 strcpy(sysnambuf, sysname);
278 for (stemp = slist; stemp != NULL; stemp = stemp->next) {
279 if (!strcmp(sysname, stemp->s_name)) {
290 * make sure only one copy of netproc runs at a time, using lock files
292 int set_lockfile(void)
297 if ((lfp = fopen(LOCKFILE, "r")) != NULL) {
298 fscanf(lfp, "%d", &onppid);
300 if (!kill(onppid, 0) || errno == EPERM)
303 lfp = fopen(LOCKFILE, "w");
304 fprintf(lfp, "%ld\n", (long) getpid());
309 void remove_lockfile(void)
315 * Why both cleanup() and nq_cleanup() ? Notice the alarm() call in
316 * cleanup() . If for some reason netproc hangs waiting for the server
317 * to clean up, the alarm clock goes off and the program exits anyway.
318 * The cleanup() routine makes a check to ensure it's not reentering, in
319 * case the ipc module looped it somehow.
321 void nq_cleanup(int e)
330 static int nested = 0;
333 signal(SIGALRM, nq_cleanup);
340 * This is implemented as a function rather than as a macro because the
341 * client-side IPC modules expect logoff() to be defined. They call logoff()
342 * when a problem connecting or staying connected to the server occurs.
350 * If there is a kill file in place, this function will process it.
352 void load_filterlist(void)
355 struct filterlist *fbuf;
358 fp = fopen("./network/filterlist", "r");
361 while (fgets(sbuf, 256, fp) != NULL) {
362 if (sbuf[0] != '#') {
363 sbuf[strlen(sbuf) - 1] = 0;
364 fbuf = (struct filterlist *)
365 malloc((long) sizeof(struct filterlist));
368 strcpy(fbuf->f_person, "*");
369 strcpy(fbuf->f_room, "*");
370 strcpy(fbuf->f_system, "*");
372 for (a = strlen(sbuf); a >= 0; --a)
377 strcpy(fbuf->f_person, sbuf);
378 strcpy(sbuf, &sbuf[p + 1]);
380 for (a = strlen(sbuf); a >= 0; --a)
385 strcpy(fbuf->f_room, sbuf);
386 strcpy(sbuf, &sbuf[p + 1]);
388 strcpy(fbuf->f_system, sbuf);
394 /* returns 1 if user/message/room combination is in the kill file */
395 int is_banned(char *k_person, char *k_room, char *k_system)
397 struct filterlist *fptr;
399 for (fptr = filter; fptr != NULL; fptr = fptr->next)
401 ((!strcasecmp(fptr->f_person, k_person)) || (!strcmp(fptr->f_person, "*")))
403 ((!strcasecmp(fptr->f_room, k_room)) || (!strcmp(fptr->f_room, "*")))
405 ((!strcasecmp(fptr->f_system, k_system)) || (!strcmp(fptr->f_system, "*")))
412 int get_sysinfo_type(char *name)
413 { /* determine routing from sysinfo file */
414 struct syslist *stemp;
415 GETSN:for (stemp = slist; stemp != NULL; stemp = stemp->next) {
416 if (!strcasecmp(stemp->s_name, name)) {
417 if (!strcasecmp(stemp->s_type, "use")) {
418 strcpy(name, stemp->s_nexthop);
421 if (!strcasecmp(stemp->s_type, "bin")) {
424 if (!strcasecmp(stemp->s_type, "uum")) {
425 return (MES_INTERNET);
429 syslog(LOG_ERR, "cannot find system '%s' in mail.sysinfo", name);
434 void fpgetfield(FILE * fp, char *string)
454 * Load all of the fields of a message, except the actual text, into a
455 * table in memory (so we know how to process the message).
457 void msgfind(char *msgfile, struct minfo *buffer)
459 int b, e, mtype, aflag;
465 fp = fopen(msgfile, "rb");
467 syslog(LOG_ERR, "can't open message file: %s", strerror(errno));
472 syslog(LOG_ERR, "incorrect message format");
491 while ((bbb[0] == ' ') && (strlen(bbb) > 1))
492 strcpy(bbb, &bbb[1]);
494 strcpy(buffer->A, bbb);
495 if (strlen(userid) == 0) {
497 for (e = 0; e < strlen(userid); ++e)
498 if (userid[e] == ' ')
503 strcpy(buffer->O, bbb);
505 strcpy(buffer->C, bbb);
507 strcpy(buffer->N, bbb);
509 strcpy(buffer->S, bbb);
511 /* extract the user id from the path */
512 for (e = 0; e < strlen(bbb); ++e)
514 strcpy(userid, &bbb[e + 1]);
516 /* now find the next hop */
517 for (e = 0; e < strlen(bbb); ++e)
520 strcpy(buffer->nexthop, bbb);
523 for (e = 0; e < strlen(bbb); ++e)
526 strcpy(buffer->R, bbb);
529 strcpy(buffer->D, bbb);
531 buffer->T = atol(bbb);
533 buffer->I = atol(bbb);
535 strcpy(buffer->H, bbb);
537 strcpy(buffer->B, bbb);
539 strcpy(buffer->G, bbb);
541 strcpy(buffer->E, bbb);
544 END:if (buffer->I == 0L)
545 buffer->I = buffer->T;
549 void ship_to(char *filenm, char *sysnm)
550 { /* send spool file filenm to system sysnm */
557 syslog(LOG_NOTICE, "shipping %s to %s", filenm, sysnm);
559 sprintf(sysflnm, "./network/systems/%s", sysnm);
560 sysflfd = fopen(sysflnm, "r");
562 syslog(LOG_ERR, "cannot open %s", sysflnm);
563 fgets(commbuf1, 99, sysflfd);
564 commbuf1[strlen(commbuf1) - 1] = 0;
566 sprintf(commbuf2, commbuf1, filenm);
571 * proc_file_transfer() - handle a simple file transfer packet
574 void proc_file_transfer(char *tname)
575 { /* name of temp file containing the whole message */
577 char dest_room[ROOMNAMELEN];
578 char subdir_name[256];
582 syslog(LOG_NOTICE, "processing network file transfer...");
584 tfp = fopen(tname, "rb");
586 syslog(LOG_ERR, "cannot open %s", tname);
593 fpgetfield(tfp, buf);
595 strcpy(dest_room, buf);
598 } while ((a != 'M') && (a >= 0));
601 syslog(LOG_ERR, "no message text for file transfer");
604 strcpy(subdir_name, "---xxx---");
605 sprintf(buf, "GOTO %s", dest_room);
609 extract(subdir_name, &buf[4], 2);
610 if (strlen(subdir_name) == 0)
611 strcpy(subdir_name, "--xxx--");
613 /* Change to the room's directory; if that fails, change to the
614 * bitbucket directory. Then run uudecode.
616 sprintf(buf, "(cd %s/files/%s || cd %s/files/%s ) ; exec %s",
617 bbs_home_directory, subdir_name,
618 bbs_home_directory, config.c_bucket_dir,
621 uud = (FILE *) popen(buf, "w");
623 syslog(LOG_ERR, "cannot open uudecode pipe");
627 fgets(buf, 128, tfp);
628 buf[strlen(buf) - 1] = 0;
629 for (a = 0; a < strlen(buf); ++a)
632 fprintf(uud, "%s\n", buf);
633 printf("netproc: %s\n", buf);
634 while (a = getc(tfp), a > 0)
642 /* send a bounce message */
643 void bounce(struct minfo *bminfo)
651 sprintf(bfilename, "./network/spoolin/bounce.%ld.%d", (long) getpid(),
653 bounce = fopen(bfilename, "wb");
656 fprintf(bounce, "%c%c%c", 0xFF, MES_NORMAL, 0);
657 fprintf(bounce, "Ppostmaster%c", 0);
658 fprintf(bounce, "T%ld%c", (long) now, 0);
659 fprintf(bounce, "APostmaster%c", 0);
660 fprintf(bounce, "OMail%c", 0);
661 fprintf(bounce, "N%s%c", config.c_nodename, 0);
662 fprintf(bounce, "H%s%c", config.c_humannode, 0);
664 if (strlen(bminfo->E) > 0) {
665 fprintf(bounce, "R%s%c", bminfo->E, 0);
667 fprintf(bounce, "R%s%c", bminfo->A, 0);
670 fprintf(bounce, "D%s%c", bminfo->N, 0);
671 fprintf(bounce, "M%s could not deliver your mail to:\n",
673 fprintf(bounce, " \n %s\n \n", bminfo->R);
674 fprintf(bounce, " because there is no such user on this system.\n");
675 fprintf(bounce, " (Unsent message does *not* follow. ");
676 fprintf(bounce, "Help to conserve bandwidth.)\n%c", 0);
685 * Purge any old entries out of the use table
687 void purge_use_table(GDBM_FILE ut) {
690 /* FIX ... this isn't even close to being finished yet.
691 * Here's what needs to be done:
692 * 1. Write an entry for each received message into the table
693 * 2. Check incoming messages against the table
694 * 3. Post a list of rejected messages
695 * 4. Purge entries more than a few days old
703 * process incoming files in ./network/spoolin
707 FILE *fp, *message, *testfp, *ls;
708 static struct minfo minfo;
709 struct recentmsg recentmsg;
710 char tname[128], aaa[1024], iname[256], sfilename[256], pfilename[256];
713 struct syslist *stemp;
720 /* temp file names */
721 sprintf(tname, tmpnam(NULL));
722 sprintf(iname, tmpnam(NULL));
726 /* Make sure we're in the right directory */
727 chdir(bbs_home_directory);
729 /* Open the use table */
730 use_table = gdbm_open("./data/usetable.gdbm", 512,
731 GDBM_WRCREAT, 0600, 0);
732 if (use_table == NULL) {
733 syslog(LOG_ERR, "could not open use table: %s",
736 /* Let the shell do the dirty work. Get all data from spoolin */
738 sprintf(aaa, "cd %s/network/spoolin; ls", bbs_home_directory);
739 ls = popen(aaa, "r");
741 syslog(LOG_ERR, "could not open dir cmd: %s", strerror(errno));
745 SKIP: ptr = fgets(sfilename, sizeof sfilename, ls);
747 sfilename[strlen(sfilename) - 1] = 0;
748 if (!strcmp(sfilename, ".")) goto SKIP;
749 if (!strcmp(sfilename, "..")) goto SKIP;
750 if (!strcmp(sfilename, "CVS")) goto SKIP;
753 } while (ptr != NULL);
754 PROCESS_IT: pclose(ls);
757 sprintf(pfilename, "%s/network/spoolin/%s", bbs_home_directory, sfilename);
758 syslog(LOG_NOTICE, "processing <%s>", pfilename);
760 fp = fopen(pfilename, "rb");
762 syslog(LOG_ERR, "cannot open %s: %s", pfilename, strerror(errno));
763 fp = fopen("/dev/null", "rb");
765 NXMSG: /* Seek to the beginning of the next message */
768 } while ((a != 255) && (a >= 0));
772 /* This crates the temporary file. */
773 message = fopen(tname, "wb");
774 if (message == NULL) {
775 syslog(LOG_ERR, "error creating %s: %s", tname, strerror(errno));
778 putc(255, message); /* 0xFF (start-of-message) */
780 putc(a, message); /* type */
782 putc(a, message); /* mode */
784 FieldID = getc(fp); /* Header field ID */
785 putc(FieldID, message);
790 } while ((FieldID != 'M') && (a >= 0));
791 /* M is always last */
793 msglen = ftell(message);
796 /* process the individual mesage */
802 msgfind(tname, &minfo);
803 strncpy(recentmsg.RMnodename, minfo.N, 9);
804 recentmsg.RMnodename[9] = 0;
805 recentmsg.RMnum = minfo.I;
806 syslog(LOG_NOTICE, "#%ld fm <%s> in <%s> @ <%s>",
807 minfo.I, minfo.A, minfo.O, minfo.N);
808 if (strlen(minfo.R) > 0) {
809 syslog(LOG_NOTICE, " to <%s>", minfo.R);
810 if (strlen(minfo.D) > 0) {
811 syslog(LOG_NOTICE, " @ <%s>",
815 if (!strcasecmp(minfo.D, FQDN))
816 strcpy(minfo.D, NODENAME);
818 /* this routine updates our info on the system that sent the message */
819 stemp = get_sys_ptr(minfo.N);
820 if ((stemp == NULL) && (get_sys_ptr(minfo.nexthop) != NULL)) {
821 /* add non-neighbor system to map */
822 syslog(LOG_NOTICE, "Adding non-neighbor system <%s> to map",
824 stemp = (struct syslist *) malloc((long) sizeof(struct syslist));
827 strcpy(slist->s_name, minfo.N);
828 strcpy(slist->s_type, "use");
829 strcpy(slist->s_nexthop, minfo.nexthop);
830 time(&slist->s_lastcontact);
831 } else if ((stemp == NULL) && (!strcasecmp(minfo.N, minfo.nexthop))) {
832 /* add neighbor system to map */
833 syslog(LOG_NOTICE, "Adding neighbor system <%s> to map",
835 sprintf(aaa, "%s/network/systems/%s", bbs_home_directory, minfo.N);
836 testfp = fopen(aaa, "r");
837 if (testfp != NULL) {
839 stemp = (struct syslist *)
840 malloc((long) sizeof(struct syslist));
843 strcpy(slist->s_name, minfo.N);
844 strcpy(slist->s_type, "bin");
845 strcpy(slist->s_nexthop, "Mail");
846 time(&slist->s_lastcontact);
849 /* now update last contact and long node name if we can */
851 time(&stemp->s_lastcontact);
852 if (strlen(minfo.H) > 0)
853 strcpy(stemp->s_humannode, minfo.H);
854 if (strlen(minfo.B) > 0)
855 strcpy(stemp->s_phonenum, minfo.B);
856 if (strlen(minfo.G) > 0)
857 strcpy(stemp->s_gdom, minfo.G);
859 /* route the message if necessary */
860 if ((strcasecmp(minfo.D, NODENAME)) && (minfo.D[0] != 0)) {
861 a = get_sysinfo_type(minfo.D);
862 syslog(LOG_NOTICE, "routing message to system <%s>", minfo.D);
864 if (a == MES_INTERNET) {
866 syslog(LOG_NOTICE, "netmailer %s", tname);
868 execlp("./netmailer", "netmailer",
870 syslog(LOG_ERR, "error running netmailer: %s",
874 while (wait(&b) != (-1));
875 } else if (a == MES_BINARY) {
876 ship_to(tname, minfo.D);
878 /* message falls into the bit bucket? */
881 /* check to see if it's a file transfer */
882 else if (!strncasecmp(minfo.S, "FILE", 4)) {
883 proc_file_transfer(tname);
885 /* otherwise process it as a normal message */
888 if (!strcasecmp(minfo.R, "postmaster")) {
890 strcpy(minfo.C, "Aide");
892 if (strlen(minfo.R) > 0) {
893 sprintf(buf, "GOTO _MAIL_");
895 if (is_banned(minfo.A, minfo.C, minfo.N)) {
896 sprintf(buf, "GOTO %s", FILTERROOM);
898 if (strlen(minfo.C) > 0) {
899 sprintf(buf, "GOTO %s", minfo.C);
901 sprintf(buf, "GOTO %s", minfo.O);
907 syslog(LOG_ERR, "%s", buf);
908 sprintf(buf, "GOTO _BITBUCKET_");
912 /* Open the temporary file containing the message */
913 message = fopen(tname, "rb");
914 if (message == NULL) {
915 syslog(LOG_ERR, "cannot open %s: %s",
916 tname, strerror(errno));
920 /* Transmit the message to the server */
921 sprintf(buf, "ENT3 1|%s|%ld", minfo.R, msglen);
924 if (!strncmp(buf, "570", 3)) {
925 /* no such user, do a bounce */
929 /* Always use the server's idea of the message length,
930 * even though they should both be identical */
931 msglen = atol(&buf[4]);
932 while (msglen > 0L) {
933 bloklen = ((msglen >= 255L) ? 255 : ((int) msglen));
934 if (fread(buf, bloklen, 1, message) < 1) {
936 "error trying to read %d bytes: %s",
937 bloklen, strerror(errno));
939 serv_write(buf, bloklen);
940 msglen = msglen - (long) bloklen;
945 syslog(LOG_ERR, "%s", buf);
957 } while (ptr != NULL);
960 purge_use_table(use_table);
961 gdbm_close(use_table);
965 /* Checks to see whether its ok to send */
966 /* Returns 1 for ok, send message */
967 /* Returns 0 if message already there */
968 int checkpath(char *path, char *sys)
976 syslog(LOG_NOTICE, "checkpath <%s> <%s> ... ", path, sys);
978 for (a = 0; a < strlen(path); ++a) {
979 if (!strncmp(&path[a], sys2, strlen(sys2)))
986 * implement split horizon algorithm
988 int ismsgok(long int mpos, FILE * mmfp, char *sysname)
991 int ok = 0; /* fail safe - no path, don't send it */
994 fseek(mmfp, mpos, 0);
995 if (getc(mmfp) != 255)
1000 while (a = getc(mmfp), ((a != 'M') && (a != 0))) {
1001 fpgetfield(mmfp, fbuf);
1003 ok = checkpath(fbuf, sysname);
1007 syslog(LOG_NOTICE, "%s", ((ok) ? "SEND" : "(no)"));
1014 /* spool list of messages to a file */
1015 /* returns # of msgs spooled */
1016 int spool_out(struct msglist *cmlist, FILE * destfp, char *sysname)
1018 struct msglist *cmptr;
1022 int msgs_spooled = 0;
1029 strcpy(curr_rm, "");
1031 /* for each message in the list... */
1032 for (cmptr = cmlist; cmptr != NULL; cmptr = cmptr->next) {
1034 /* make sure we're in the correct room... */
1035 if (strcasecmp(curr_rm, cmptr->m_rmname)) {
1036 sprintf(buf, "GOTO %s", cmptr->m_rmname);
1039 if (buf[0] == '2') {
1040 strcpy(curr_rm, cmptr->m_rmname);
1042 syslog(LOG_ERR, "%s", buf);
1045 /* download the message from the server... */
1047 sprintf(buf, "MSG3 %ld", cmptr->m_num);
1050 if (buf[0] == '6') { /* read the msg */
1051 msg_len = atol(&buf[4]);
1052 while (msg_len > 0L) {
1053 blok_len = ((msg_len >= 256L) ? 256 : (int) msg_len);
1054 serv_read(buf, blok_len);
1055 fwrite(buf, blok_len, 1, mmfp);
1056 msg_len = msg_len - (long) blok_len;
1058 } else { /* or print the err */
1059 syslog(LOG_ERR, "%s", buf);
1064 if (ismsgok(0L, mmfp, sysname)) {
1068 fread(fbuf, 3, 1, mmfp);
1069 fwrite(fbuf, 3, 1, destfp);
1070 while (a = getc(mmfp), ((a != 0) && (a != 'M'))) {
1073 fpgetfield(mmfp, fbuf);
1075 fprintf(destfp, "%s!", NODENAME);
1077 fwrite(fbuf, strlen(fbuf) + 1, 1, destfp);
1080 fprintf(destfp, "C%s%c",
1081 cmptr->m_rmname, 0);
1092 return (msgs_spooled);
1095 void outprocess(char *sysname)
1096 { /* send new room messages to sysname */
1099 char shiptocmd[128];
1103 struct msglist *cmlist = NULL;
1104 struct rmlist *crmlist = NULL;
1105 struct rmlist *rmptr, *rmptr2;
1106 struct msglist *cmptr, *cmptr2;
1107 FILE *sysflfp, *tempflfp;
1111 sprintf(tempflnm, tmpnam(NULL));
1112 tempflfp = fopen(tempflnm, "w");
1113 if (tempflfp == NULL)
1118 * Read system file for node in question and put together room list
1120 sprintf(sysflnm, "%s/network/systems/%s", bbs_home_directory, sysname);
1121 sysflfp = fopen(sysflnm, "r");
1122 if (sysflfp == NULL)
1124 fgets(shiptocmd, 128, sysflfp);
1125 shiptocmd[strlen(shiptocmd) - 1] = 0;
1126 while (!feof(sysflfp)) {
1127 if (fgets(srmname, 32, sysflfp) == NULL)
1129 srmname[strlen(srmname) - 1] = 0;
1130 fgets(lbuf, 32, sysflfp);
1131 rmptr = (struct rmlist *) malloc(sizeof(struct rmlist));
1133 strcpy(rmptr->rm_name, srmname);
1134 strip_trailing_whitespace(rmptr->rm_name);
1135 rmptr->rm_lastsent = atol(lbuf);
1136 if (crmlist == NULL)
1138 else if (!strcasecmp(rmptr->rm_name, "control")) {
1139 /* control has to be first in room list */
1140 rmptr->next = crmlist;
1144 while (rmptr2->next != NULL)
1145 rmptr2 = rmptr2->next;
1146 rmptr2->next = rmptr;
1152 * Assemble list of messages to be spooled
1154 for (rmptr = crmlist; rmptr != NULL; rmptr = rmptr->next) {
1156 sprintf(buf, "GOTO %s", rmptr->rm_name);
1159 if (buf[0] != '2') {
1160 syslog(LOG_ERR, "%s", buf);
1162 sprintf(buf, "MSGS GT|%ld", rmptr->rm_lastsent);
1166 while (serv_gets(buf), strcmp(buf, "000")) {
1167 thismsg = atol(buf);
1168 if (thismsg > (rmptr->rm_lastsent)) {
1169 rmptr->rm_lastsent = thismsg;
1171 cmptr = (struct msglist *)
1172 malloc(sizeof(struct msglist));
1174 cmptr->m_num = thismsg;
1175 strcpy(cmptr->m_rmname, rmptr->rm_name);
1181 while (cmptr2->next != NULL)
1182 cmptr2 = cmptr2->next;
1183 cmptr2->next = cmptr;
1186 } else { /* print error from "msgs all" */
1187 syslog(LOG_ERR, "%s", buf);
1193 cmptr2 = cmlist; /* this loop counts the messages */
1194 while (cmptr2 != NULL) {
1196 cmptr2 = cmptr2->next;
1198 syslog(LOG_NOTICE, "%d messages to be spooled to %s",
1199 outgoing_msgs, sysname);
1202 * Spool out the messages, but only if there are any.
1204 if (outgoing_msgs != 0)
1205 outgoing_msgs = spool_out(cmlist, tempflfp, sysname);
1206 syslog(LOG_NOTICE, "%d messages actually spooled",
1210 * Deallocate list of spooled messages.
1212 while (cmlist != NULL) {
1213 cmptr = cmlist->next;
1219 * Rewrite system file and deallocate room list.
1221 syslog(LOG_NOTICE, "Spooling...");
1222 sysflfp = fopen(sysflnm, "w");
1223 fprintf(sysflfp, "%s\n", shiptocmd);
1224 for (rmptr = crmlist; rmptr != NULL; rmptr = rmptr->next)
1225 fprintf(sysflfp, "%s\n%ld\n", rmptr->rm_name, rmptr->rm_lastsent);
1227 while (crmlist != NULL) {
1228 rmptr = crmlist->next;
1234 * Close temporary file, ship it out, and return
1237 if (outgoing_msgs != 0)
1238 ship_to(tempflnm, sysname);
1244 * Connect netproc to the Citadel server running on this computer.
1246 void np_attach_to_server(void)
1251 {"netproc", "localhost", NULL, NULL};
1253 syslog(LOG_NOTICE, "Attaching to server...");
1254 sprintf(portname, "%d", config.c_port_number);
1256 attach_to_server(3, args);
1258 syslog(LOG_NOTICE, "%s", &buf[4]);
1259 sprintf(buf, "IPGM %d", config.c_ipgm_secret);
1262 syslog(LOG_NOTICE, "%s", &buf[4]);
1263 if (buf[0] != '2') {
1273 int main(int argc, char **argv)
1278 int import_only = 0; /* if set to 1, don't export anything */
1280 openlog("netproc", LOG_PID, LOG_USER);
1281 strcpy(bbs_home_directory, BBSDIR);
1284 * Change directories if specified
1286 for (a = 1; a < argc; ++a) {
1287 if (!strncmp(argv[a], "-h", 2)) {
1288 strcpy(bbs_home_directory, argv[a]);
1289 strcpy(bbs_home_directory, &bbs_home_directory[2]);
1291 } else if (!strcmp(argv[a], "-i")) {
1294 fprintf(stderr, "netproc: usage: ");
1295 fprintf(stderr, "netproc [-hHomeDir] [-i]\n");
1302 if (set_lockfile() != 0) {
1303 syslog(LOG_NOTICE, "lock file exists: already running");
1306 signal(SIGINT, cleanup);
1307 signal(SIGQUIT, cleanup);
1308 signal(SIGHUP, cleanup);
1309 signal(SIGTERM, cleanup);
1311 syslog(LOG_NOTICE, "started. pid=%d", getpid());
1313 np_attach_to_server();
1316 if (load_syslist() != 0)
1317 syslog(LOG_ERR, "cannot load sysinfo");
1318 setup_special_nodes();
1320 inprocess(); /* first collect incoming stuff */
1322 if (import_only != 1) {
1323 allfp = (FILE *) popen("cd ./network/systems; ls", "r");
1324 if (allfp != NULL) {
1325 while (fgets(allst, 32, allfp) != NULL) {
1326 allst[strlen(allst) - 1] = 0;
1331 /* import again in case anything new was generated */
1335 syslog(LOG_NOTICE, "processing ended.");