/* getnode.cpp */ /* Synchronet node information retrieval functions */ /* $Id$ */ /**************************************************************************** * @format.tab-size 4 (Plain Text/Source Code File Header) * * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) * * * * Copyright Rob Swindell - http://www.synchro.net/copyright.html * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * See the GNU General Public License for more details: gpl.txt or * * http://www.fsf.org/copyleft/gpl.html * * * * Anonymous FTP access to the most recent released source is available at * * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net * * * * Anonymous CVS access to the development source and modification history * * is available at cvs.synchro.net:/cvsroot/sbbs, example: * * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login * * (just hit return, no password is necessary) * * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src * * * * For Synchronet coding style and modification guidelines, see * * http://www.synchro.net/source.html * * * * You are encouraged to submit any modifications (preferably in Unix diff * * format) via e-mail to mods@synchro.net * * * * Note: If this box doesn't appear square, then you need to fix your tabs. * ****************************************************************************/ #include "sbbs.h" #include "cmdshell.h" /****************************************************************************/ /* Reads the data for node number 'number' into the structure 'node' */ /* from NODE.DAB */ /* if lockit is non-zero, locks this node's record. putnodedat() unlocks it */ /****************************************************************************/ int sbbs_t::getnodedat(uint number, node_t *node, bool lockit) { char str[MAX_PATH+1]; int rd=sizeof(node_t); int count; if(node==NULL || number<1) return(-1); if(number>cfg.sys_nodes) { errormsg(WHERE,ERR_CHK,"node number",number); return(-1); } if(node!=&thisnode) memset(node,0,sizeof(node_t)); sprintf(str,"%snode.dab",cfg.ctrl_dir); if(nodefile==-1) { if((nodefile=nopen(str,O_RDWR|O_DENYNONE))==-1) { errormsg(WHERE,ERR_OPEN,str,O_RDWR|O_DENYNONE); return(errno); } } else utime(str,NULL); /* NFS fix... utime() forces a cache refresh */ number--; /* make zero based */ for(count=0;count<LOOP_NODEDAB;count++) { if(count) mswait(100); if(lockit && lock(nodefile,(long)number*sizeof(node_t),sizeof(node_t))!=0) { unlock(nodefile,(long)number*sizeof(node_t),sizeof(node_t)); continue; } lseek(nodefile,(long)number*sizeof(node_t),SEEK_SET); rd=read(nodefile,node,sizeof(node_t)); if(!lockit || rd!=sizeof(node_t)) unlock(nodefile,(long)number*sizeof(node_t),sizeof(node_t)); if(rd==sizeof(node_t)) break; } if(!lockit && cfg.node_misc&NM_CLOSENODEDAB) { close(nodefile); nodefile=-1; } if(count==LOOP_NODEDAB) { errormsg(WHERE,rd==sizeof(node_t) ? ERR_LOCK : ERR_READ,"node.dab",number+1); if(nodefile!=-1) close(nodefile); nodefile=-1; return(-2); } if(count>(LOOP_NODEDAB/2)) { sprintf(str,"NODE.DAB (node %d) COLLISION - Count: %d" ,number+1, count); logline(LOG_WARNING,"!!",str); } return(0); } /****************************************************************************/ /* Synchronizes all the nodes knowledge of the other nodes' actions, mode, */ /* status and other flags. */ /* Assumes that getnodedat(node_num,&thisnode,0) was called right before it */ /* is called. */ /****************************************************************************/ void sbbs_t::nodesync() { char str[256],today[32]; int atr=curatr; if(nodesync_inside || !online) return; nodesync_inside=1; if(thisnode.action!=action) { if(getnodedat(cfg.node_num,&thisnode,true)==0) { thisnode.action=action; putnodedat(cfg.node_num,&thisnode); } } criterrs=thisnode.errors; if(sys_status&SS_USERON) { if(thisnode.status==NODE_WFC) { lprintf(LOG_ERR, "Node %d NODE STATUS FIXUP", cfg.node_num); if(getnodedat(cfg.node_num,&thisnode,true)==0) { thisnode.status=NODE_INUSE; thisnode.useron=useron.number; putnodedat(cfg.node_num,&thisnode); } } if(!(sys_status&SS_NEWDAY)) { now=time(NULL); unixtodstr(&cfg,(time32_t)logontime,str); unixtodstr(&cfg,(time32_t)now,today); if(strcmp(str,today)) { /* New day, clear "today" user vars */ sys_status|=SS_NEWDAY; // So we don't keep doing this over&over resetdailyuserdat(&cfg, &useron,/* write: */true); } } if(thisnode.misc&NODE_UDAT && !(useron.rest&FLAG('G'))) { /* not guest */ getuserdat(&cfg, &useron); if(getnodedat(cfg.node_num,&thisnode,true)==0) { thisnode.misc&=~NODE_UDAT; putnodedat(cfg.node_num,&thisnode); } } if(!(sys_status&SS_MOFF)) { if(thisnode.misc&NODE_MSGW) getsmsg(useron.number); /* getsmsg clears MSGW flag */ if(thisnode.misc&NODE_NMSG) getnmsg(); /* getnmsg clears NMSG flag */ } } if(cfg.sync_mod[0]) exec_bin(cfg.sync_mod,&main_csi); if(thisnode.misc&NODE_INTR) { bputs(text[NodeLocked]); logline(LOG_NOTICE,nulstr,"Interrupted"); hangup(); nodesync_inside=0; return; } if(thisnode.misc&NODE_LCHAT) { // pulled into local chat with sysop SAVELINE; privchat(true); RESTORELINE; } if(sys_status&SS_USERON && memcmp(&nodesync_user,&useron,sizeof(user_t))) { getusrdirs(); getusrsubs(); memcpy(&nodesync_user,&useron,sizeof(nodesync_user)); } if(sys_status&SS_USERON && online && (timeleft/60)<(5-timeleft_warn) && !SYSOP) { timeleft_warn=5-(timeleft/60); if(!(sys_status&SS_MOFF)) { attr(LIGHTGRAY); bprintf(text[OnlyXminutesLeft] ,((ushort)timeleft/60)+1,(timeleft/60) ? "s" : nulstr); } } attr(atr); /* replace original attributes */ nodesync_inside=0; } /****************************************************************************/ /* Prints short messages waiting for this node, if any... */ /****************************************************************************/ int sbbs_t::getnmsg() { char str[MAX_PATH+1], *buf; int file; long length; if(getnodedat(cfg.node_num,&thisnode,true)==0) { thisnode.misc&=~NODE_NMSG; /* clear the NMSG flag */ putnodedat(cfg.node_num,&thisnode); } sprintf(str,"%smsgs/n%3.3u.msg",cfg.data_dir,cfg.node_num); if(flength(str)<1L) return(0); if((file=nopen(str,O_RDWR))==-1) { /** errormsg(WHERE,ERR_OPEN,str,O_RDWR); **/ return(errno); } length=(long)filelength(file); if(!length) { close(file); return(0); } if((buf=(char *)malloc(length+1))==NULL) { close(file); errormsg(WHERE,ERR_ALLOC,str,length+1); return(-1); } if(lread(file,buf,length)!=length) { close(file); free(buf); errormsg(WHERE,ERR_READ,str,length); return(errno); } chsize(file,0L); close(file); buf[length]=0; if(thisnode.action==NODE_MAIN || thisnode.action==NODE_XFER || sys_status&SS_IN_CTRLP) { CRLF; } putmsg(buf,P_NOATCODES); free(buf); return(0); } /****************************************************************************/ /* 'ext' must be at least 128 bytes! */ /****************************************************************************/ int sbbs_t::getnodeext(uint number, char *ext) { char str[MAX_PATH+1]; int rd,count; if(!number || number>cfg.sys_nodes) { errormsg(WHERE,ERR_CHK,"node number",number); return(-1); } sprintf(str,"%snode.exb",cfg.ctrl_dir); if((node_ext=nopen(str,O_RDONLY|O_DENYNONE))==-1) { memset(ext,0,128); errormsg(WHERE,ERR_OPEN,str,O_RDONLY|O_DENYNONE); return(errno); } number--; /* make zero based */ for(count=0;count<LOOP_NODEDAB;count++) { if(count) mswait(100); if(lock(node_ext,(long)number*128L,128)!=0) continue; lseek(node_ext,(long)number*128L,SEEK_SET); rd=read(node_ext,ext,128); unlock(node_ext,(long)number*128L,128); if(rd==128) break; } close(node_ext); node_ext=-1; if(count==LOOP_NODEDAB) { errormsg(WHERE,ERR_READ,"node.exb",number+1); return(-2); } if(count>(LOOP_NODEDAB/2)) { sprintf(str,"NODE.EXB (node %d) COLLISION - Count: %d" ,number+1, count); logline("!!",str); } return(0); } /****************************************************************************/ /* Prints short messages waiting for 'usernumber', if any... */ /* then deletes them. */ /****************************************************************************/ int sbbs_t::getsmsg(int usernumber) { char str[MAX_PATH+1], *buf; int file; long length; node_t node; int i; for(i=1;i<=cfg.sys_nodes;i++) { /* clear msg waiting flag */ if(getnodedat(i,&node,true)==0) { if(node.useron==usernumber && (node.status==NODE_INUSE || node.status==NODE_QUIET) && node.misc&NODE_MSGW) node.misc&=~NODE_MSGW; putnodedat(i,&node); } } sprintf(str,"%smsgs/%4.4u.msg",cfg.data_dir,usernumber); if(flength(str)<1L) return(0); if((file=nopen(str,O_RDWR))==-1) { errormsg(WHERE,ERR_OPEN,str,O_RDWR); return(errno); } length=(long)filelength(file); if((buf=(char *)malloc(length+1))==NULL) { close(file); errormsg(WHERE,ERR_ALLOC,str,length+1); return(-1); } if(lread(file,buf,length)!=length) { close(file); free(buf); errormsg(WHERE,ERR_READ,str,length); return(errno); } chsize(file,0L); close(file); buf[length]=0; getnodedat(cfg.node_num,&thisnode,0); if(thisnode.action==NODE_MAIN || thisnode.action==NODE_XFER || sys_status&SS_IN_CTRLP) { CRLF; } putmsg(buf,P_NOATCODES); free(buf); return(0); } /****************************************************************************/ /* This function lists users that are online. */ /* If listself is true, it will list the current node. */ /* Returns number of active nodes (not including current node). */ /****************************************************************************/ int sbbs_t::whos_online(bool listself) { int i,j; node_t node; CRLF; bputs(text[NodeLstHdr]); for(j=0,i=1;i<=cfg.sys_nodes && i<=cfg.sys_lastnode;i++) { getnodedat(i,&node,0); if(i==cfg.node_num) { if(listself) printnodedat(i,&node); continue; } if(node.status==NODE_INUSE || (SYSOP && node.status==NODE_QUIET)) { printnodedat(i,&node); if(!lastnodemsg) lastnodemsg=i; j++; } } if(!j) bputs(text[NoOtherActiveNodes]); return(j); } void sbbs_t::nodelist(void) { node_t node; CRLF; bputs(text[NodeLstHdr]); for(int i=1;i<=cfg.sys_nodes && i<=cfg.sys_lastnode;i++) { getnodedat(i,&node,0); printnodedat(i,&node); } } static char* node_connection_desc(sbbs_t* sbbs, ushort conn, char* str) { switch(conn) { case NODE_CONNECTION_LOCAL: return (char*)" Locally"; /* obsolete */ case NODE_CONNECTION_TELNET: return sbbs->text[NodeConnectionTelnet]; case NODE_CONNECTION_RLOGIN: return sbbs->text[NodeConnectionRLogin]; case NODE_CONNECTION_SSH: return sbbs->text[NodeConnectionSSH]; default: sprintf(str,sbbs->text[NodeConnectionModem],conn); break; } return str; } /****************************************************************************/ /* Displays the information for node number 'number' contained in 'node' */ /****************************************************************************/ void sbbs_t::printnodedat(uint number, node_t* node) { uint i; char hour,mer[3]; char tmp[512]; attr(cfg.color[clr_nodenum]); bprintf("%3d ",number); attr(cfg.color[clr_nodestatus]); switch(node->status) { case NODE_WFC: bputs(text[NodeStatusWaitingForCall]); break; case NODE_OFFLINE: bputs(text[NodeStatusOffline]); break; case NODE_NETTING: bputs("Networking"); /* obsolete */ break; case NODE_LOGON: bputs(text[NodeStatusLogon]); bputs(node_connection_desc(this, node->connection, tmp)); break; case NODE_LOGOUT: bprintf(text[NodeStatusLogout] ,(node->misc&NODE_ANON) && !SYSOP ? text[UNKNOWN_USER] : username(&cfg,node->useron,tmp)); break; case NODE_EVENT_WAITING: bputs(text[NodeStatusEventWaiting]); break; case NODE_EVENT_LIMBO: bprintf(text[NodeStatusEventLimbo],node->aux); break; case NODE_EVENT_RUNNING: bputs(text[NodeStatusEventRunning]); break; case NODE_NEWUSER: bputs(text[NodeStatusNewUser]); bputs(node_connection_desc(this, node->connection, tmp)); break; case NODE_QUIET: if(!SYSOP) { bputs(text[NodeStatusWaitingForCall]); break; } case NODE_INUSE: if(node->misc&NODE_EXT) { getnodeext(number,tmp); bputs(tmp); break; } attr(cfg.color[clr_nodeuser]); if(node->misc&NODE_ANON && !SYSOP) bputs(text[UNKNOWN_USER]); else bputs(username(&cfg,node->useron,tmp)); attr(cfg.color[clr_nodestatus]); bputs(" "); switch(node->action) { case NODE_MAIN: bputs("at main menu"); break; case NODE_RMSG: bputs("reading messages"); break; case NODE_RMAL: bputs("reading mail"); break; case NODE_RSML: bputs("reading sent mail"); break; case NODE_RTXT: bputs("reading text files"); break; case NODE_PMSG: bputs("posting message"); break; case NODE_SMAL: bputs("sending mail"); break; case NODE_AMSG: bputs("posting auto-message"); break; case NODE_XTRN: if(node->aux<1 || node->aux>cfg.total_xtrns) bputs("at external program menu"); else { bputs("running "); i=node->aux-1; if(SYSOP || chk_ar(cfg.xtrn[i]->ar,&useron,&client)) bputs(cfg.xtrn[node->aux-1]->name); else bputs("external program"); } break; case NODE_DFLT: bputs("changing defaults"); break; case NODE_XFER: bputs("at transfer menu"); break; case NODE_RFSD: bprintf("retrieving from device #%d",node->aux); break; case NODE_DLNG: bprintf("downloading"); break; case NODE_ULNG: bputs("uploading"); break; case NODE_BXFR: bputs("transferring bidirectional"); break; case NODE_LFIL: bputs("listing files"); break; case NODE_LOGN: bputs("logging on"); break; case NODE_LCHT: bprintf("in local chat with %s",cfg.sys_op); break; case NODE_MCHT: if(node->aux) { bprintf("in multinode chat channel %d",node->aux&0xff); if(node->aux&0x1f00) { /* password */ outchar('*'); if(SYSOP) bprintf(" %s",unpackchatpass(tmp,node)); } } else bputs("in multinode global chat channel"); break; case NODE_PAGE: bprintf("paging node %u for private chat",node->aux); break; case NODE_PCHT: if(node->aux) bprintf("in private chat with node %u",node->aux); else bprintf("in local chat with %s",cfg.sys_op); break; case NODE_GCHT: i=node->aux; if(i>=cfg.total_gurus) i=0; bprintf("chatting with %s",cfg.guru[i]->name); break; case NODE_CHAT: bputs("in chat section"); break; case NODE_TQWK: bputs("transferring QWK packet"); break; case NODE_SYSP: bputs("performing sysop activities"); break; default: bputs(ultoa(node->action,tmp,10)); break; } bputs(node_connection_desc(this, node->connection, tmp)); if(node->action==NODE_DLNG) { if(cfg.sys_misc&SM_MILITARY) { hour=node->aux/60; mer[0]=0; } else if((node->aux/60)>=12) { if(node->aux/60==12) hour=12; else hour=(node->aux/60)-12; strcpy(mer,"pm"); } else { if((node->aux/60)==0) /* 12 midnite */ hour=12; else hour=node->aux/60; strcpy(mer,"am"); } bprintf(" ETA %02d:%02d %s" ,hour,node->aux%60,mer); } break; } i=NODE_LOCK; if(node->status==NODE_INUSE || SYSOP) i|=NODE_POFF|NODE_AOFF|NODE_MSGW|NODE_NMSG; if(node->misc&i) { bputs(" ("); if(node->misc&(i&NODE_AOFF)) outchar('A'); if(node->misc&NODE_LOCK) outchar('L'); if(node->misc&(i&(NODE_MSGW|NODE_NMSG))) outchar('M'); if(node->misc&(i&NODE_POFF)) outchar('P'); outchar(')'); } if(SYSOP && ((node->misc &(NODE_ANON|NODE_UDAT|NODE_INTR|NODE_RRUN|NODE_EVENT|NODE_DOWN|NODE_LCHAT)) || node->status==NODE_QUIET)) { bputs(" ["); if(node->misc&NODE_ANON) outchar('A'); if(node->misc&NODE_INTR) outchar('I'); if(node->misc&NODE_RRUN) outchar('R'); if(node->misc&NODE_UDAT) outchar('U'); if(node->status==NODE_QUIET) outchar('Q'); if(node->misc&NODE_EVENT) outchar('E'); if(node->misc&NODE_DOWN) outchar('D'); if(node->misc&NODE_LCHAT) outchar('C'); outchar(']'); } if(node->errors && SYSOP) { attr(cfg.color[clr_err]); bprintf(" %d error%c",node->errors, node->errors>1 ? 's' : '\0' ); } attr(LIGHTGRAY); CRLF; }