IMD 1.16: 23/05/2007 22:43:34 metal 1.30a source #2 MENTR ASMMES C  MES C 5MESEND C  !"#$%&'()*MESEND C +MESTUFF C 5,-./012MESYSOP C ?3456789:METAL C d;<=>?@ABCDEFGMETALIB LIBrHIJKLMNOPQRSTUVMEUSER C WXYZ[\]^_`abcdefMEUSER C gMEZ3 C EhijklmnopMOVBGN O qUCOMP SUBrXPM H stuvXPMIO C ;wxyz{|}~; This file loads METAL.COM and uses the MENTER.OVR to init name.. ; ; Use Aztec's assembler/linker to assemble this ; ; 09/02/84 MENTR.COM ; ; There are inexcusable hacks in this file.. forgive me. ; It is expected that this be called MENTR.COM, and is the file loaded ; by BYE as a caller comes in. This is required because something MUST ; be in the command line (default dma 80h buffer) to indicate that the ; name/id enter program be run, OTHERWISE the message system will read ; the lastcalr file and use the last users ID. ; user equ 0 ; user area to get metal.com from.... org 100h lxi h,005ch ; default fcb fcbloop1: mvi m,0 inx h mov a,l cpi 80h jnz fcbloop1 lxi h,005dh ; where to put name of file lxi d,fname fcbloop2: ldax d ora a jz done mov m,a inx h inx d jmp fcbloop2 ; fname: db 'METAL COM',0 ; done: mvi c,20h ; set user func mvi e,user call 0005 ; bdos mvi c,0fh ; open code.. lxi d,005ch ; fcb call 0005 ; bdos cpi 0ffh ; error? jz 0 ; yes boot... lxi d,loader lxi h,0080h ; dma.. lxi b,07fh movloop: ldax d mov m,a inx d inx h dcr c jnz movloop lxi sp,0ffh ; stack goes to a safe place lxi b,005ch ; fcb jmp 080h+loadrun-loader ; jump to loader... ; loader: db 15 db 'run menter' ; command line..REQUIRED! and <=14 chars!!!!!! db 0 loadrun: lxi d,100h ; tpa load1: push d push b mvi c,1ah ; set dma.. call 0005 ; bdos pop d push d mvi c,14h ; read seq. call 0005 ; bdos pop b pop d ora a ; error? jz 80h+(bumpdma-loader) ; jrz bumpdma a1: mvi c,1ah ; set dma lxi d,0080h ; reset default dma address.. call 0005 ; bdos mvi c,10h ;close lxi d,05ch call 0005 db 0,0,0,0,0 jmp 100h ; tpa.. (program just loaded) ; bumpdma: lxi h,0080h dad d xchg jz 80h+(load1-loader) ; jr loader ; lend: db 0 END t user func mvi e,user call 0005 ; bdos mvi c,0fh ; open code.. lxi d,005ch ; fcb call 0005 ; bdos cpi 0ffh ; e/****************************************************************************** * METAL Message section... * * File name: MES.C version 1.30xx * * Metal and Metal Message System are Trademarked and * Copyright (c) 1984 Tim Gary * All rights reserved. * * * This module contains common message base routines (read, msgheader, etc) * ***************************************************************************** * * 1.30xx 6/23/85 Spelling error fixed. * 1.30xx 3/03/85 Z3 stuff added, fixed prompts for ignoring controls. * 1.20b 01/21/85 Message read fixed for sysop '<' function.. * 1.20b 01/11/85 Swap order of sender/recipient in summary. * 1.20b 01/09/85 Really fixed search function. Added & op to search. * Added sysop link of a message to a file.. * 1.20b 01/07/85 Search function fixed, Quiet read mode, novice help, * extended abort checking during search operations, and * summary function output changed. * 1.20a 11/11/84 Nothing found message fixed in selective read. * 1.20 11/09/84 [Nothing found/not addressed to ya/dead] msg in read. * 1.20 11/04/84 Fixed timefix routine for no clock. * 1.10e 11/01/84 Allow for reading of dead msgs. * 1.10e 10/31/84 Width stuff changed in msgheader, fixed for unkill. * 1.10c 10/12/84 Made a few functions here overlays to conserve space. * 1.10b 10/09/84 Complete reworking of read message routines (internal only). * 1.10b 10/04/84 More cosmetics.. Should be it for a while. * 1.10a 9/28/84 Fixed reply problem (msg shown after reply..). * 1.10a 9/26/84 Added a few cosmetic changes (y/n)? and selective read help. * 1.10a 9/24/84 Fixed edit user/kill this msg, bugs.. (introduced 8/31/84) * 1.10a 9/12/84 Eliminated Reverse read bug (replies not listed) * 1.10a 9/12/84 Cosmetic changes. * 1.10a 9/09/84 Cosmetic changes. * 1.10a 9/07/84 Added Kill previous message to selective read for sysop. * 1.10a 9/06/84 Changed Edit/delete user on read for previous message. * 1.10a 8/31/84 Split for overlays, now contains readmsg() and commons. * * 1.01a 8/05/84 Got things going, added delete user, and edit user during * message read (prompted mode). * 1.01a 7/14/84 Message editing bugs fixed (delete line.. movmem changed). * Added subject truncation notice on message entry. * 1.01a 6/30/84 Cleaned up more functions. * 1.01a 6/26/84 Cleaned up a few functions, and added MULTI_USER stuff. * 1.01a 6/10/84 Fixed to work with Aztec C 1.06. Started Multi-user stuff. * * 1.0b 4/20/84 (cont) Added msearch, for string search for msgs.. * 1.0b 4/13/84 Modified for upper/lower case names, and added check for * maximum messages allowed (killed and active ones). * * 1.0 1/20/84 New format of Message file headers. * p3.0 12/14/83 pre-release version 3.0 mods for MCONFIG.. * *****************************************************************************/ #include "xpm.h" #include "hmh.h" #include "hmconfg.h" #include "ctype.h" getindex(m) register unsigned m; { register int a; if (m==0) return ERROR; for (a=0; astatus!=DEADMSG) { msg[mindex].number=mptr->number; msg[mindex].seek=mptr->seek; msg[mindex].parent=mptr->parent; msg[mindex].reply=mptr->reply; ++totalmsgs; ++msgcount;  if (thisis(mptr->reciever)) printf("\n#%u from %s %s is for you.\n",mptr->number, mptr->fsend,mptr->lsend); } /* if */ } /* while */ close(summary); lmsg=msg[mindex-1].number; putchar('\n'); return rval; /* # of new msgs */ } /* mu_update */ /********************************************************* * check for differing (in nextmsg) counters file * returns new nextmsg *********************************************************/ unsigned new_msgs() { unsigned tnext=0; if ((counters=open(COUNTERS,F_RD | F_UNLOCK))!=NULL) { sscanf(bufloc(counters),"%*d %*d %d",&tnext); close(counters); if (tnext==nextmsg) tnext=0; } return tnext; } #endif /* multi user */ /*************************** * help for read functions * ***************************/ read_help(mode) char mode; { static char *r_hlp[] = { "\nEnter the message number you wish to retrieve.", "\nTo read a series of messages, enter a plus (+) or minus (-)", "\n(for increasing or decreasing order) after the number of", "\nthe first message you wish to read. (eg. 10+ or 280-)\n", 0 }; /* help text */ if (mode=='S' || mode=='R') send("\nEnter the message you wish to start retrieval at.\n"); else if (mode!='P') dis_text(r_hlp); if (mode & 128) search_help(); } selrd_help() { static char *nsr_help[] = { "\n> (Y)es, read this message. (N)o, don't read it.", "\n> (R)eply to PREVIOUS message. (Q)uit reading messages.\n", 0 }; static char *ssr_help[] = { "\nSpecial SYSOP functions:", "\n> (K)ill PREVIOUS message. (W)rite message to disk file.", "\n> (P)rint message to LST: device", "\n> (E)dit sender of PREVIOUS message", "\n> (D)elete sender of previous message\n", 0 }; if (dis_text(nsr_help)!=ERROR) if (user.status==SYSOP) dis_text(ssr_help); } /****************************************** * Read messages routine. * * Code is much clearer, and is not * * dependent on message structure. * ******************************************/ readmsgs(mode) int mode; { int firstm,lastm,inc; /* message indexes and increment count */ register int flag; /* flag for various things ERROR=abort */ register unsigned startmsg; /* starting message number */ int read_flag; /* flag for something read or not */ #ifdef MULTI_USER mu_update(); #endif if (!msgcount) { send("\nSorry, there are currently no messages posted.\n"); return; } novhelp(); if (strloc==0 && user.parm.expert==POFF) read_help(mode); /* * Loop the Loop... */ do { if (ovloader(OVMISC,GETRANGE,&mode,&firstm,&lastm,&inc)==ERROR) break; read_flag=FALSE; /* nothing read yet */ if ((messages=open(MESSAGES,F_RD | F_UNLOCK))==NULL) { send("\nUnable to open messages file.\n"); read_flag=TRUE; /* fake it out so only one msg! */ break; } for (flag=NULL,startmsg=msg[firstm].number; ((inc!=-1) ? (firstm<=lastm) : (firstm>=lastm)) && (flag!=ERROR); firstm+=((inc==0) ? 1 : inc) ) { int loc_first,loc_reply; /* local copies */ loc_first=firstm; loc_reply=msg[firstm].reply; if (msg[loc_first].number && (msg[loc_first].parent" : message.status==DEADMSG ? "" : ""), user.parm.width<80 ? "\n " : " ", message.fsend,message.lsend); if (user.parm.width>=80) buf[user.parm.width]='\0'; /* cut off at 80 chars */ } else if ((mode!=3 && mode!=4) || user.parm.expert==POFF) { if (message.parent) sprintf(tstr,"\n[Reply to msg #%u]\n",a); sprintf(buf,"\nMsg #%u posted %s %s%s by %s %s\ \nTo: %s %s About: %s (%d lines)\n%s\n",message.number,message.date, O.RTC ? "at " : "",O.RTC ? message.time : "", message.fsend,message.lsend,message.receiver, message.status==PRIVMSG ? "" : message.status==DEADMSG ? "" : " ", message.topic,message.lines,tstr); } } /* msgheader() displays the message header information in one of three * formats. 0=Quick Summary format 1=Full summary format * 2=Read Message format 3=Kill message format * 4=Unkill msg * Bit 0x80 of mode indicates display even if dead. * It expects you to supply the file descriptor, a 'starting' msg number (which * is only used by the summary funtions, and should be 1 or 0 for Read), * and the mode as described above. * * it returns ERROR if it could not read the header, or ^K was entered aborting * its output. * NULL (0) is returned if the message is private, and can't be read by the * current user of the system. * if everything is ok, it returns the number of lines in the message. */ msgheader(ffd,startmsg,mode) FILE *ffd; unsigned startmsg; int mode; { register unsigned a; if (read(ffd,1)!=128) return ERROR; movmem(bufloc(ffd),&message,128); /* get msg structure */ timefix(message.time); /* make time look better.. */ if (message.status==DEADMSG) message.parent=message.reply=0; if (mode==4) { if (message.status!=DEADMSG) { if (startmsg!=0) printf("\n[Message %u not dead!] ",message.number); return NULL; } } else if ((message.status==DEADMSG) && !(mode & 0x80)) return NULL; /* send("."); */ if ((message.status==PRIVMSG || (message.status==DEADMSG && (mode & 0x80))) && !thisis(message.receiver) && ( (mode<3) ? (O.user_types[user.type].readpriv==NO) : (O.user_types[user.type].killflag==NO) ) && (ustrcmp(message.fsend,user.first) || ustrcmp(message.lsend,user.last)) ) return NULL; /* send("."); */ if (mode==3 && !thisis(message.receiver) && (ustrcmp(message.fsend,user.first) || ustrcmp(message.lsend,user.last)) && O.user_types[user.type].killflag==NO) return NULL; /* send("."); */ if (message.number>=startmsg || startmsg==0) { if (msearch(0)==0) return NULL; /* no match.. ret */ if (message.parent!=0) { /* find original msg number */ if (((mode&0x7f)==2) && (message.parent>=startmsg) && startmsg!=0) return NULL; while (msg[getindex(message.parent)].parent!=0) message.parent=msg[getindex(message.parent)].parent; /* parent now has 0 if none, else orig. msg number */ } get_header(mode&0x7f,buffer); if ((mode!=3 && mode!=4) || user.parm.expert==POFF) /* write line */ if (send(buffer)==ERROR) return ERROR; } else return NULL; return message.lines ? message.lines : 1; /* if 0 lines, fake it.. */ } /* convert passed string (containing time in hh:mm:ss format) to hh:mm[am|pm] format */ timefix(s) register char *s; { register int n; char ch[3]; if (strlen(s)>=8) { n=atoi(s); if (n>=12) { n-=12; strncpy(ch,s+3,2); *(ch+2)='\0'; /* get mins in ch */ sprintf(s,"%2d:%2s pm",n,ch); } else strcpy(s+5," am"); } if (n==0) strncpy(s,"12",2); /* fix 00:xx:xx type times.. */ if (*s=='0') *s=' '; /* we don't like leading zeros */ } /*************** * search help * ***************/ search_help() { static char *s_hlp[] = { "\nThe following message fields may be searched:", "\n s: = subject field d: = date field", "\n f: = from (name) field t: = to (name) field", "\n *: = ALL of the above fields", "\nIf multiple fields are specified, then if any field", "\nmatches, the message will be selected. To change", "\nthis so that only messages matching every field", "\nat once, use a '&' character before any of the above fields.", "\nMultiple search fields may separately be specified.", "\nExamples: 244+ s:for sale &t:all users", "\n 1024- t:all users", "\n  ft:sysop s:metal\n", 0 }; /* that's enuf for now */ dis_text(s_hlp); } /************************************************************************ * Search for string in message variables if passed string ptr=0, * else, setup the string to be compared to the message variables later. * string, if passed, format of: * : s=subject search * f=from search t=to search d=date search * *=search all above fields &=perform 'and' search on * examples: ALL fields...sorry * s:for sale ft:tim gary d:09-02-84 * t:all &s:for sale t:tim gary s:metal * in read operations: * rs;30+ s:wanted r;223+ *:sysop etc... * * returns: bit 0 ON for SUBJECT match bit 1 ON for DATE match * bit 2 ON for FROM match bit 3 ON for TO match * bit 8 ON if no search.. ************************************************************************/ char msearch(sstr) char *sstr; { char *ps,*t_sstr; register char ret_flag; static char f_pattern[FNAMELEN+LNAMELEN+3]; static char t_pattern[FNAMELEN+LNAMELEN+3]; static char s_pattern[TOPICLEN+2]; static char d_pattern[DATELEN+2]; static int field_flag,and_flag; ret_flag=0; if (sstr) /* if not null ptr, setup search string */ { (*t_pattern)=(*f_pattern)=(*s_pattern)=(*d_pattern)='\0'; /* make empty at first */ field_flag=and_flag=NO; /* all off */ for (t_sstr=sstr; (ps=index(t_sstr,':')) && (t_sstr!=1); t_sstr=index(t_sstr,':')+1) /* '=' IS ON PURPOSE!!!!!!!! */ { while (--ps>=t_sstr) /* backwards parse from ':' */ { switch (*ps) { case 'S': field_flag|=1; get_pat(ps,s_pattern,TOPICLEN); break; case 'D': field_flag|=2; get_pat(ps,d_pattern,DATELEN); break; case 'F': field_flag|=4; get_pat(ps,f_pattern,FNAMELEN+LNAMELEN+1); break; case 'T': field_flag|=8; get_pat(ps,t_pattern,FNAMELEN+LNAMELEN+1); break; case '&': and_flag=YES; break; case '*': field_flag=15; /* all bits on */ get_pat(ps,t_pattern,FNAMELEN+LNAMELEN+1); get_pat(ps,f_pattern,FNAMELEN+LNAMELEN+1); get_pat(ps,d_pattern,DATELEN); get_pat(ps,s_pattern,TOPICLEN); break; default: ps=t_sstr; /* stop loop here */ } /* switch */ } /* while loop */ } /* for loop */ ret_flag=field_flag; } /* main 'string passed' if */ else { /* no string passed, compare with message fields */ if (!field_flag) ret_flag=128; /* flag bit 7 if no compare */ else { char tstr[MAXLINE+1]; /* used for sender string */ if (field_flag&1) ret_flag|=(usindex(s_pattern,message.topic) ? 1 : 0); if (field_flag&2) ret_flag|=(usindex(d_pattern,message.date) ? 2 : 0); if (field_flag&4) { sprintf(tstr,"%s %s",message.fsend,message.lsend); ret_flag|=(usindex(f_pattern,tstr) ? 4 : 0); } if (field_flag&8) ret_flag|=(usindex(t_pattern,message.receiver) ? 8 : 0); if (and_flag && (field_flag!=ret_flag)) ret_flag=0; /* not & */ } /* check pattern?? if */ } return ret_flag; /* return value */ } /* msearch */ get_pat(sub_str,dest,max_len) char *sub_str,*dest; int max_len; { register char *tp2; register char *tp1,*s_cop; tp1=s_cop=index(sub_str,':')+1; if (tp2=index(tp1,':')) /* if there are more ':'s */ while (!isspace(*(--tp2)) && tp2>tp1); else tp2=tp1+strlen(tp1); --tp2; while (tp1<=tp2 && (tp1-s_cop)<=max_len) *(dest++)=*(tp1++); *dest='\0'; /* terminate */ } /* get_pat */ /* End of MES.C */ e.topic) ? 1 : 0); if (field_flag&2) ret_flag|=(usindex(d_pattern,message.date) ? 2 : 0); if (field_flag&4) { sprintf(tstr,"%s %s",message.fsend,message.lsend); ret_flag|=(usindex(f_pattern,tstr) ? 4 : 0); } if (field_flag&8) ret_flag|=(usindex(t_pattern,message.receiver) ? 8 : 0); if (and_flag && (field_flag!=ret_flag)) ret_flag=0; /* not & */ } /****************************************************************************** * Metal Enter (send) message routine. * * File name: MESEND.C version 1.30xx * * Metal and Metal Message System are Trademarked and * Copyright (c) 1984 Tim Gary * All rights reserved. * * This module contains the message entry routine (enter, reply, etc) * ***************************************************************************** * * 1.30xx 6/15/85 Subject of APPLY command 'New User Application'. * 1.30xx 6/09/85 EOL char added for edit command, subject ok prompt fixed. * 1.30xx 3/03/85 Z3 stuff looked into and general touchups * 1.20b 01/10/85 Add link to messages for sysop enter message.. * 1.20b 01/07/85 Alternate end of message text char, and blank line accept * 1.20a 11/07/84 Subject confirmation on reply. * 1.20a 11/04/84 Apply stuff added, private msg to sysop. * 1.10e 11/02/84 Fixed for new get/put counters. * 1.10e 10/30/84 Added privmsgs counter. * 1.10b 10/02/84 Cosmetics (deleted extra spaces). * 1.10a 9/28/84 Edit bug looked into. * 1.10a 9/27/84 More cosmetic fixes. * 1.10a 9/14/84 Added simplistic line edit of message text... * 1.10a 9/01/84 Routine taken from MS.C for overlay metal. * * 1.01a 7/14/84 Message editing bugs fixed (delete line.. movmem changed). * Added subject truncation notice on message entry. * 1.01a 6/30/84 Cleaned up more functions. * 1.01a 6/26/84 Cleaned up a few functions, and added MULTI_USER stuff. * 1.01a 6/10/84 Fixed to work with Aztec C 1.06. Started Multi-user stuff. * * 1.0b 4/13/84 Modified for upper/lower case names, and added check for * maximum messages allowed (killed and active ones). * * 1.0a 3/16/84 Fixed reply bug. * * 1.0 1/20/84 New format of Message file headers. * p3.0 12/14/83 pre-release version 3.0 mods for MCONFIG.. * *****************************************************************************/ #include "xpm.h" #include "hmh.h" #include "hmconfg.h" #include "ctype.h" static char *lp[MAXMLINES]; /* array of pointers to msg text lines */ /************************************************************************** * enter a message, or reply to a message... mode=0 to enter, -1 to reply * * or msg # to reply without asking for #.. (ie for read/reply) * ************************************************************************** * if func=0, then reply or enter, if func=1 then APPLY command, private * message to sysop (subject 'New User Application'), func=2 then comments * to the system.. */ ovmain(func,mode) int func; /* definition required, but variable not used */ unsigned mode; { char *ptr,temp[81],*reserve; /* reserve=reserved alloc block for files */ int a,b,c,edit_mode; register int loop,line; if (O.user_types[user.type].postmsg==NO && func<1) { send("You may not enter a message until the System Operator approves it.\ \nLeave a message to the Sysop with the APPLY command if\ \nyou  would like this ability.\n"); return; } if ((totalmsgs>=O.MAXTOTMSGS) || (msgcount>=O.MAXMSGS)) { send("\nSorry, the message base is full.\nPlease try to leave your message at a later time."); return; } if (mode==0) /* regular msg entry */ { if (func<1) { ask("Who to (RETURN for all) ?", message.receiver,FNAMELEN+LNAMELEN+1,UPLOW); capstr(message.receiver); if (message.receiver[0]=='\0') strcpy(message.receiver,"ALL USERS"); } else { strcpy(message.receiver,"Sysop"); send("To: Sysop\n"); } if (func!=1) { if (get_topic(message.topic)==ERROR) return; } else strcpy(message.topic,"* New User Application *"); } else { /* reply to message */ if ((int)mode==-1) /* regular reply command.. */ { ask("Reply to what message ? ",temp,6,UP); if (!isdigit(*temp)) return; /* not alpha, return to command */ mode=atoi(temp); /* convert to number */ if (!mode) return; /* invalid message #=0 */ messages=open(MESSAGES,F_RD | F_UNLOCK); /* the following assumes open file */ } /* both regular and read/reply use the following */ /* mode=message number replying to */ /* file must be open before... from read, or whatever.. */ a=getindex(mode); /* get index into msg array, of msg mode */ if (a==ERROR) { close(messages); send("\n[Message not found]\n"); return; } setarec(messages,msg[a].seek); /* seek to message replying to */ read(messages,0); /* get the header */ movmem(bufloc(messages),&message,128); /* get stuff into structure */ sprintf(message.receiver,"%s %s",message.fsend,message.lsend); send("\nTo: "); send(message.receiver); putchar('\n'); send("Subject: "); send(message.topic); close(messages); /* close the file */ do send("\n[Is the subject ok (y/n)? ] "); while ((c=tolower(getd()))!='n' && c!='y'); if (c=='n') { send("[no]\n"); if (get_topic(message.topic)==ERROR) return; } else send("[yes]\n"); if (message.status==DEADMSG) mode=0; /* make rest of stuff nonrep */ } /* end of initial reply stuff all the rest of entermsg is as it was, except to end where pointers are setup to the reply */ if (func>=1) { send("\nMessage will be Private.\n"); message.status=PRIVMSG; } else do { message.status=NORMMSG; /* default to normal message */ if (strcmp(message.receiver,"ALL USERS")) { send("(Private/Normal) ?"); getl(buffer,UP); *buffer=tolower(*buffer); } else *buffer='n'; if (*buffer=='p') message.status=PRIVMSG; /* private msg */ else if (*buffer=='?') { send("\nTo make the message readable only by the person\n\ it is addressed to, enter P for private.\n\n\ Anything else will make the message public (normal).\n\n"); continue; /* and ask again */ } else if (*buffer!='n') send("[Normal assumed]\n"); break; /* what, you say??? yeh, yeh.. see the continue above?? */ } while (1); if (user.parm.expert==POFF) /* not expert.. tell him what to do */ { sprintf(buffer, "\nEnter message text following each line number.\ \nTo edit or end, hit RETURN alone on a line.\ \nUp to %d characters (letters/numbers) on a line,\ \nand %d lines maximum.\n",O.MAXMSGLINE,O.MLINES); send(buffer); } reserve=malloc(2*(sizeof(FILE))+10); /* make sure there's room for files */ edit_mode=ON; /* blank line to enter editor */ /********************************/ /* Lines may be up to MAXMSGLINE long, and up to MLINES lines */ /* can be entered... limitted by avaliable memory only! */ /********************************/ /* Main loop */ /****************/ for (line=1; line<=O.MLINES; line++) { cont: printf("%2d%c ",line,edit_mode ? ':' : '/'); getl(buffer,UPLOW+MSGLINE); /* get line up to MAXLINE long */ if ((edit_mode==ON && *buffer=='\0') || (edit_mode==OFF && !strcmp(buffer,"/")) ) break; if (save_line(line,buffer)==ERROR) break; /* above allocs space, and puts line there if room.. ERROR==no room */ } do { if (user.parm.expert==POFF) { send("\n(A)bort, (C)ontinue, (D)elete, (E)dit,\n\ (I)nsert, (L)ist, (R)eplace, (S)ave,\n(U)pload"); if (user.status==SYSOP) send("\n(F)ile read"); send(" :: Select"); } else if (user.status!=SYSOP) send("\nA,C,D,E,I,L,R,S,U"); else send("\nA,C,D,E,I,L,R,S,U,F"); sepstr=' '; ask(" ? ",temp,10,UP); sepstr='\0'; switch (*temp) { case '?': send("(A)bort message entry (C)ontinue entering message\ \n(D)elete line of the message (E)dit message text\ \n(I)nsert a line of text (L)ist the message"); send("\n(R)eplace line with new one (S)ave the message\ \n(U)pload mode (allows blank lines, use \"/\" to finish)"); if (user.status==SYSOP) send("\n(F)ile transfer to message text\n"); break; case 'A': ask("Are you sure you wish to abort message entry? ", buffer,3,UP); if (*buffer!='Y') break; /* nope, not sure */ for (loop=0; loopTOPICLEN) /* tell him it's too long.. */ { temp[TOPICLEN]='\0'; /* truncate topic */ printf("\nSubject truncated to: %s\n",temp); ask("Is this ok (y/n)? ",temp+TOPICLEN+2,2,UP); if (temp[TOPICLEN+2]=='N') goto about; /* ask topic again */ if (temp[TOPICLEN+2]!='Y') send("[Yes assumed]\n"); } /* I'm sick of slandering goto, in certain cases, it makes life much easier... */ strcpy(message.topic,temp); if (message.topic[0]=='\0') return ERROR; /* return hit? yep->return */ return NULL; } /******************************************************** * save line pointed to by buf, in message buffer.. * ********************************************************/ save_line(line,buf) register int line; register char *buf; { if ((lp[line-1]=malloc(strlen(buf)+2))==0) /* try to get space */ { send("\n[Message buffer full!! Line not entered]\n\ [Please save message, and continue in a new one]\n"); return ERROR; /* and exit to enter command mode */ } strcpy(lp[line-1],buf); /* setup line po inter for later use */ return NULL; } /***************************************** * read in a message from a regular file * *****************************************/ read_file(line) register int line; { char file[20]; register FILE *fd; register int oline; char *bp; int i; oline=line; /* for ending output of # lines read */ ask("\nFile to copy to message text? ",file,19,UP); if ((fd=open(file,0))!=NULL) /* try to open file */ { read(fd,1); /* fgets needs initial read */ while (line<=O.MLINES && i!=0x1a && i!=EOF) { bp=buffer; while (1) { if ((i=getc(fd))==EOF) break; if (i=='\r' || i==0x1a) break; if (i!='\n') *bp++=i; } *bp='\0'; /* terminate string */ if (save_line(line,buffer)==ERROR) break; /* no space */ send("\n"); /* to allow ^s */ printf("%2d: %s",line++,buffer); } printf("\n\n[%d lines read from %s]\n",line-oline,file); close(fd); } else send("[File NOT found]"); return line; } ins_line(cline) register int cline; { register char *ptr; register int ln,loop; char temp[11]; if (cline0) && (ln<=cline)) { printf("%3d: ",ln); getl(buffer,UPLOW+MSGLINE); if ((ptr=malloc(strlen(buffer)+2))==0) { send("\n[Message buffer FULL, line not entered!]\n"); return cline; } /* move line pos pointers up a line */ for (loop=cline+2; loop>=ln; loop--) lp[loop]=lp[loop-1]; lp[ln-1]=ptr; strcpy(ptr,buffer); /* insert the line */ cline++; /* one more line */ } else send("\n[Invalid line]"); } else { sprintf(buffer,"\n[Max of %d lines!!]",O.MLINES); send(buffer); } return cline; } /* ins_line */ del_line(cline) register int cline; { register int ln ,i; char temp[11]; ask("Delete which line ?",temp,10,UP); putchar('\n'); ln=atoi(temp); if ((ln>0) && (ln0) && (ln0) && (lnO.MAXMSGLINE) { send("\nNew line to long. Edit aborted.\n"); return; } printf("\n%3d: %s\n",ln,buffer); free(lp[ln-1]); save_line(ln,buffer); } else send("\n[Invalid line]"); } /* edit_line */ /* End of file */ /**************************************************************** * Metal Message System stuff (summary/adduser, etc..) * * File: MESTUFF.C Version 1.30xx * * Z-Msg and Metal Message System are Trademarked and * Copyright (c) 1984 Tim Gary * All Rights Reserved. * **************************************************************** * * 1.30xx 06/19/85 Expert toggle, and user name display moved here.. * 1.30xx 05/01/85 Put Adduser routine here to distribute space. * 1.30xx 03/03/85 General checkup. * 1.10e 11/01/84 Added ability to do summary of dead msgs. * 1.10e 10/30/84 Width stuff changed again. * 1.10a 9/01/84 Taken from MS.C for Overlay Metal. * ****************************************************************/ #include "xpm.h" #include "hmh.h" #include "hmconfg.h" #include "ctype.h" /*************************************************** * do a 'quick' or slow summary of the messages... * ************************************************** */ ovmain(func,parm) int func; /* not used in this overlay, but definition required */ int parm; { switch (func) { case ADDUSER: adduser((char *)parm); break; case SUMM: do_summ(parm); break; case WHO: whoisthis(); break; case EXPERT: expert(); break; } } /********************** * toggle expert mode * **********************/ expert() { user.parm.expert==PON ? /* so what if it could be an IF.. */ (send("\n[Novice mode]"),user.parm.expert=POFF) : (send("\n[Expert mode]"),user.parm.expert=PON); } /************* * Show user * *************/ whoisthis() { printf("Name - %s %s\n %s",user.first,user.last,user.city); } static unsigned dead_rec_no; static unsigned dead_user_no; adduser(nada) int nada; { register int cfast; /* fast c variable */ char first[FNAMELEN+1],last[LNAMELEN+1]; /* temp name */ char temp[MAXLINE+1]; unsigned tu; usr *up; gcntrs(0); /* get counters (date) */ do { sepstr=' '; ask("User name? ",first,FNAMELEN,UPLOW); sepstr='\0'; if (*first=='\0') break; capstr(first); ask("Last name? ",last,LNAMELEN,UPLOW); if (*last=='\0') break; capstr(last); if ((users=open(USERFILE,1))!=NULL) { /* open users file, and create it if it doesn't exist now */ up=bufloc(users); dead_user_no=dead_rec_no=up->number=0; /* clear these */ do { tu=up->number; cfast=read(users,1); /* read and increment record counter */ if (cfast!=128) break; /* exit loop if eof */ /* get desired info from users file... */ if (dead_rec_no==0) dead_user_no=tu; if (up->number==0 && dead_rec_no==0) { dead_user_no++; /* make the user one after last ok one */ dead_rec_no=getrec(users)-1; } /* see if a match of either name or user number */ if ( up->number && ((ustrcmp(first,up->first)==0) && (ustrcmp(last,up->last)==0)) ) { send("\nUser Exists, use 'E'dit to change info.\n"); break; /* exit this loop and ask for name again */ } } while (cfast==128); /* read do loop ends */ } /* good open loop */ close(users); /* user not found, get new user, location and password */ if (cfast!=128) newuser(first,last); /* newuser or bad name */ } while (1); /* new user loop */ } /**/ /* this routine checks if mistaken name, or gets new user's info */ /**/ newuser(first,last) char *first,*last; { register int cfast; char temp[MAXLINE+1]; usr userbuf; setmem(&userbuf,128,0); /* zero out buffer */ ask("\nCity, State? ",userbuf.city,CITYLEN,UPLOW); if (userbuf.city[0]=='\0') return ERROR; /* not entered, get name again */ capstr(userbuf.city); printf("\nUser is %s %s from %s", first,last,userbuf.city); ask("\nRight? ",temp,1,UP); if (*temp=='N') return ERROR; do { ask("\nPassword? ",temp,PASSLEN,UP); if (*temp=='\0') return ERROR; if (isspc(temp)) { send("\nSpaces aren't allowed in passwords!!\n"); continue; /* ask again... */ } if (isdigit(*temp)) { send("\nThe first character must NOT be numeric!!\n"); continue; } break; } while (1); users=open(USERFILE,1); /* open for r/w */ if (dead_rec_no!=0) userbuf.number=dead_user_no; else { toeof(users); if (!getrec(users)) userbuf.number=1; else { usr *up; setrrec(users,-1); read(users,1); up=bufloc(users); userbuf.number=up->number+1; } } /* printf("\nusers=%xh seek loc=%u dead_user=%u dead_rec=%u\n", users,getrec(users),dead_user_no,dead_rec_no); */ printf("\nUser number is %u.\n",userbuf.number); strcpy(userbuf.first,first); strcpy(userbuf.last,last); strcpy(userbuf.pass,temp); strcpy(&userbuf.parm.ulcase,"0000110"); /* initial user parms.. */ userbuf.lastread=0; userbuf.status=NORMAL; userbuf.type=get_type(userbuf.status); userbuf.parm.height=24; userbuf.parm.width=0; userbuf.parm.calls=1; getdate(); strcpy(userbuf.date,date); strcpy(userbuf.time,time); if (dead_rec_no!=0) setarec(users,dead_rec_no); movmem(&userbuf,bufloc(users),128); write(users,1); close(users); return NULL; /* got a new usr ok.. */ } /* newuser */ do_summ(mode) int mode; { register int flag; register unsigned start; char temp[MAXLINE+1],sreq; #ifdef MULTI_USER mu_update(); /* get anything new that's happened */ #endif *temp='\0'; if (!msgcount) return; do { /* if '?' entered, or user is novice.. print this... */ if (*temp=='?' || (user.parm.expert==POFF && strloc==0)) { send("\nEnter message number to start summary at.\n"); if (*temp=='?') search_help(); } sprintf(buffer,"\nStarting message (%u-%u) ?",fmsg,lmsg); ask(buffer,temp,MAXLINE,UP); } while (*temp=='?'); if (*temp=='K') { sprintf(temp,"%s",temp+1); mode|=0x80; } sreq=msearch(temp); /* setup search string if called for.. */ if (!strcmp(temp,"0")) *temp='1'; /* make 0 same as 1 */ if (isdigit(*temp)) /* number entered.. check if valid */  { if ((start=atoi(temp))>lmsg || start<1) { send("\n[Invalid message number]"); return; } } else if (sreq==FALSE) return; /* no #, see if search req */ else start=1; /* yep.. start at first msg */ if ((summary=open(SUMMARY,F_RD | F_UNLOCK))==NULL) return; setarec(summary,1); /* skip count */ novhelp(); /* help a local novice */ do flag=msgheader(summary,start,mode); while (!breakkey() && flag!=ERROR); close(summary); if (flag==ERROR) send("\n[End Msgs]\n"); } /* End of File */ ch_help(); } sprintf(buffer,"\nStarting message (%u-%u) ?",fmsg,lmsg); ask(buffer,temp,MAXLINE,UP); } while (*temp=='?'); if (*temp=='K') { sprintf(temp,"%s",temp+1); mode|=0x80; } sreq=msearch(temp); /* setup search string if called for.. */ if (!strcmp(temp,"0")) *temp='1'; /* make 0 same as 1 */ if (isdigit(*temp)) /* number entered.. check if valid *//**************************************************************** * Metal Sysop Routines for METAL * * * * FILE: MESYSOP.C version 1.30xx * * * * Metal and Metal Message System are Trademarked and * * Copyright (c) 1984 Tim Gary * * All rights reserved * * * **************************************************************** * 1.30xx 6/23/85 BAK files deleted before rename.. * * 1.30xx 3/03/85 Z3 stuff looked into for this module * * 1.20b 01/07/85 Double purge bug corrected. * * 1.20a 11/07/84 Purge message after effects muffled. * * 1.20a 11/04/84 Few more safeguards added. * * 1.10e 11/03/84 Ho hum, added info about disk reset, etc.. * * 1.10e 11/02/84 Make purge function work!.. (after yesterday)* * 1.10e 11/01/84 Reset disk performed before purge.. * * 1.10e 10/31/84 Added sostat() and readcomm(). * * Fixed purge messages to allow seperate output * * drive for message file. * * 1.10c 10/12/84 Modified to use msg[] table for reply/parent * * in case of conficts found earlier. * * 1.10b * * 1.10a 9/26/84 Fixed purge to allow messages on drives * * than A: * * 1.10a 9/01/84 Split from mutil.c for overlay Metal. * * * * 1.01c 8/16/84 Improved bad record handling, and patchup. * * * * 1.01b 8/03/84 Fixed to handle message purge cases when a * * summary file is unavailable, or destroyed.. * * This is handled by removing or renaming the * * the destroyed summary file, and index will be * * built from message file directly. * * * * 1.01a 6/10/84 Fixed for Aztec C 1.06. * * * ****************************************************************/ #include "xpm.h" #include "hmh.h" #include "hmconfg.h" #include "ctype.h" /* Main dispatcher */ ovmain(func,parm) int func,parm; { switch (func) { case PURGE: if (user.status!=SYSOP) return; return destroy(parm); case SOSTAT: return sostat(parm); case READCOMM: return readcomm(parm); default: send("\nUnknown overlay function called for.\n"); break; } return ERROR; } /* main */ FILE *msource,*mdest; static int new_index; destroy(parm) int parm; { int tindex; char temp[50],msgdest[30],sumdest[30],countdest[30],*tp,newdrive[10]; msg_record *mptr; new_index=0; if (!lmsg) { send("\nNo messages to purge.\n"); return; } msource=open(MESSAGES,0); printf("\nThere are %d active messages, and %d deleted messages (unpurged).\n", msgcount,mindex-msgcount); if (msource) { toeof(msource); printf("\nMessage file now %dk",(getrec(msource)+7)/8); } if (summary=open(SUMMARY)) { toeof(summary); printf(", Summary file is %dk\n",(getrec(summary)+7)/8); close(summary); } close(msource); /* cause gotta close for reset disk */ ask("\n\nPurge messages (y/n) ?",temp,1,UP); if (*temp!='Y') return; send("\nPress any key to perform a disk reset and continue.\n(swap disks NOW if you need to!) --> "); getchar(); reset_disk(0); msource=open(MESSAGES,0); mptr=bufloc(msource); *newdrive='\0'; /* nothing */ do { ask("\n\nUser area/Drive to place new files on ( uu/d: )\n(RETURN=same as message source files)? ",temp,8,UP); if (index(temp,':') || index(temp,'/')) { sprintf(buffer,"\nNew user/drive = '%s', ok (y/n)? ",temp); ask(buffer,temp+10,2,UP); if (temp[10]=='Y') { strcpy(newdrive,temp); /* put in place */ break; } continue; } else if (*temp=='\0') break; } while (1); send("\n\n[Purging messages]\n"); if (!*newdrive) { unlink("summary.bak"); rename(SUMMARY,"summary.bak"); /* backup of summary file */ summary=open(SUMMARY,1); /* make new summary file */ } else { sprintf(sumdest,"%ssummary",newdrive); unlink(sumdest); /* make sure no file previously */ summary=open(sumdest,1); } *msgdest='\0'; if (tp=index(MESSAGES,':')) /* THIS = IS ON PURPOSE !!! */ { strncpy(msgdest,MESSAGES,tp-MESSAGES+1); msgdest[tp-MESSAGES+1]='\0'; /* terminate */ } if (*newdrive) { sprintf(msgdest,"%smessages",newdrive); sprintf(countdest,"%scounters",newdrive); unlink(countdest); unlink(msgdest); } else { strcat(msgdest,"messages.new"); unlink("counters.bak"); rename(COUNTERS,"counters.bak"); /* backup counters */ *countdest='\0'; } if (*newdrive) printf("\nOutput message file is %s.\nOutput summary file is %s.\n\ Output counters file is %s.\n",msgdest,sumdest,countdest); mdest=open(msgdest,1); if (!(msource && mdest && summary)) { printf("\nCan't open all files...\nMESSAGES=%s NEWMESS=%s SUMMARY=%s \n\n", msource ? "" : "", mdest ? "" : "", summary ? "" : ""); close(msource); close(mdest); close(summary); return; } sprintf(bufloc(summary),"%u",msgcount); write(summary,1); tindex=0; while (tindexstatus!=DEADMSG) wrtmsg(mdest,tindex); /* output to file */ ++tindex; } mindex=new_index; printf("\n\nMessage file now %dk, Summary file is %dk\n\n[Finishing up]\n", (getrec(mdest)+7)/8,(getrec(summary)+7)/8); close(mdest); close(summary); close(msource); if (!*newdrive) { unlink("messages.bak"); rename(MESSAGES,"messages.bak"); /* backup message file */ rename(msgdest,MESSAGES); } pcounters(*countdest ? countdest : 0); /* write new counters file */ send("\nPress any key to return to command mode.\n(swap disks back NOW if you need to!) --> "); getchar(); reset_disk(0); /* make sure buffers flushed */ printf("\n\n[done]\n"); } /* destroy */ wrtmsg(fil,tindex) FILE *fil; int tindex; { msg_record *mptr; int lines; unsigned rseek,eseek; mptr=bufloc(msource); sprintf(buffer,"\r[Processing %5u]",mptr->number); send(buffer); msg[new_index].number=mptr->number; msg[new_index].seek=mptr->seek=getrec(fil); /* fix seek loc */ msg[new_index].parent=mptr->parent=msg[tindex].parent; /* fix if bombed */ msg[new_index++].reply=mptr->reply=msg[tindex].reply; /* from msg_alert function */ movmem(bufloc(msource),bufloc(fil),128); /* copy to output buffer */ write(fil,1); movmem(bufloc(msource),bufloc(summary),128); write(summary,1); lines=mptr->lines+1; rseek=getrec(msource); /* save location */ read(msource,1); while (lines--) while (getc(msource)!='\n'); /* flush line */ eseek=getrec(msource); setarec(msource,rseek); /* go back to begining */ while (getrec(msource)class==1) z3env=z3env->expath; /* if ext., point there */ *(z3env->wheel)=0; /* no wheel */ m_buff=(z3env->msg)+Z3MSG_OFFSET; #ifdef Z3BUG printf("\nZ3 is being used, and z3env is located at %xh.\n", (unsigned)z3env); printf("\nZ3 message buffer (@ %xh) has a value of %xh.\n", (unsigned)m_buff,(unsigned)*m_buff); #endif if (*m_buff!=(char *)0 && argc>1) { argc=-1; /* MUST do this to flag silent stuff */ g_restore(*m_buff); #ifdef Z3BUG printf("\nBack from g_restore. User name=%s %s.\n", user.first,user.last); #endif *m_buff=(char *)0; /* clear this */ } } else /* falls through */ #endif /* Z3 */ if (O.ZCPR) *O.SECURELOC=0; /* make sure system is safe */ if (argc>1) argc=ovloader(OVMENTER,argc,argv); if (argc==1) { ovloader(OVINFREQ,INIT,argc); /* initialize the works.. */ /* if auto read option ON, then do this.. */ if (user.parm.rp==POFF) { send("[Auto Read]\n"); readmsgs('P'); /* do a RP */ } } *maxuser=O.user_types[user.type].maxuser; /* fix this */ new_page(); /* reset line count */ } /* init */ /* Restore global variables */ g_restore(glob_loc) char *glob_loc; { struct g_prot *gh_p; /* header pointer */ struct g_save *gp; /* global variables pointer */ int size; gh_p=glob_loc; /* header loc */ glob_loc=gh_p->g_vars; /* skip to real fields */ #ifdef Z3BUG printf("\nglob_loc now=%x gh_p=%x\n",glob_loc,gh_p); #endif movmem(glob_loc,&user,sizeof(user)); glob_loc+=sizeof(user); gp=glob_loc; /* get misc. variables area */ #ifdef Z3BUG printf("\nUser #%d '%s %s'\n",user.number,user.first,user.last); printf("gp=%x, gp->glbstr=%x glbstr=%x\n",gp,gp->glbstr,glbstr); #endif movmem(gp->glbstr,glbstr,MAXLINE+1); /* restore command line */ #ifdef Z3BUG printf("after glbstr move, name='%s %s'\n",user.first,user.last); #endif /* msg=gp->msg; */ /* restore msg variable pointer */ strloc=gp->strloc; globalch=gp->globalch; print_flag=gp->print_flag; echo_flag=gp->echo_flag; sepstr=gp->sepstr; fmsg=gp->fmsg; lmsg=gp->lmsg; mindex=gp->mindex; msgcount=gp->msgcount; privmsgs=gp->privmsgs; nextmsg=gp->nextmsg; totalmsgs=gp->totalmsgs; callnum=gp->callnum; strcpy(date,gp->date); strcpy(time,gp->time); strcpy(last_date,gp->last_date); strcpy(last_time,gp->last_time); height=gp->height; #ifdef Z3BUG printf("\nname='%s %s'...gp=%xh\n",user.first,user.last,gp); #endif movmem(gp->path,z3env->expath,(unsigned)(2*z3env->expaths)); movmem(&(gp->cmdbuf),z3env->cl,(unsigned)(z3env->cls+4) ); } /* g_restore */ /******************************************** * Get a line of input, and do command if a * * match is found.... * ********************************************/ get_cmd(str,cmdlist) char *str; struct cmdtype *cmdlist; { register struct cmdtype *ind; /* index to go through list */ register char *chind; /* character index */ char s_time[TIMELEN+10]; char temp[MAXLINE+1]; sepstr=' '; /* allow space seperator */ do { if (O.RTC) { int mins,tm; readclock(); /* get time */ mins=timecomp(time,user.time,date,user.date); sprintf(s_time,"[%d min.] ",mins); tm=O.user_types[user.type].minutes; if (tm && mins>tm) { send("\n[Time Limit Expired]\n"); if (!strcmp(BYE,"NONE")) { char *zero=0; *zero=0xcd; exit(0); } else linkbye(); } } else *s_time='\0'; sprintf(temp,"\n%s%s",s_time,str); /* add current time to string */ ask(temp,buffer,MAXLINE,UP); /* print prompt, and get line */ if (*buffer=='/' && buffer[1]!='/') { strloc=0; /* nullify rest of line */  *buffer='\0'; continue; } } while (*buffer=='\0'); sepstr='\0'; /* turn this off */ for (ind=cmdlist; ind->abbr; ind++) { if (!strncmp(buffer,ind->abbr,strlen(ind->abbr))) { /* matched abbreviation */ chind=buffer+strlen(ind->abbr); if (!strncmp(chind,ind->full,strlen(chind))) { if (ind->ovname==0) (*ind->func)(ind->value); else ovloader(ind->ovname,ind->func,ind->value); break; /* get out of all these nested tests */ } } /* abbr. match test */ } /* search loop */ if (ind->abbr) return NULL; /* NULL=command found */ #ifdef Z3 if (O.ZCPR==3) /* if ZCPR3 is in use */ { strcpy(temp,buffer); return ovloader(OVZ3,CMD,temp); /* do alias command if found */ } else /* 'fall' through to return ERROR */ #endif return ERROR; /* command not found */ } /* get_cmd */ char ostat=0; /* these need to be externs here, since overlays */ char otype=0; /* don't like statics (they don't stick) */ /***************************** * Check if user matches the passed string *****************************/ thisis(s) register char *s; { char bs[FNAMELEN+LNAMELEN+2]; sprintf(buffer,"%s %s",user.first,user.last); strcpy(bs,s); upcase(bs); /* make passed string upper case only */ if (!ustrcmp(buffer,s) || (user.status==SYSOP && usindex("SYSOP",bs))) return TRUE; return FALSE; } /**************************************** * da..du..du..da..dat's all folks.... * ****************************************/ search loop */ if (ind->abbr) return NULL; /* NULL=command found */ #ifdef Z3 if (O.ZCPR==3) /* if ZCPR3 is in use */ { strcpy(temp,buffer); return ovloader(OVZ3,CMD,temp); /* do alias command if found */ } else /* 'fall' through to return ERROR */ #endif return ERROR; /* command not found */ } /* get_cmd */ char ostat=0; /* these need to be externs here, since overlays */ char otype=0; /* don't like statics (they don't stick) */ /***************************** * Ch.an.cm.chl.sav.dv.ud.ng.um.false.true.eq.ne.le.ge.lt.gt.rm.ml.nt.or.rs.ls.sb.jmp.swt.ue.uf.ug.ul.ur.xr.move.ARG1.ARG2.ARG3.asaveprintf_scanf_sprintf_format_Cbuffs_'Stdbufs_'sscanf_'scanfmt_'skipblan'getnum_'alloc_=morecore=free_=.lnprm=.beginGboot__Gbdoshl_Gbdos_GCPM_Gbios_Gbioshl_Gctp__KCroot_Kexit_Kunlink_Kbadfd_Knoper_Katoi_Sblockmv_Vclear_V.stlpXstrcmp_X.sylpXstrcpy_Xstrlen_Xstrncmp_Xstrncpy_Xstrcat_Xstrncat_Xindex_Xrindex_Xisspace_^isupper_^islower_^isdigit_^toupper_^tolower_^fcbinit_asettop_fsbrk_frsvstk_f$MEMRYfin_hout_hovname_jovloaderjctp__psupp8080nn!.begin5 .anin5 .cmin5 .chln5 .savn5&.retn5 ..dvn5 A.udn5signn5divsub5 .ngub5 .umub5 R.false5 a.true5 H.eqe5 W.nee5 h.lee5 g.gee5z.lediff .ltiff .gtiff.gtdiff .rmiffhlposftempf.dlpf.dj1f.dj2f .mlf.mlpf.mskf ".ntf *.orf 2.rsfYsetccf.arloop?.signp L.lsnpTlslpp \.sbp e.jmpp}jokpjdfltp .swtpswt.1pswt.defswt.3fswt.2f .ue2f .uf2f .ug2f .ul2f .ur2f .xr2f .movef .ARG1f .ARG2f .ARG3f .asavecpyloop asmret|g}o|/g}/o^#V#DM!99`is|z2xy:xz}{}}||}!}}||!}|r}|?>o&zo&|u}|>o&|o&z2xy:xz||w/g}/o#z{/W{/_{DM!>2x))z#}o|g{ :x=2xy}:x=2xy}DM!>))~ =}}}/o|/g#}|}||g}o{_r|s|7g}ot{_r)v}}o|gN#F# N#F#zy{z##^#VBK^#Vz}#y~###|#x#~#fo}|>?o&}|>o&{_r|g}os|g}o~# xv!9w~#{!||fmtio@z printf_.savf_xputchar_xformat_ scanf_+getchar_vscanfmt_V!+q`!":`9!":`9^#V!rsqb!"a!":b9!":b9^#V!uvformat" sprintf_.savtf_1spsub__Oformat_MO.anat_ .eqat_.geat_, .leat_>.mlat_kconvert_!.ltert_.ngert_$strlen_^#.swtn_$.sbn_.gtn_.chln_.umn_#^.udn_9[jYv-L5dV)VgzCwqa!"8a9^#V"`!"f9~#fo+s#rs!":f9^#V`irDMg!" 3COAYlpmd o 5ZOZZsf!"8f9^#V"d!}2e!"l9~#fo##s#r++^#Vs#r!"0l9~#fo#s#rb!!"El9s#r`i^!^wd`i^!~we`i#DM!!"El9s#r!"Uol9!"Il9s#r`i#DM+^!"2l9s#r!]|g!"2l9^#V!"Gl9~#fo#s#r+sf!!"Gl9^#Vsh!!"El9s#r! !"Uol9s! !"Vol9s! !"Wol9s!!"Xol9sz`!"Al9~#j!"l9~#fo##s#r++^#Vs!"0l9~#fo#s#rb%hhjdlxnoo[csicbbd!"2l9^#Vpezf!"0l9~#g!!"0l9^#Vhz`!*c}!"2l9~#fo|i!"0l9^#Vo!"0l9^#Vsj!*c}plk!*c}wm!!sn*bqo!!!"An9s#r!"0n9s#r!*c}!"2n9s#r!-w`!!"An9s#r*b+"ba!"2n9^#V!+wb*b+"bc!*c}*b+"b#|e!*c}!":n9^#V~DM|f!*c}e!" 6 #=t>6#=u wx0_zWv/yz : >{ A|[}@~a|{|`w# .qrsw#p{o|g rsw#t&jz!|*u >?a{ 0:v7sbrkGzz settop_ sbrk__ 6rsvstk_ $MEMRYsbrk11sbrk2safety!t#|+!9^#V*su*v9}|u*s"s|ɯ=go!9~#f/o|/g#"vport,llINCC5OUTC5*fRETC5 in_C5 out_C5TMPC5!9f."u!!u26uo&!9~++f."u!!u26umovload:H xovname_ ovloader_ovld_r.sav_rstrcmp_ .nemp_vstrcpy_ open__loadaboruread_rmw.uld_r(6close_r>printf_@0i&!9^#V"prsb!`*atd*cue*a!`v!!`w!"2b9s#rzf! !"4b9^#Vx!!c!"6b9^#Vyug!!"4b9^#Vx*cuh!!"4b9^#Vx*!c4*!c2!"6b9^#Vy*!c4zi!2!"4b9^#Vx!"2b9^#V{*!c6sj!}2`!":j9^#V!!k0|!"8j9^#V{! Overlay error #%d.ctype&, !ctp__5 00000   @@@@@@@@@@@@@@@ @@@@@@@ @@@@@ @@@@ movload:H xovname_ ovloader_ovld_r.sav_rstrcmp_ .nemp_vstrcpy_ open__loadaboruread_rmw.uld_r(6close_r>printf_@0i&!9^#V"prsb!`*atd*cue*a!`v!!`w!"2b9s#rzf! !"4b9^#Vx!!c!"6b9^#Vyug!!"4b9^#Vx*cuh!!"4b9^#Vx*!c4*!c2!"6b9^#Vy*!c4zi!2!"4b9^#Vx!"2b9^#V{*!c6sj!}2`!":j9^#V!!k0|!"8j9^#V{! Overlay error #%d./**************************************************************** * User edit/add routines for Metal/Z-MSG version 1.30xx * * * * FILE: MUTIL.C version 1.30xx * * * * Copyright (c) 1984 Tim Gary * * All rights reserved * * * **************************************************************** * * * 1.30xx 6/29/85 Packed down to under 8k.. must stay this way * * 1.30xx 5/26/85 Minor cosmetic bugs fixed (prompt mode, etc) * * 1.30xx 5/15/85 Edit user function made simpler. * * 1.30xx 5/01/85 Split Add function to other overlay (space) * * 1.30xx 4/25/85 Edit user fixed... was wiping previous user * * 1.30xx 4/08/85 Fixed so selective read user funcs work * * 1.30xx 4/04/85 Few bug fixes (won't re-delete users) * * 1.20c 04/01/85 Not an April Fools joke.. mass stuff added * * 1.20c 03/29/85 Still more mass user stuff added * * 1.20c 03/23/85 More advanced mass-user delete method.. * * 1.20a 11/07/84 More work on the ADD command (gcntrs change) * * 1.10e 11/03/84 # calls initialized in ADD * * 1.10e 10/30/84 User width initialized. * * 1.10a 9/12/84 Cosmetic fixes. * * 1.10a 9/08/84 Cosmetic fixes. * * 1.10a 9/01/84 Split from mutil for overlay Metal. * * * * 1.01a 6/10/84 Fixed for Aztec C 1.06. * * * * 1.0b 4/13/84 Fixed for upper/lower case names. * * * ****************************************************************/ #include "xpm.h" #include "hmh.h" #include "hmconfg.h" #include "ctype.h" static int dead_rec_no=0; /* for deleted user */ static int dead_user_no=0; /* main program */ ovmain(func,parm) int func; char *parm; { if (user.status==SYSOP) { if (func==EDITUSER) { init_tags(); user_sweep(parm); } else { /* delete user */ users=open(USERFILE,1); if (finduser(parm)!=ERROR) purge_user(); close(users); } } } /* main */ edituser() { register int cfast; char temp[MAXLINE+1]; usr *up; up=bufloc(users); /********************************** * begin editing user * *********************************/ send("\n[Edit]\n\nHit return if no change.\n"); do { sprintf(buffer,"Name: %s %s : ",up->first,up->last); sepstr=' '; ask(buffer,temp,FNAMELEN,UPLOW); sepstr='\0'; if (*temp!='\0') { capstr(temp); if (isdigit(*temp)) { send("First char can't be numeric!"); continue; } else { strcpy(up->first,temp); break; } } } while (*temp!='\0'); if (*temp) do { sprintf(buffer,"Last name: %s : ",up->last); ask(buffer,temp,LNAMELEN,UPLOW); if (*temp!='\0') { capstr(temp); strcpy(up->last,temp); break; } } while (*temp!='\0'); sprintf(buffer,"City: %s : ",up->city); ask(buffer,temp,CITYLEN,UPLOW); capstr(temp); if (*temp!='\0') strcpy(up->city,temp); do { sprintf(buffer,"Password: %s : ",up->pass); ask(buffer,temp,PASSLEN,UP); if (*temp!='\0') { if (isdigit(*temp)) { send("First char can't be numeric!"); continue; } else { strcpy(up->pass,temp); break; } } } while (*temp!='\0'); do { sprintf(buffer,"Status: '%c' (%s) :",up->status,up->status==SYSOP ? "SYSOP" : up->status==SPECIAL ? "SPECIAL" : up->status==NORMAL ? "NORMAL" : up->status==NOCPM ? "NO OS" : up->status==TWIT ? "*TWIT*" : "OTHER"); ask(buffer,temp,10,UPLOW); if (*temp=='\0') continue; if (!index("+snxXabc",*temp)) { send("Bad status. Try:\n'+' for SYSOP\n's' for SPECIAL\ \n'n' for NORMAL\n'x' for NO Operating System\n'X' for TWIT\ \nor 'a','b' or 'c' for user defined types\n"); continue; } else { up->status=*temp; up->type=get_type(up->status); break; } } while (*temp!='\0'); write(users,0); /* write new version */ send("[Saved]\n"); } /* edituser */ user_sweep(name) char *name; { register int flag; /* to abort do loop */ int offset,c,all; char temp[MAXLINE]; usr *up; all=FALSE; flag=TRUE; users=open(USERFILE,1); if (users==NULL) { send("\nNo Users file.\n"); return ERROR; } if (name) strcpy(temp,name); else *temp='\0'; if (strloc && !(*temp)) ask("",temp,FNAMELEN+LNAMELEN+3,UPLOW); /* fudge to get parm */ if (*temp) { /* if name passed, then it's from the selective read */ if (finduser(temp)!=ERROR) edituser(); close(users); return TRUE; } offset=0; up=bufloc(users); do { setrrec(users,offset); if (read(users,0)!=128) { putchar('\n'); /* mark end of file */ if (getrec(users)==0) { send("\nRead ERROR.\n"); close(users); return ERROR; } setarec(users,0); offset=0; continue; } if (!all && up->number==0) { if (offset==0) offset=1; continue; /* skip deleted users */ } offset=0; /* clear this afterwards */ out_user(); send("--> "); switch(c=tolower(getchar())) { case ' ': case '\n': case '\r': offset=1; /* advance */ break; case 'b': case '-': /* backup one user */ case '\b': offset=-1; break; case 'd': /* delete? */ purge_user(); offset=1; /* and bump past him */ break; case 'u': unpurge_user(); /* undelete this user... */ break; case 'a': /* show all users (deleted ones too..) */ all= all ? FALSE : TRUE; if (all) send("\n[All users]"); else send("\n[Only active Users]"); break; case 'z': /* to eof */ toeof(users); offset=-1; /* so next read will backup */ break; case 'm': /* mass delete from current position */ mass_func(); break; case 't': tag_users(); break; case 'i': printf("\nFrom: %s\nPass: %s\n",up->city,up->pass); break; case 'e': /* edit this user */ edituser(); break; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': sprintf(temp,"%c",(char)c); /* start of number */ while ( isdigit(c=getchar()) && strlen(temp) ",temp,FNAMELEN+LNAMELEN+2,UPLOW); if (*temp) finduser(temp); break; case 'x': /* abort this mode */ flag=FALSE; break; default: sweep_help(); } /* switch */ putchar('\n'); /* goto next line */ } while (flag); /* do... */ close(users); return NULL; } /* deleteuser */ sweep_help() { static char *sw_help[] = { "\n\n or = Advance one user.", "\n, 'b' or '-' = Backup one user.", "\n = Advance to user number.", "\n'a' = All users display toggle (show deleted users)", "\n'd' = Delete user. 'e' = Edit user.", "\n'f' = Find user by name. 'i' = Display more user info.", "\n'm' = Mass user function (SET TAGS FIRST).", "\n't' = Tag users. 'u' = Undelete user.", "\n'x' = Exit to BBS. 'z' = Goto last user.\n\n", 0 }; dis_text(sw_help); } out_user() { char temp[MAXLINE],temp1[FNAMELEN+LNAMELEN+5]; usr *up; up=bufloc(users); sprintf(temp1,"%s %s",up->first,up->last); sprintf(temp,"%4u (%c) %4u calls. %8s %-26s ",up->number,up->status, up->parm.calls,up->date,temp1); send(temp); } purge_user() /* delete user at current location */ { usr *up; register unsigned tu; up=bufloc(users); if ((tu=up->number)==0) return; /* ignore already deleted users */ if (tu==1) { send("\nCan't delete User #1 !!"); return; } printf("\n[User #%u deleted]",tu); up->number=0; /* zero out.. */ write(users,0); /* and do this... */ } unpurge_user() /* delete user at current location */ { unsigned rec,tu; usr *up; rec=getrec(users); up=bufloc(users); if (up->number!=0) return; /* not dead to start with */ if (rec) do { /* search for valid user to count from */ setrrec(users,-1); read(users,0); } while (up->number==0 && getrec(users)!=0); tu=up->number+(rec-getrec(users)); if (!tu) tu++; /* if zero, increment to make 1 */ setarec(users,rec); /* back to where we belong */ read(users,0); printf("\n[User #%u restored]",tu); up->number=tu; /* zero out.. */ write(users,0); /* and do this... */ } #define LT 3 #define GT 2 #define EQ 1 #define NOT 256 static char date_pat[DATELEN+1]; /* date pattern */ static int date_flag; /* flag if date < or > or == */ static char stat_pat[10]; /* status matchers */ static int stat_flag; /* flag if status == or != */ static int calls_num; /* # of calls matcher */ static int calls_flag; /* if < or > or == */ static int prompt_flag; /* wether or not prompted mode */ init_tags() { *date_pat=*stat_pat='\0'; /* clear date/status flags */ date_flag=stat_flag=calls_flag=prompt_flag=calls_num=0; } show_tags() { printf("\n\nDate: %s %s Status: %s %s Calls: %s %u\n", date_flag==GT ? ">" : date_flag==LT ? "<" : date_flag==EQ ? "=" : "(none)",date_pat, stat_flag==EQ ? "=" : stat_flag==NOT ? "NOT" : "(none)",stat_pat, calls_flag==GT ? ">" : calls_flag==LT ? "<" : calls_flag==EQ ? "=" : "(none)",calls_num); } /* show pat */ mass_func() { unsigned start_rec; /* initial record #, and one to change */ int flag; char temp[MAXLINE+1]; if ( !(calls_flag+stat_flag+date_flag) ) { send("\nNo 'Tags' set. Use the 'T' function to set them.\n\n"); return; } show_tags(); send("\nNote: function starts scanning at the CURRENT location,\n\ NOT at the start of the users file!!\n\n"); ask("Perform mass delete function (y/n)? ",temp,2,UP); if (*temp!='Y') return; sprintf(temp,"Prompted mode (RETURN=%s)? ",prompt_flag ? "YES" : "NO"); ask(temp,temp,2,UP); switch (*temp) { case 'N': prompt_flag = !prompt_flag; break; case 'Y': prompt_flag = YES; break; case '\0': break; default: send("[aborted]\n"); return; } /* switch */ start_rec=getrec(users); /* save starting place */ while (read(users,0)==128) { usr *up; up=bufloc(users); flag=match_date(); /* check for date match */ flag&=match_calls(); /* check for calls match */ flag&=match_stat(); /* see if status matches */ if (flag && up->number) /* if not already gone, and a match.. */ { if (prompt_flag) { out_user(); send("Delete? "); *temp=tolower(getchar()); if (*temp=='y') purge_user(); if ( ((*temp)&0x0b) == 0x0b) /* ^k to abort */ { send("[Purge aborted]"); break; } else send("\n[User REMAINS]"); putchar('\n'); } else purge_user(); } setrrec(users,1); /* goto next record location for read */ if (breakkey()) { send("\n[Mass deletion aborted!]\n"); break; } } /* while */ setarec(users,start_rec); /* back to where we began */ read(users,0); /* and read */ } /* mass function */ match_date() { int flag; usr *up; char td_pat[DATELEN],td_usr[DATELEN]; up=bufloc(users); if (!date_flag) return TRUE; /* fake match if no date pattern */ strncpy(td_pat,date_pat+6,2); strncpy(td_pat+2,date_pat,2); strncpy(td_pat+4,date_pat+2,2); td_pat[6]='\0'; strncpy(td_usr,up->date+6,2); strncpy(td_usr+2,up->date,2); strncpy(td_usr+4,up->date+2,2); td_usr[6]='\0'; if (date_flag==EQ && !strcmp(td_usr,td_pat)) return TRUE; if (date_flag==LT && (strcmp(td_usr,td_pat)==-1)) return TRUE; if (date_flag==GT && (strcmp(td_usr,td_pat)==1)) return TRUE; return FALSE; } match_stat() { usr *up; int flag; up=bufloc(users); if (!stat_flag) return TRUE; /* fake match if no status pattern */ flag=index(stat_pat,up->status); if (stat_flag==EQ && flag) return TRUE; /* match */ if (stat_flag==NOT && !flag) return TRUE; /* also a match */ return FALSE; /* otherwise no match */ } match_calls() { usr *up; up=bufloc(users); if (!calls_flag) return TRUE; /* fake match if no calls pattern */ if (calls_flag==EQ && up->parm.calls==calls_num) return TRUE; if (calls_flag==LT && up->parm.callsparm.calls>calls_num) return TRUE; return FALSE; /* otherwise no match */ } tag_users() { char temp[MAXLINE+1]; /* parm holder */ show_tags(); ask("\nChange current tags (y/n)? ",temp,2,UP); if (*temp!='Y') return; send("\nReturn alone at a prompt CLEARS that match string!\n"); do { *date_pat='\0'; /* clear this */ date_flag=0; /* and this */ ask("\nDate match string (? for help) -> ",temp,DATELEN+5,UP); if (*temp=='?') { send("\nMatch string is a condition followed by the date (no space).\n\ Conditions are '>' (greater than), '<' (less than), and '=' (equal to).\n"); send("The date is of the format MM/DD/YY (month/day/year).\n\ Ex: >08/09/84 Dates after 08/09/84.\n"); send(" <01/01/85 Dates before Jan. 1, '85.\n\ 02/28/85 Only this date (same as =02/28/85).\n\n"); continue; } switch (*temp) { case '\0': break; case '>': date_flag=GT; /* Greater than flag */ strcpy(date_pat,temp+1); break; case '<': date_flag=LT;  strcpy(date_pat,temp+1); break; case '=': date_flag=EQ; strcpy(date_pat,temp+1); break; default: if (isdigit(*temp)) { date_flag=EQ; strcpy(date_pat,temp); break; } else { *temp='?'; send("\nBad Match string.\n"); } break; } /* switch */ } while (*temp && (strlen(temp)!=9) ); /* date match question */ do { *stat_pat='\0'; stat_flag=0; ask("\nUser Status match string (? for help) -> ",temp,10+3,UPLOW); if (*temp=='?') { send("\nMatch string is a condition followed by the Status Chars. (no space)\n\ Conditions are '=' (equal to), and '!' (not equal to).\n"); send("Status Characters are one of the following (check manual): +,s,n,x,X,a,b,c\n\ Examples: =ns Matches all normal ('n') and Special ('s') users.\n"); send(" !abc Matches everything but 'a','b' or 'c' type users.\n\ xX Matches no-os and twits (same as '=xX').\n\n"); continue; } switch (*temp) { case '\0': break; case '=': stat_flag=EQ;  strcpy(stat_pat,temp+1); break; case '!': stat_flag=NOT; strcpy(stat_pat,temp+1); break; default: if (index("+snxXabc",*temp)) { stat_flag=EQ; strcpy(stat_pat,temp); break; } else { *temp='?'; send("\n[Bad Match String]\n"); } break; } /* switch */ } while (*temp && (strlen(temp)<2) ); /* match question */ do { calls_num=0; calls_flag=0; ask("\nTimes user has called match string (? for help) -> ",temp,10,UPLOW); if (*temp=='?') { send("\nMatch string is a condition followed by the number of calls value.\n\ Conditions are '>' (greater than), '<' (less than), and '=' (equal to).\n"); send("Ex: >100 Called more than 100 times.\n\ <2 Called less than 2 times.\n"); send(" 0 (same as '=0') 0 times callers ('add' users).\n\n"); continue; } switch (*temp) { case '\0': break; case '=': calls_flag=EQ; calls_num=atoi(temp+1); break; case '>': calls_flag=GT; calls_num=atoi(temp+1); break; case '<': calls_flag=LT; calls_num=atoi(temp+1); break; default: if (isdigit(*temp)) { calls_flag=EQ; calls_num=atoi(temp); break; } else { *temp='?'; send("\n[Bad Match String]\n"); } break; } /* switch */ } while (*temp && (strlen(temp)<2) ); /* match question */ show_tags(); } /* tag_users */ finduser(name) char *name; { register int cfast,dir; char temp[MAXLINE+1]; usr *up; if (!name) { ask("Enter user # or full/partial name? ",temp,MAXLINE,UP); if (*temp=='\0') return ERROR; /* exit to main */ } else strcpy(temp,name); /* ok.. now check if name entered, or user number */ up=bufloc(users); setarec(users,isdigit(*temp) ? atoi(temp)-1 :0); /* fix for search, if any */ dir=1; /* forward */ send("\n[Searching.."); while ((cfast=read(users,dir))==128) { if (!(getrec(users)%25)) putchar('.'); cfast=128; if (up->number!=0) { if (isdigit(*temp)) { if (up->number==atoi(temp)) break; else { dir=-1; setrrec(users,dir); } } else { sprintf(buffer,"%s %s",up->first,up->last); if (usindex(temp,buffer)) break; /* found him */ } /* I know.. the index func. is backwards.. */ } } if (cfast!=128) { send("]\n[Not found]"); return FALSE; } setrrec(users,-dir); /* back to where user was actually read */ putchar(']'); /* make things look neato */ return TRUE; } /* End Of File */ /******************************************************************** * ZCPR3 routines for Metal/Z-MSG * * File: MEZ3.C version 1.30xx * * Copyright (c) 1984 Tim Gary * All Rights Reserved. * ******************************************************************** * * 1.30xx 7/01/85 Print/echo flags saved... * 1.30xx 6/09/85 New bye stuff deleted, new protect method done. * 1.30xx 5/26/85 Save bye stuff if bye is active.. (at new topmem loc) * 1.30xx 5/25/85 Msg pointer saved in gp area, see also meinfreq.. * 1.30xx 5/12/85 Bug in calculations fixed. * 1.30xx 5/11/85 Protection code that should work with bye.. * 1.30xx 5/09/85 Protect mode working... * 1.30xx 5/05/85 Modified Path stuff, fixed protection for globals. * 1.30xx 5/03/85 Z3 Path stuff saved, and used in alias command lines. * 1.30xx 5/02/85 Z3BUG turned off, Z3MSG_OFFSET added, glbstr buffer * save fixed.. * 1.30xx 5/01/85 Error returned only if command not found, not if *  can't access it. ALIASRET define used. If allocation * error, command line is restored. * 1.30xx 4/28/85 Z3BUG stuff added. * 1.30xx 4/26/85 Fix for saving command buffer before entering Z3 * 1.30xx 4/04/85 Etc.. * 1.30xx 3/03/85 Back to work. * 1.30xx 2/26/85 Command routine started. * ********************************************************************/ /* #define Z3BUG */ /* for Z3 alias debugging */ #include "xpm.h" #include "hmh.h" #include "hmconfg.h" #include "ctype.h" ovmain(func,parm) register int func; register char *parm; { #ifndef Z3 return ERROR; #else switch (func) { case CMD: return do_command(parm); default: send("\nMEZ3: Unknown Overlay function called for.\n"); return ERROR; } #endif } #ifdef Z3 /************************************************************************* * do_command looks for a command in a file of the following format: * * Status mask Command name Number of parms Alias command name * (4 hex chars) (small string) in alias ONE WORD ONLY! * * All fields are seperated by a space. * * *** EVERY FIELD MUST BE PRESENT!!!!!! *** * * The number of parms is not currently acurate. If there are * more than zero parms expected, it will take the rest of the line up * to the next ';' character (or eol). It does NOT take several parms * based on the value you give it. * When the alias is performed, and execution should return to * metal upon termination. This will be fairly slow, but it should * work ok. * ************************************************************************/ do_command(name) char *name; { FILE *commands; unsigned flags; /* temp storage of current mask flag from file */ char cmd_name[20]; /* current command name in file */ int n_parms; /* number of parms */ char alias[MAXLINE+1]; /* alias to use, parms are simply appended */ char *ccl; /* pointer to current command line */ char *ts; char a_user,a_drive; /* user/drive alias is in */ int ti; char *index(); static struct cmd_line savecmd; if ((commands=open(COMMANDS,0))==0) return ERROR; #ifdef Z3BUG printf("\nCommands file open, trying to match --> '%s'.\n",name); #endif read(commands,1); /* fill buffer to start with */ while (1) { fgets(buffer,commands); if (strlen(buffer)<10) break; /* EOF.... */ while (*buffer=='\n' || *buffer=='\r') strcpy(buffer,buffer+1); sscanf(buffer,"%x %s %d %s",&flags,cmd_name,&n_parms,alias); #ifdef Z3BUG printf("\nFlag='%x' User flag='%x'\nCommand name='%s' Number of parms='%d' Alias='%s'.\n",flags,O.user_types[user.type].flags,cmd_name,n_parms,alias); #endif if ( !(flags & O.user_types[user.type].flags) || (ustrcmp(name,cmd_name))) continue; /* command doesn't match or not allowed */ /* Ok, got here, command matches and available to this user */ /* ts=1+index(1+index(1+index(buffer,' '),' '),' '); point to alias */ ccl=z3env->cl->buffer; /* point to z3 command line buffer */ movmem(z3env->cl,&savecmd,z3env->cls+4); /* save for later */ a_user=0; a_drive=1; /* normally use A0: */ if (index(alias,':') && (index(alias)<(5+alias)) ) { a_user=atoi(alias+1); /* must be duu:alias format */ a_drive=1+(tolower(*alias)-'a'); strcpy(alias,index(alias,':')+1); /* delete drive spec */ } sprintf(ccl,"%s ",alias); if (n_parms && strloc) /* get parm if there is one on the line */ { ask("",buffer,40,UPLOW); /* get next parm */ strcat(ccl,buffer); /* append parm to command line */ } strcat(ccl,ALIASRET); /* make sure we return ok.. */ z3env->cl->next_char=ccl; close(commands); #ifdef Z3BUG printf("Command line buffer (Z3 one) is at %xh. Contents at %xh='%s'.\n", z3env->cl,ccl,ccl); #endif do_alias(&savecmd,a_user,a_drive); /* never returning function */ return NULL; /* if we're here, there's a problem */ } /* if we get here, there were problems */ close(commands); return ERROR;  } /* do_command */ /* char *ptr; int fixup(); */ /* do_alias function saves globals, and warm boots to perform command */ do_alias(savecmd,a_user,a_drive) struct cmd_line *savecmd; char a_user,a_drive; { struct g_save *gp; /* pointer to global variable area */ struct g_prot *gh_p; /* pointer to globals protect header */ /* char *troom; */ /* allocated space to play it safe */ char *g_v,*global_loc; /* pointer to start of all globals (msg, user, etc.) */ char **m_buff; /* pointer to char pointer */ char *ptr; int size,i; global_loc=g_v=malloc(sizeof(user)+sizeof(struct g_save)); #ifdef Z3BUG printf("\n%xh bytes of free memory required.",sizeof(user)+sizeof(struct g_save) ); printf("\nMalloc=%xh (zero indicates not enough space)\n",global_loc); #endif if (!global_loc) { movmem(savecmd,z3env->cl,(unsigned)((z3env->cls)+4)); if (user.status==SYSOP) send("\nERROR: Insufficient memory for aliases."); else send("\nCommand unavailable at this time.\n"); return ERROR;  } /* to protect the private global area, we do a bye-like fake of top memory */ ptr=*((char **)0001)+3; /* Point to bios jump table */ g_h.obdos=*((char **)0x0006); /* warm boot address */ g_h.g_vars=g_v; /* pointer arith!.. pt. to globals */ movmem(ptr,g_h.bt,18); /* copy old bios jmp table */ g_h.prot_bdos=z3_hp; /* address of our bdos jmp (defined in main) */ /* if (bye!=nothing) movmem(g_h.obdos+0x0c,g_h.bye_a1,32); */ /* save bye vars */ /* this must go before the loop. z3_hp defined in main */ movmem(&g_h,z3_hp,sizeof(g_h)); /* move to actual location */ for (i=0; i<6; i++) { unsigned *uptr; z3_hp->abt[i].addr=z3_hp->bt[i].addr; /* fill in our new bios jumps */ z3_hp->abt[i].swapbdos=&(z3_hp->swap); uptr=(ptr+(3*i)+1); *uptr=&(z3_hp->abt[i]); /* store new bios vector */ } #ifdef Z3BUG printf("\nz3_hp=%xh z3_hp->g_vars=%xh\n",gh_p,gh_p->g_vars); #endif #ifdef Z3BUG printf("\nAfter swap, *(0006)=%xh.\n",*(int *)0006); #endif g_v=(z3_hp->g_vars); /* point to loc for variables */ movmem(&user,g_v,sizeof(user)); g_v+=sizeof(user); gp=g_v; /* compute gp like this or problem might occur */ #ifdef Z3BUG printf("gp=%xh msg=%xh (msg should be higher!)\n",gp,msg); #endif gp->msg=msg; /* save location of msg array */ movmem(glbstr,gp->glbstr,MAXLINE+1); gp->strloc=strloc; gp->globalch=globalch; gp->print_flag=print_flag; gp->echo_flag=echo_flag; gp->sepstr=sepstr; gp->fmsg=fmsg; gp->lmsg=lmsg; gp->mindex=mindex; gp->msgcount=msgcount; gp->privmsgs=privmsgs; gp->nextmsg=nextmsg; gp->totalmsgs=totalmsgs; gp->callnum=callnum; strcpy(gp->date,date); strcpy(gp->time,time); strcpy(gp->last_date,last_date); strcpy(gp->last_time,last_time); gp->height=height; movmem(z3env->expath,gp->path,(z3env->expaths)*2); (z3env->expath)[0]=a_drive; /* setup alias drive/user */ (z3env->expath)[1]=a_user; (z3env->expath)[2]=1; /* setup A0: for bbs re-entry */ (z3env->expath)[3]=0; (z3env->expath)[4]=0; /* end of table */ /* save command buffer, away.. 4 bytes overhead for info, and buflen+1 */ movmem(savecmd,&(gp->cmdbuf),(unsigned)(z3env->cls+4)); ptr=0; *ptr=0xc3; /* make safe to warm boot */ /* now we put location of global save spot in message buffer (0x48/9) */ m_buff=z3env->msg+Z3MSG_OFFSET; *m_buff=z3_hp; /* global_loc; */ /* save this away */ #ifdef Z3BUG printf("Command line buffer (Z3 one) is at %xh. Contents are '%s'.\n", z3env->cl,z3env->cl->buffer); printf("Old contents were '%s'.\n",savecmd->buffer); #endif exit(0); /* and do so */ } /* routine generally never returns */ #endif /* Z3 */ /* eof.. */ gp->time,time); strcpy(gp->last_date,last_date); strcpy(gp->last_time,last_time); gp->height=height; movmem(z3env->expath,gp->path,(z3env->expaths)*2); (z3env->expath)[0]=a_drive; /* setup alias drive/user */ (z3env->expath)[1]=a_user; (z3env->expath)[2]=1; /* setup A0: for bbs re-entry */ (z3env->expath)[3]=0; (z3env->expath)[4]=0; /* end of table */ /* save command U''`i"uy"v"w"t!9"sr*t*uDM{*v*w!9^#V*szp .ovbgn5 4ovexit_ovmain_ovstkptsaveretbcsaveixsaveiysave clrbsssavedone-ovretneGrestdoneera $1.o CII -y25 -x2500 -z2000 -e100 $1.C AS $1.ASM ERA $1.ASM MESEND C +MESTUFF C 5,-./012MESYSOP C ?3456789:METAL C d;<=>?@ABCDEFGMETALIB LIBrHIJKLMNOPQRSTUVMEUSER C WXYZ[\]^_`abcdefMEUSER C gMEZ3 C EhijklmnopMOVBGN O qUCOMP SUB#define C105 /* * Header file..... * xPM.H: VERY small i/o package (cpmio.c) header file... * includes console and file i/o * Objective was to make a SIMPLE, efficient, WORKING! I/O package to * use in the Metal Message system. * * Copyright (c) 1984 Tim Gary * Delphi Data Systems * All Rights reserved. * * * 10/04/84 Full USER area change for read/write ops supported. * 10/03/84 Added reset_disk() define for bdos disk system reset. * * CP/M and MP/M are registered trademarks of Digital Research. * TurboDOS is a registered trademark of Software 2000, Inc. */ #define ERROR -1 #define EOF -1 /**************************************** * differences from 1.05 and 1.06 * ****************************************/ #ifdef C105 #define malloc(a) alloc(a) /* for name change */ #define movmem(a,b,c) blockmv(b,a,c) /* name and order change */ #define setusr(a) bdos(32,a) /* everything change */ #define setmem(a,b,c) clear(a,b,c) /* name change */ #endif /* Ways to open files... */ #define F_RD 0 /* open for read (just says not to MAKE file) */ #define F_RW 1 /* open/make file */ #define F_UNLOCK 0x10 /* open in multiuser unlocked mode */ #define F_RO 0x20 /* open for Read only (multiuser) */ #define F_LOCK 0 /* open in locked mode ( " ) */ /* define a xP/M fcb, length of it is 36 bytes */ struct fcb { char f_drive; /* drive code 0=current, 1=A, etc... */ char f_name[8]; /* file name, up to 8 chars in length */ char f_type[3]; /* file type (extention), 3 chars long */ char f_ext; /* curret extent number */ char f_resv[2]; /* internal cp/m use, 0's initially ! */ char f_rc; /* extent record count */ char f_sydx[16]; /* disk map */ char f_cr; /* current record for r/w */ unsigned f_record; /* random record number (low 2 bytes) */ char f_overfl; /* random record number high byte */ }; /* this is the buffered file structure... use 'FILE *fil;' in declarations */ typedef struct { struct fcb _fcb; /* pointer to fcb (must be first item */ char _buffer[128]; /* cpm sector buffer.. */ char *_bp; /* buffer pointer.. to current char */ char _user; /* user number file is in */ } FILE; #define _BUFSIZ 128 /* for now use 128 byte buffer */ #define bufloc(fd) ((fd)->_buffer) /* pointer to begin of buffer.. */ #define gchar(fd) (*(fd)->_bp++) /* get next char from buffer, increment */ #define pchar(fd,ch) (*(fd)->_bp++=ch) /* put char in buffer, increment*/ #define setbuf(fd,pos) ((fd)->_bp=fd->_buffer+pos) /* set buffer pointer */ #define getbuf(fd) ((fd)->_bp - (fd)->_buffer) /* offset pos of _bp */ #define eobuf(f) (getbuf(f)>=_BUFSIZ) /* end of buffer indicater... */ #define setarec(fd,pos) ((fd)->_fcb.f_record=pos) /* set absolute record*/ #define setrrec(fd,offset) ((fd)->_fcb.f_record+=offset) /* set rel rec */ #define getrec(fd) ((fd)->_fcb.f_record) /* like tell function */ #define toeof(fd) bdos(35,fd) /* seek to end of xP/M file */ #define reset_disk(nada) bdos(13,nada) /* reset disk system for disk change */ r.. to current char */ char _user; /* user number file is in */ } FILE; #define _BUFSIZ 128 /* for now use 128 byte buffer */ #define bufloc(fd) ((fd)->_buffer) /* pointer to begin of buffer.. */ #define gchar(fd) (*(fd)->_bp++) /* get next char from buffer, increment */ #define pchar(fd,ch) (*(fd)->_bp++=ch) /* put char in buffer, increment*/ #define setbuf(fd,pos) ((fd)->_bp=fd->_buffer+pos) /* set buffer pointer */ #define getbuf(fd) ((fd)->_bp - (fd)->_buffer) /* offset pos of _bp */ #define eobuf(f) (getbuf(f)>=_BUFSIZ) /* end of buffer indicater... */ #define setarec(fd,pos) ((fd)->_fcb.f_record=pos) /* set absolute record*/ #define setrrec(fd,offset) ((fd)->_fcb.f_record+=offset) /* set rel rec */ #define getrec(fd) ((fd)->_fcb.f_record) /* like tell function */ #define toeof(fd) bdos(35,fd) /* seek to end of xP/M file */ #define res/* * Very RAW xP/M i/o routines... THESE ARE FOR AZTEC C 1.06 * * FILE: XPMIO.C 10/28/84 * * Copyright (c) 1984 Tim Gary * Delphi Data Systems * All rights reserved. * * * 01/30/85 Allow getchar/putchar, etc.. with a single define.. default is * to exclude those routines.. * 10/28/84 uread function bug fixed (wrong byte_rem_count). * * User area for each file is kept track of for all reads/writes, not * just set when file was opened. * * If the macro MULTI_USER is defined, then file operations are for * MP/M and TURBODOS Multi-user operating systems. * * CP/M and MP/M are registered trademarks of Digital Research. * TURBODOS is a registered trademark of Software 2000, Inc. */ #include "xpm.h" #define NULL 0 /* bdos call numbers.... */ #define DIRIO 6 #define SELDRV 14 /* file i/o stuff */ #define OPNFIL 15 #define CLSFIL 16 #define DELFIL 19 #define MAKFIL 22 #define SETDMA 26 #define SETUSR 32 #define READRN 33 #define WRITRN 34 #define FILSIZ 35 #define SETREC 36 #define kbhit() bdos(CONSTAT,0) /* console status.. */ /* open a file .. direct cpm open, allocates a buffer for FCB/record inform of * FILE... If file exists, a simple open is done.. * if non-existant, a file is made.. * if couldn't make.. then return NULL as error... * Try and be sure to close opened files (assuming they were successfully * opened), since buffer space is dynamically allocated. */ FILE *open(name,mode) register char *name; register int mode; /* see xpm.h for modes.. */ { register FILE *fd; int err_code; /* from open file function */ if ((fd=malloc(sizeof(FILE)+1))!=NULL) { setmem(fd,sizeof(FILE),0); /* alloc memory for fcb */ setusr(fd->_user=fcbinit(name,fd)); /* setup fcb, get user area */ #ifdef MULTI_USER /* the following applies to multiuser ONLY */ if (mode & F_UNLOCK) fd->f_name[4]|=0x80; if (mode & F_RO) fd->f_name[5]|=0x80; #endif /* multi user */ fd->_bp=fd->_buffer; /* set up current char position */ if ( (err_code=bdos(OPNFIL,&fd->_fcb)) >3 || err_code<0) /* hanging to next statement set.. */ #ifdef MULTI_USER if (err_code==5) { /* file locked.. wait */ unsigned u; while (bdoshl(OPNFIL,&fd->_fcb)==5) { printf("\nQueued. "); for (u=0; u<50000; u++); } } else #endif /* multi user */ if (mode & F_RW) { if (bdos(MAKFIL,&fd->_fcb)==0xff) { close(fd); /* free up space */ fd=NULL; } } else { close(fd); fd=NULL; } } else printf("\nUnable to alloc space for file: %s\nStack near %xh ",name,&err_code); return (fd); /* return pointer to the fcb */ } /* close a file... and free up allocated space... */ close(fd) register FILE *fd; { register int code; if ((fd->_bp==NULL) || (fd==NULL)) return 0; /* 0=ok.. but no file there. */ setusr(fd->_user); /* restore file's user area */ code=bdos(CLSFIL,&fd->_fcb); /* CP/M close file */ free(fd); fd->_bp=NULL; /* in case close again */ return code==0xff ? ERROR : NULL; } /* random xP/M read.. and optional increment of record position... * if rinc=0 then no increment.. else increment by rinc sectors * The record is placed in the files buffer space (bufloc(fd)). */ read(fd,rinc) /* read one cp/m sector (128 bytes) and return # bytes read */ register FILE *fd; unsigned rinc; /* record increment.. used so can read without advance */ { register int code; bdos(SETDMA,(fd->_bp=fd->_buffer)); /* set DMA to file buffer area */ setusr(fd->_user); /* restore file user number */ if ((code=bdos(READRN,&fd->_fcb))>0) return (code); /* read random record.. */ fd->_fcb.f_record+=rinc; /* incrememt record count... */ setbuf(fd,0); /* set this to zero */ return 128; /* 128 bytes read */ } /************************************************* * Unix style read into buffer, for size bytes.. * *************************************************/ uread(fd,buf,size) FILE *fd; char *buf; unsigned size; { register unsigned rec_count,byte_rem_count; /* # of whole records, and of remaining bytes after the whole records */ setusr(fd->_user); /* restore file user number */ rec_count=(((size+128)-getbuf(fd))/128); if (rec_count!=0) rec_count--; byte_rem_count=(getbuf(fd)+size)%128; /* printf("\nrec_count=%d getbuf(fd)=%xh byte_rem_count=%d ", rec_count,getbuf(fd),byte_rem_count); */ if (getbuf(fd)!=0 && getbuf(fd)!=128) { if (size<=128-getbuf(fd)) { movmem(bufloc(fd)+getbuf(fd),buf,size); setbuf(fd,getbuf(fd)+size); return size; } else { movmem(bufloc(fd)+getbuf(fd),buf,128-getbuf(fd)); buf+=(128-getbuf(fd)); } } while (rec_count--) { bdos(SETDMA,buf); if (bdos(READRN,&fd->_fcb)>0) return ERROR; fd->_fcb.f_record++; /* incrememt record count... */ buf+=128; /* bump buffer one records worth */ } if (byte_rem_count) { if (read(fd,1)!=128) return ERROR; movmem(bufloc(fd),buf,byte_rem_count); /* mov in last bytes */ setbuf(fd,byte_rem_count); } else setbuf(fd,0); /* at zero */ return size; } /* write sector.. rinc same format as read... Writes from files buffer space */ write(fd,rinc) /* write random.. */ register FILE *fd; unsigned rinc; { register int code; /* eror return code. */ setusr(fd->_user); /* restore file user number */ bdos(SETDMA,(fd->_bp=fd->_buffer)); if ((code=bdos(WRITRN,&fd->_fcb))>0) return (code); fd->_fcb.f_record+=rinc; return 128; } rename(old, new) char *old, *new; { auto char buff[60]; register int user; user = fcbinit(old,buff); fcbinit(new,buff+16); setusr(user); if (bdos(15,buff+16) != 0xff) { bdos(16,buff+16); bdos(19,buff+16); /* delete file if was there.. */ } bdos(23,buff); /* rename */ } /* primative getc/putc function */ getc(fd) register FILE *fd; { register char ch; if (eobuf(fd)) if (read(fd,1)!=128) return EOF; /* end of file */ ch=gchar(fd); return ch!=0x1a ? ch : EOF; /* also cp/m EOF ^Z */ } putc(ch,fd) register char ch; register FILE *fd; { if (ch=='\n') putc('\r',fd); /* recursive cr/lf */ if (eobuf(fd)) if (write(fd,1)!=128) return ERROR; return pchar(fd,ch); } fputs(s,fd) register char *s; register FILE *fd; { while (*s) putc(*s++,fd); } fgets(s,fd) register char *s; register FILE *fd; { register int i; char *cp; cp=s; while ((i=getc(fd))!='\r' && i!=EOF) *cp++=i; *cp='\0'; return(s); } /* further i/o defines are set up in cpm.h ... they include routines for * the following.. get buffer location * get/put char within buffer * get/set char POSition within buffer * absolute record seek (from begin of file) * relative record seek (from current pos) * detect end of buffer condition (used after get/put) * all seek positions are by 128 byte cp/m records.. */ #ifdef CON_IO /* some new char i/o routines.. */ getchar() { register int ch; while((ch=bdos(6,0xff))==0); putchar(ch); return ch; } putchar(ch) register int ch; { if (ch=='\n') bdos(6,'\r'); bdos(6,ch); return ch; } char *gets(s) char *s; { register char *cp; register int i; cp=s; while ((i=getchar()) != '\r') *cp++=i; *cp='\0'; return s; } puts(s) char *s; { while (*s) putchar(*s++); return putchar('\n'); } #endif /* CON_IO */ tc(fd))!='\r' && i!=EOF) *cp++=i; *cp='\0'; return(s); } /* further i/o defines are set up in cpm.h ... they include routines for * the following.. get buffer location * get/put char within buffer * get/set char POSition within buffer * absolute record seek (from begin of file) * relative record seek (from current pos) * detect end of buffer condition (used after get/put) * all seek positions are by 128 byte cp/m records.. */ #ifdef CON_IO /* some new char i/o routines.. */ getchar() { register int ch; while((ch=bdos(6,0xff))==0); putchar(ch); return ch; } putchar(ch) register in !"#$%&'