#include #include #include long sizmem(); char *getmem(); char *next_arg(); /* An automatic mailer for Fido; given a text file in the format below, generates FidoNet messages automatically. T. Jennings 8 Aug 86 */ struct _msg msg; /* message header structure */ struct _fido fido; /* big system file */ struct _area msgarea; struct _nmap nmap; struct _ndat ndat; struct _ntc ntc; int nodefile; /* node file handles */ int ntcfile; int ndatfile; int idxfile; int ndxfile; int zdxfile; int nodetotal; /* satisfy link */ int connect_tries,dial_tries; /* satisfy link */ char nodepath[80] = ""; /* current directory */ struct _node id,altid; /* our address */ struct _node dest; /* work node */ int msgtotal; /* total number of messages */ int msghighest; /* highest number */ int log; /* log file handle */ char *txbuff; /* message text buffer, */ unsigned txsize; /* buffer size, */ unsigned txcount; /* current count */ char bymsg[SS]; int _stack = 5000; main(argc,argv) int argc; char *argv[]; { char arg[SS],path[SS],fname[SS]; struct _xfbuf xfbuf; int n; printf("FidoMail (23 Jan 91) FidoNet Message Mailer for "); copr(); if (argc < 2) { printf("No Message Script Files specified\r\n"); exit(1); } allmem(); /* free memory, */ fastfile(4); if (sizmem() > 65535L) txsize= 65535; else txsize= sizmem(); txbuff= getmem(txsize); /* get memory for input buffer */ cpyarg(arg,argv[1]); /* copy the filename */ fixdir(arg); /* in case directory name */ log= append("fidonet.log"); /* add to the log file, */ if (log == -1) { printf("ERROR: cant open FIDONET.LOG!\r\n"); exit(1); } gtod(fname); lprintf("--------------\r\nFidoMail started %s\r\n",&fname[11]); n= open("fido.sys",0); /* load system stuff */ if (n == -1) { clprintf("The Fido system file \"FIDO.SYS\" is missing!\r\n"); exit(1); } read(n,&fido,sizeof(fido)); close(n); if (fido.fido_version != FIDOVER) { clprintf("Wrong Fido/FidoNet or FidoMail 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; getarea(fido.netmarea,&msgarea); /* select the msg area */ if (open_node() == -1) { clprintf(" * Missing or wrong revision nodelist files; please run \"MAKELIST\"\r\n"); } else { sprintf(bymsg," * from FidoMail v%d%c\r\n",FIDOVER,'a' + FILEVER - 1); msgcount(); /* count the messages, */ strip_path(path,arg); /* copy of the path only */ xfbuf.s_attrib= 0; /* normal attribute, */ n= 0; while (_find(arg,n,&xfbuf)) { /* process each file, */ ++n; cpyarg(fname,path); /* build the full pathname, */ strcat(fname,xfbuf.name); makemsg(fname); /* process it, */ } if (n == 0) { clprintf(" * No message script files to do\r\n"); } gtod(fname); } lprintf("Complete at %s\r\n------------\r\n",&fname[11]); close_node(); close(log); /* done with the log */ exit(0); } /* Generate messages from the message script file. Output reports as we go. */ makemsg(fname) char *fname; { char *lp,ln[SS]; /* line buffer */ char arg[SS]; /* line command */ char nodes[SS]; /* list of nodes */ int f; /* open file */ int recd; /* nodelist record */ struct _msg msg; /* message header */ int state; #define FROM 1 /* got a From: line */ #define TO 2 /* got a To: line */ #define ON 4 /* got On: node list */ #define SUBJ 8 /* got Subj: or File: */ #define DONE (FROM + TO + ON + SUBJ) /* means we are done */ lp= (char *) &msg; for (f= 0; f < sizeof(struct _msg); f++) *lp++= NUL; f= open(fname,0); if (f == -1) { clprintf(" * No such file %s\r\n",fname); return; } *nodes= NUL; /* no nodes yet, */ msg.orig_node= id.number; /* originating node */ msg.orig_net= id.net; /* msg.orig_zone= id.zone; */ msg.up= 0; /* clear reply links */ msg.reply= 0; msg.times= 1; /* mark as read once for TWIX */ msg.attr= MSGLOCAL; /* generated locally */ msg.cost= 0; /* cost so far */ gtod(msg.date); /* creation date */ for (state= 0; state != DONE;) { if (! rline(f,ln,sizeof(ln))) { clprintf(" * File ended before the message was completed!\r\n"); return; } lp= skip_delim(ln); /* ignore leading garbage, */ cpyatm(arg,lp); /* a copy of the command word, */ lp= next_arg(lp); /* pointer to the following text */ stolower(arg); if (same(arg,"from:")) { lp[sizeof(msg.from)]= NUL; strcpy(msg.from,lp); state |= FROM; } else if (same(arg,"to:")) { lp[sizeof(msg.to)]= NUL; strcpy(msg.to,lp); state |= TO; } else if (same(arg,"on:")) { strcpy(nodes,lp); state |= ON; } else if (same(arg,"subj:")) { lp[sizeof(msg.subj)]= NUL; strcpy(msg.subj,lp); state |= SUBJ; } else if (same(arg,"file:") || same(arg,"files:")) { lp[sizeof(msg.subj)]= NUL; strcpy(msg.subj,lp); state |= SUBJ; msg.attr |= MSGFILE; } else if (same(arg,"option:") || same(arg,"options:")) { while (num_args(lp)) { switch (*lp) { case 'p': case 'P': msg.attr |= MSGPRIVATE; break; case 'k': case 'K': msg.attr |= MSGKILL; break; } lp= next_arg(lp); } } } /* We have all the basic args. Fill in the rest of the message structure, send a message to each node specified. Watch that we delete any Control-Z at the end of the file. */ txbuff[read(f,txbuff,txsize)]= SUB; /* load text, mark the end */ for (txcount= 0; txbuff[txcount] != SUB; ++txcount); lp= nodes; /* list of nodes */ cpy_node(&dest,&id); /* default to us */ while (num_args(lp)) { cpyatm(arg,lp); /* not cpyarg; / is a delimiter! */ lp= next_arg(lp); /* next item, */ stolower(arg); if (same(arg,"ournet")) { /* if meta "ournet" */ clprintf(" * To OurNet:\r\n"); cpy_node(&dest,&id); /* choose us, */ dest.number= 0; /* make it the host, */ recd= find_ndat(&dest); /* find our host */ if (recd == 0) { clprintf(" * Can't find our own host %s in the nodelist??\r\n", str_node(&dest)); } else { while (get_ndat(recd++)) { if (is_us(&ndat.node)) continue; if (! same_net(&ndat.node,&dest)) break; write_msg(&msg,f); } } clprintf("\r\n"); } else { /* hopefully normal net/node */ cpy_node(&dest,&id); set_nn(arg,&dest); /* change /number */ if (find_ndat(&dest) != -1) { /* write one message */ write_msg(&msg,f); } else { clprintf(" * There is no %s\r\n",str_node(&dest)); } } } } /* Write out the message as is, return 0 if an error. (Disk full). The global struct 'dest' is the actual destination. */ write_msg(m,fi) struct _msg *m; int fi; { int i,f; char c,buff[SS],name[SF],*cp; m-> dest_node= dest.number; /* set basic net/node address */ m-> dest_net= dest.net; /* m-> dest_zone= dest.zone; */ if (id.zone && /* do IFNA Kludge if */ !same_zone(&dest,&id) && /* not our zone */ !same_zone(&dest,&altid)) { m-> dest_node= dest.zone; /* send to ourzone:1/destzone */ m-> dest_net= 1; } m-> cost= ndat.cost; /* set message cost, */ clprintf(" * Message to %s\r\n",str_node(&dest)); sprintf(name,"%d.MSG",msghighest + 1); makemname(buff,name); f= creat(buff,1); if (f == -1) { clprintf(" * Cant create message file %s\r\n",name); return; } write(f,m,sizeof(struct _msg)); /* write header (ignore error) */ sprintf(buff,"\001INTL %s %s\r\n",str_node(&dest),str_node(&id)); write(f,buff,strlen(buff)); /* IFNA Kludge */ if (write(f,txbuff,txcount) != txcount) { clprintf(" * Disk Full!\r\n"); /* write text, check error */ close(f); delete(name); return; } /* Add the "via" line only of there is a message body -- allows generating null "poll" messages. */ for (i= 0; i < txcount; i++) { /* count printable characters */ if (txbuff[i] > ' ') { /* (not including spaces) */ write(f,bymsg,strlen(bymsg)); /* autodial's message */ break; } } write(f,"",1); /* write a null, */ close(f); /* message complete */ ++msghighest; /* next highest message number, */ ++msgtotal; /* another message */ } /* Get message area #n; return 0 if not set, illegal number or other error. */ getarea(n,a) unsigned n; /* area number */ struct _area *a; /* struct to load */ { int off,f,i; if (n < 0) return(0); /* no such area */ off= sizeof(struct _fido); /* offset to beg msg areas */ if (n >= fido.marea_max) return(0); /* msg area max */ f= open("fido.sys",0); if (f == -1) return(0); /* no system file! */ off += n * sizeof(struct _area); /* offset plus area # */ lseek(f,(0L + 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 */ } /* 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 */ } /* Open a file for appending, creating it if necessary. Return the open handle, or -1 if error. */ append(s) char *s; { int h; h= open(s,2); /* open or create the */ if (h == -1) h= creat(s,2); /* file, if opened OK */ else lseek(h,0L,2); /* seek to the end */ return(h); /* handle or error */ } /* Count the number of messages and the highest message number, update the system file array. */ msgcount() { int n; char buff[SS]; struct _xfbuf xfbuf; makemname(buff,"????????.msg"); msgtotal= 0; msghighest= 0; xfbuf.s_attrib= 0; while (_find(buff,msgtotal,&xfbuf)) { ++msgtotal; /* count another, */ n= atoi(xfbuf.name); /* change name to number */ if (n > msghighest) msghighest= n;/* pick highest one, */ } } /* Formatted print to the log file. If the log fills up, mark the handle as -1, stop writing to it. */ lprintf(f) char *f; { char *cp,buf[500]; if (! log) return; _spr(buf,&f); if (write(log,buf,strlen(buf)) != strlen(buf)) { printf("LOG FILE: DISK FULL!!\r\n"); log= 0; } } /* Formatted print to the log file and console. */ clprintf(f) char *f; { char buf[500]; _spr(buf,&f); cputs(buf); if (! log) return; if (write(log,buf,strlen(buf)) != strlen(buf)) { printf("LOG FILE: DISK FULL!!\r\n"); log= 0; } } /* Return true if the FBIT is set. */ fbit(bit) int bit; { return(fido.fbits[bit / sizeof(char)] & (1 << bit % sizeof(char))); }