/****************************************************************************** * METAL Message section... for METAL version 1.20a * * File name: MES.C version 1.20a * * Copyright (c) 1984 Tim Gary * Delphi Data Systems * All rights reserved. * * * This module contains common message base routines (read, msgheader, etc) * ***************************************************************************** * * 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 ? "" : " "), message.lines,message.topic); 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 */ } *(char *)O.RESETDRIVE; /* defined in HMH.H */ get_header(mode&0x7f,buffer); if ((mode!=3 && mode!=4) || user.parm.expert==POFF) /* write line */ if (send(buffer)==ERROR) return ERROR; *(char *)O.RESETDRIVE; } 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) { if (n=atoi(s)) /* if a number is there, assume correct format */ if (n>=12) { strncpy(ch,s+3,2); *(ch+2)='\0'; /* get mins in ch */ sprintf(s,"%2d:%2s pm",n==12 ? 12 : n-12,ch); } else strcpy(s+5," am"); } } /*************** * 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", "\nThe above may be mixed (ie. ft: = from and to)", "\nExamples: 244+ s:for sale AND *:my name\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 * * examples: * * s:for sale ft:tim gary d:09-02-84 * * 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 * ************************************************************************/ char msearch(sstr) char *sstr; { char *ps; register char ret_flag; static spattern[MAXLINE+1],from_flag,to_flag,subject_flag,date_flag; ret_flag=0; if (sstr) /* if not null ptr, setup search string */ { *spattern='\0'; /* make empty string at first */ from_flag=to_flag=subject_flag=date_flag=NO; /* all off */ if (ps=index(sstr,':')) /* '=' IS ON PURPOSE!!!!!!!! */ { /* search pattern given.. */ while (--ps>=sstr) /* backwards parse from ':' */ { switch (*ps--) { case 'S': subject_flag=YES; break; case 'D': date_flag=YES; break; case 'F': from_flag=YES; break; case 'T': to_flag=YES; break; case '*': subject_flag=date_flag=from_flag=to_flag=YES; /* fall through to default.. */ default: ps=sstr; /* stop loop here */ } /* switch */ } /* while loop */ strcpy(spattern,index(sstr,':')+1); /* get rest of line */ ret_flag=TRUE; /* flag search */ } /* if ':' test */ } /* main 'string passed' if */ else { /* no string passed, compare with message fields */ if (!subject_flag && !date_flag && !from_flag && !to_flag) ret_flag=128; /* bit 7 set if no compare */ else { char tstr[MAXLINE+1]; /* used for sender string */ if (subject_flag) ret_flag|=(usindex(spattern,message.topic) ? 1 : 0); if (date_flag) ret_flag|=(usindex(spattern,message.date) ? 2 : 0); if (from_flag) { sprintf(tstr,"%s %s",message.fsend,message.lsend); ret_flag|=(usindex(spattern,tstr) ? 4 : 0); } if (to_flag) ret_flag|=(usindex(spattern,message.receiver) ? 8 : 0); } /* check pattern?? if */ } return ret_flag; /* return value */ } /* msearch */ /* End of MES.C */