#include <\fido\fido.h> #include <\lib\xfbuf.h> #include <\lib\ascii.h> #define same(s1,s2) (strcmp(s1,s2)==0) char *getmem(); long sizmem(); struct _area msgarea; /* current msg area */ struct _area filearea; /* current file area */ struct _fido fido; struct _node id,altid; char kill_null = 0; /* 1 == kill null messages */ char kill_files = 0; /* 1 == kill MISSING FidoNet files */ main(argc,argv) int argc; char **argv; { int i; char *cp,buff[SS]; printf("KillARCM (13 Apr 90) FidoNet/EchoMail Cleanup Utility /? for help\r\n"); printf("Tom Jennings / World Power Systems\r\nBox 77731, San Francisco, CA 94107, USA\r\n"); printf("(k) All wrights revered\r\n"); allmem(); fastfile(3); i= open("fido.sys",0); /* load system stuff */ if (i == -1) { printf("The Fido system file FIDO.SYS is missing!\r\n"); exit(1); } read(i,&fido,sizeof(fido)); close(i); if (fido.fido_version != FIDOVER) { printf("KillARCM doesn't match your Fido/FidoNet version!\r\n"); exit(1); } id.zone= fido.zone; /* node ID */ id.net= fido.net; id.number= fido.number; id.point= fido.point; altid.zone= fido.altzone; /* alternate ID */ altid.net= fido.altnet; altid.number= fido.altnumber; altid.point= fido.altpoint; while (--argc) { ++argv; /* cpyarg(buff,*argv); /* a copy of any filename */ */ strip_switch(buff,*argv); /* a copy of the switches, */ for (cp= buff; *cp; ++cp) switch (*cp) { case 'N': kill_null= 1; break; case 'F': kill_files= 1; break; case '?': printf("\r\nKillARCM will always K)ill messages that are \"From: ARCMail\", ie. \r\n"); printf("incoming ARCMail packets. It can do these things if you put magic symbols \r\n"); printf("after the program name:\r\n"); printf("\r\n"); printf(" /N Kills null FidoNet messages. (Messages with no text -- file-\r\n"); printf(" requests, etc.)\r\n"); printf("\r\n"); printf(" /F Removes all \"MISSING\" file entries from your FidoNet file\r\n"); printf(" area. (ie. incoming ARCmail packets, automatically processed\r\n"); printf(" NODEDIFFs, etc.)\r\n"); exit(1); } } getmarea(fido.netmarea,&msgarea); /* pick the area, */ purge(); /* purge them */ if (kill_files) kill_missing(); /* purge files */ } /* Purge messages so many days old. */ purge() { int arcm_count,null_count,n,i; int msgfile; char *cp,buff[SS],name[SS]; char work[256]; struct _xfbuf xfbuf; struct _msg msg; /* message header */ struct _node msg_orig; /* actual message originator */ struct _node msg_dest; /* actual message destination */ arcm_count= null_count= 0; makemname(name,"*.msg"); xfbuf.s_attrib= 0; i= 0; while (_find(name,i++,&xfbuf)) { /* find a msg file */ makemname(buff,xfbuf.name); /* assemble its name */ msgfile= open(buff,2); /* read its header */ if (msgfile == -1) continue; read(msgfile,&msg,sizeof(struct _msg)); /* load the header */ work[read(msgfile,work,sizeof(work) - 1)]= '\0'; /* read some msg body */ close(msgfile); /* close the file */ msg_orig.number= msg.orig_node; msg_orig.net= msg.orig_net; /* assume addresses */ msg_dest.number= msg.dest_node; /* are from the header */ msg_dest.net= msg.dest_net; msg_orig.zone= id.zone; /* in case no */ msg_dest.zone= id.zone; /* IFNA Kludge */ /* msg_dest.zone= msg.dest_zone; /* so-called real msgs */ msg_orig.zone= msg.orig_zone; */ /* Don't touch messages we created! */ if (is_us(&msg_orig)) continue; /* Check for the presence of an IFNA Kludge; if there is one, set the addresses to that. */ if (fcomp(work,"\001INTL",5) == 0) { cp= next_arg(work); set_nn(cp,&msg_dest); cp= next_arg(cp); set_nn(cp,&msg_orig); } /* Now check to see if this message is From: ARCmail, not our node. */ if ( (strcmp("ARCmail",msg.from) == 0) /* if From: ARCmail */ && (msg.attr & MSGFILE) /* and a file attach, */ && (!is_us(&msg_orig)) ) { /* and not from us */ delete(buff); /* kill it */ ++arcm_count; /* Now check to see if this message is empty. Skip all IFNA kludge lines, see if there is anything left. If 4 or less characters (CR/LF CR/LF) consider it null. */ } else { for (cp= work; *cp == '\01';) { /* find 1st non-IFNA kludge */ while (*cp != 13) { /* look for the CR */ if (!*cp) break; ++cp; } if (*cp == 13) ++cp; /* skip any CR */ if (*cp == 10) ++cp; /* skip any LF */ } for (n= 0; *cp;) { /* count printable chars */ if (*cp++ > ' ') ++n; /* but not spaces */ } if (kill_null & (n == 0)) { /* if a null message, */ delete(buff); /* kill it */ ++null_count; } } } printf("\r\nKilled "); if (kill_null) printf("%d null messages, ",null_count); printf("%d messages \"From: ARCmail\"\r\n",arcm_count); } kill_missing() { struct _xfbuf xfbuf; int dead,f,o,i,n; char *cp,fname[SS],buff[SS],ln[200]; getfarea(fido.netfarea,&filearea); /* pick the area, */ /* Open FILES.BBS in the net file area, plus a new temp file. For each line in FILES.BBS, copy those list files that do exist to the temporary file, ie. delete lines with MISSING files. */ makefname(buff,"FILES.BBS"); /* file list name */ f= open(buff,0); /* open source file, */ if (f == -1) return; /* no file to delete from */ makefname(buff,"FILES.$$$"); /* temp. work file name */ o= creat(buff,2); /* create output file */ if (o == -1) { close(f); printf("Cant create work file %s\r\n",buff); return; } dead= 0; xfbuf.s_attrib= 0; while (rline(f,ln,sizeof(ln))) { /* process each line in FILES.BBS */ if (*ln == SUB) break; /* exit if Control-Z */ cpyarg(buff,ln); /* copy file name */ makefname(fname,buff); /* make full pathname */ if (_find(fname,0,&xfbuf)) { /* if the file exists, write it */ if (write(o,ln,strlen(ln)) != strlen(ln)) { printf("Disk full! The file list is not updated\r\n"); close(o); o= -1; break; } write(o,"\r\n",2); } else { cp= next_arg(ln); /* point to comment */ stoupper(buff); /* make name upper case */ printf("%13s %s: REMOVED\r\n",buff,cp); ++dead; } } close(f); /* close input */ if (o != -1) { close(o); /* save output */ makefname(fname,"FILES.BBS"); delete(fname); /* delete and */ makefname(buff,"FILES.$$$"); rename(buff,fname); /* rename, */ } if (! dead) printf("No files marked \"MISSING\" in the FidoNet file area\r\n"); } /* Assemble a full msg filename */ makefname(d,p) char *d,*p; { strcpy(d,filearea.path); /* put in the path, */ strcat(d,p); /* add the filename */ } /* Assemble a full msg filename */ makemname(d,p) char *d,*p; { strcpy(d,msgarea.path); /* put in the path, */ strcat(d,p); /* add the filename */ } /* Get message area N, return 0 if error. */ getmarea(n) unsigned n; { return(getarea(n,&msgarea,0)); } /* Get file area N, return 0 if error. */ getfarea(n) unsigned n; { return(getarea(n,&filearea,1)); } /* Get message or file area #n; return 0 if not set, illegal number or other error. */ getarea(n,a,file) unsigned n; /* area number */ struct _area *a; /* struct to load */ int file; /* 1 == get a file area */ { int f,i; long off; if (n < 0) return(0); /* no such area */ off= 0L + sizeof(struct _fido); /* offset to beg msg areas */ if (file) { /* if a file area, */ if (n >= fido.farea_max) return(0); /* bound it */ off += (long)(sizeof(struct _area) * fido.marea_max); /* beg file areas */ } else if (n >= fido.marea_max) return(0); /* msg area max */ f= open("fido.sys",0); if (f == -1) return(0); /* no system file! */ off += (long)(n * sizeof(struct _area)); /* offset plus area # */ lseek(f,off,0); /* seek there, */ i= read(f,a,sizeof(struct _area)); /* read some, */ close(f); /* immediately close it */ if (i != sizeof(struct _area)) return(0); /* check read error */ a-> number= n; /* set the path number */ return(*a-> path != NUL); /* invalid if no path set */ } /* Return true if the two nodes are the same. */ same_node(n1,n2) struct _node *n1,*n2; { return( (n1-> number == n2-> number) && (n1-> net == n2-> net) && (n1-> zone == n2-> zone) ); } /* Return true if this net/node combination is us. */ is_us(n) struct _node *n; { return(same_node(n,&id) || same_node(n,&altid)); } /* Parse a string into net and node number. zone and net are untouched if not found in the input string. This parses as follows: (xx means unchanged) string output 99:88/77 99:88/77 88/77 xx:88/88 77 xx:xx/77 99:88 99:88/00 88/ xx:88/00 */ set_nn(cp,n) char *cp; struct _node *n; { int x; n-> number= atoi(cp); /* assume its node only */ while (isdigit(*cp)) ++cp; /* skip the number, */ if (*cp == ':') { /* if it was a zone, */ n-> zone= n-> number; /* that was a zone number, */ n-> net= atoi(++cp); /* net must follow */ while (isdigit(*cp)) ++cp; /* skip the net number */ if (*cp == '/') /* if that was a net number */ n-> number= atoi(++cp); /* set node number (or zero) */ } else if (*cp == '/') { /* if that was a net number, */ n-> net= n-> number; /* copy it up, */ n-> number= atoi(++cp); /* now set node number */ } } /* Fixed length string compare. Returns 0 if a match */ fcomp(s1,s2,n) char *s1,*s2; int n; { while (n) { if (*s1++ != *s2++) break; --n; } return(n); }