#define Use_MsgBase #include #include #include #include #include "proboard.hpp" #include "jam.hpp" //////////////////////////////////////////////////////////////////////////////////// static dword PbDate2JamDate( const Date& pbd , const Time& pbt) { int years = pbd.year() - 70; dword unixtime = dword(years) * 365L + (dword(years + 1) / 4L); return ((unixtime + pbd.dayNum() - 1) * 86400L + long(pbt)); } static void JamDate2PbDate( Date &pbd, Time& pbt , dword jamdate ) { struct tm *tms = localtime( (long *) & jamdate ); long seconds = long( jamdate ) % 86400L; jamdate -= seconds; pbt = seconds; pbd[ 0 ] = tms->tm_mday; pbd[ 1 ] = tms->tm_mon+1; pbd[ 2 ] = tms->tm_year; // Y2K - LOOKS OK, BUT CHECK IT OUT } static void JamMsg2Message(JamHeader *jam,JamExtHeader *xjam,Message *msg) { strcpy(msg->from , xjam->from); strcpy(msg->to , xjam->to); strcpy(msg->subj , xjam->subject); msg->origZone = xjam->fromZone; msg->origNet = xjam->fromNet; msg->origNode = xjam->fromNode; msg->origPoint = xjam->fromPoint; msg->destZone = xjam->toZone; msg->destNet = xjam->toNet; msg->destNode = xjam->toNode; msg->destPoint = xjam->toPoint; JamDate2PbDate( msg->postDate, msg->postTime , jam->dateWritten ); JamDate2PbDate( msg->recvDate, msg->recvTime , jam->dateReceived); msg->num = jam->messageNumber; msg->id = msg->num; msg->prev = jam->replyTo; msg->next = jam->reply1St; msg->attr = 0; if(jam->attribute & JAM_MSG_LOCAL ) msg->attr |= MSGATTR_LOCAL; if(jam->attribute & JAM_MSG_INTRANSIT ) msg->attr |= MSGATTR_TRANSIT; if(jam->attribute & JAM_MSG_PRIVATE ) msg->attr |= MSGATTR_PRIVATE; if(jam->attribute & JAM_MSG_READ ) msg->attr |= MSGATTR_RECEIVED; if(jam->attribute & JAM_MSG_SENT ) msg->attr |= MSGATTR_SENT; if(jam->attribute & JAM_MSG_KILLSENT ) msg->attr |= MSGATTR_KILL; if(jam->attribute & JAM_MSG_HOLD ) msg->attr |= MSGATTR_HOLD; if(jam->attribute & JAM_MSG_CRASH ) msg->attr |= MSGATTR_CRASH; if(jam->attribute & JAM_MSG_IMMEDIATE ) msg->attr |= MSGATTR_IMMEDIATE; if(jam->attribute & JAM_MSG_DIRECT ) msg->attr |= MSGATTR_DIRECT; if(jam->attribute & JAM_MSG_FILEREQUEST) msg->attr |= MSGATTR_FILEREQ; if(jam->attribute & JAM_MSG_FILEATTACH ) msg->attr |= MSGATTR_FILE; if(jam->attribute & JAM_MSG_TRUNCFILE ) msg->attr |= MSGATTR_TRUNCFILE; if(jam->attribute & JAM_MSG_KILLFILE ) msg->attr |= MSGATTR_DELFILE; if(jam->attribute & JAM_MSG_RECEIPTREQ ) msg->attr |= MSGATTR_RECEIPTREQ; if(jam->attribute & JAM_MSG_ORPHAN ) msg->attr |= MSGATTR_ORPHAN; if(jam->attribute & JAM_MSG_NODISP ) msg->attr |= MSGATTR_NODISP; if(jam->attribute & JAM_MSG_LOCKED ) msg->attr |= MSGATTR_LOCKED; if(jam->attribute & JAM_MSG_DELETED ) msg->attr |= MSGATTR_DELETED; if(jam->attribute & JAM_MSG_TYPEECHO ) msg->attr |= MSGATTR_ECHOMAIL; if(jam->attribute & JAM_MSG_TYPENET ) msg->attr |= MSGATTR_NETMAIL; } static void Message2JamMsg(JamHeader *jam,JamExtHeader *xjam,Message *msg) { if(xjam != NULL) { strcpy(xjam->from , msg->from); strcpy(xjam->to , msg->to ); strcpy(xjam->subject , msg->subj); xjam->fromZone = msg->origZone ; xjam->fromNet = msg->origNet ; xjam->fromNode = msg->origNode ; xjam->fromPoint = msg->origPoint; xjam->toZone = msg->destZone ; xjam->toNet = msg->destNet ; xjam->toNode = msg->destNode ; xjam->toPoint = msg->destPoint; } if(msg->postDate.ok()) jam->dateWritten = PbDate2JamDate( msg->postDate, msg->postTime ); jam->dateReceived = 0; if(msg->attr & MSGATTR_RECEIVED && msg->recvDate.ok()) jam->dateReceived = PbDate2JamDate( msg->recvDate, msg->recvTime ); jam->messageNumber = msg->num; jam->replyTo = msg->prev; jam->reply1St = msg->next; jam->attribute = 0; if(msg->attr & MSGATTR_LOCAL ) jam->attribute |= JAM_MSG_LOCAL ; if(msg->attr & MSGATTR_TRANSIT ) jam->attribute |= JAM_MSG_INTRANSIT ; if(msg->attr & MSGATTR_PRIVATE ) jam->attribute |= JAM_MSG_PRIVATE ; if(msg->attr & MSGATTR_RECEIVED ) jam->attribute |= JAM_MSG_READ ; if(msg->attr & MSGATTR_SENT ) jam->attribute |= JAM_MSG_SENT ; if(msg->attr & MSGATTR_KILL ) jam->attribute |= JAM_MSG_KILLSENT ; if(msg->attr & MSGATTR_HOLD ) jam->attribute |= JAM_MSG_HOLD ; if(msg->attr & MSGATTR_CRASH ) jam->attribute |= JAM_MSG_CRASH ; if(msg->attr & MSGATTR_IMMEDIATE ) jam->attribute |= JAM_MSG_IMMEDIATE ; if(msg->attr & MSGATTR_DIRECT ) jam->attribute |= JAM_MSG_DIRECT ; if(msg->attr & MSGATTR_FILEREQ ) jam->attribute |= JAM_MSG_FILEREQUEST; if(msg->attr & MSGATTR_FILE ) jam->attribute |= JAM_MSG_FILEATTACH ; if(msg->attr & MSGATTR_TRUNCFILE ) jam->attribute |= JAM_MSG_TRUNCFILE ; if(msg->attr & MSGATTR_DELFILE ) jam->attribute |= JAM_MSG_KILLFILE ; if(msg->attr & MSGATTR_RECEIPTREQ) jam->attribute |= JAM_MSG_RECEIPTREQ ; if(msg->attr & MSGATTR_ORPHAN ) jam->attribute |= JAM_MSG_ORPHAN ; if(msg->attr & MSGATTR_NODISP ) jam->attribute |= JAM_MSG_NODISP ; if(msg->attr & MSGATTR_LOCKED ) jam->attribute |= JAM_MSG_LOCKED ; if(msg->attr & MSGATTR_DELETED ) jam->attribute |= JAM_MSG_DELETED ; if(msg->attr & MSGATTR_ECHOMAIL ) jam->attribute |= JAM_MSG_TYPEECHO ; if(msg->attr & MSGATTR_NETMAIL ) jam->attribute |= JAM_MSG_TYPENET ; if(!(msg->attr & (MSGATTR_ECHOMAIL|MSGATTR_NETMAIL))) jam->attribute |= JAM_MSG_TYPELOCAL; } static bool SubFields2ExtHeader( byte *subfields , word size , JamExtHeader& ext_hdr ) { JamSubField *sub; word pos; for(pos = 0 ; pos < size ; ) { sub = (JamSubField *)(&subfields[pos]); pos += sizeof(JamSubField); byte *buf = new byte[word(sub->datLen)+1]; memcpy(buf , &subfields[pos] , word(sub->datLen)); buf[word(sub->datLen)] = '\0'; pos += sub->datLen; // At this point we have all data! switch(sub->loId) { case JAMID_SENDERNAME: { strncpy( ext_hdr.from , buf , 35 ); ext_hdr.from[35] = '\0'; } break; case JAMID_RECEIVERNAME: { strncpy( ext_hdr.to , buf , 35 ); ext_hdr.to[35] = '\0'; } break; case JAMID_SUBJECT: { strncpy( ext_hdr.subject , buf , 71 ); ext_hdr.subject[71] = '\0'; } break; case JAMID_PID: { strncpy( ext_hdr.pid , buf , 79 ); ext_hdr.pid[79] = '\0'; } break; case JAMID_OADDRESS: { char *s = strtok( buf , ":"); ext_hdr.fromZone = 0; ext_hdr.fromNet = 0; ext_hdr.fromNode = 0; ext_hdr.fromPoint = 0; if(s) { ext_hdr.fromZone = atoi(s); s = strtok( NULL , "/"); if(s) { ext_hdr.fromNet = atoi(s); s = strtok( NULL , "."); if(s) { ext_hdr.fromNode = atoi(s); s = strtok( NULL , "@"); if(s) { ext_hdr.fromPoint = atoi(s); } } } } } break; case JAMID_DADDRESS: { char *s = strtok( buf , ":"); ext_hdr.toZone = 0; ext_hdr.toNet = 0; ext_hdr.toNode = 0; ext_hdr.toPoint = 0; if(s) { ext_hdr.toZone = atoi(s); s = strtok( NULL , "/"); if(s) { ext_hdr.toNet = atoi(s); s = strtok( NULL , "."); if(s) { ext_hdr.toNode = atoi(s); s = strtok( NULL , "."); if(s) { ext_hdr.toPoint = atoi(s); } } } } } break; } delete [] buf; } return TRUE; } word ExtHeader2SubFields(byte *subfields, JamExtHeader& xjam) { char addr_buf[30]; JamSubField *sub; word index = 0; sub = (JamSubField *) &subfields[index]; sub->loId = JAMID_SENDERNAME; sub->hiId = 0; sub->datLen = strlen(xjam.from); index += sizeof(JamSubField); strcpy(&subfields[index] , xjam.from); index += sub->datLen; sub = (JamSubField *) &subfields[index]; sub->loId = JAMID_RECEIVERNAME; sub->hiId = 0; sub->datLen = strlen(xjam.to); index += sizeof(JamSubField); strcpy(&subfields[index] , xjam.to); index += sub->datLen; sub = (JamSubField *) &subfields[index]; sub->loId = JAMID_SUBJECT; sub->hiId = 0; sub->datLen = strlen(xjam.subject); index += sizeof(JamSubField); strcpy(&subfields[index] , xjam.subject); index += sub->datLen; if(xjam.fromZone) { sprintf(addr_buf,"%d:%d/%d.%d",xjam.fromZone,xjam.fromNet,xjam.fromNode,xjam.fromPoint); sub = (JamSubField *) &subfields[index]; sub->loId = JAMID_OADDRESS; sub->hiId = 0; sub->datLen = strlen(addr_buf); index += sizeof(JamSubField); strcpy(&subfields[index] , addr_buf); index += sub->datLen; } if(xjam.toZone) { sprintf(addr_buf,"%d:%d/%d.%d",xjam.toZone,xjam.toNet,xjam.toNode,xjam.toPoint); sub = (JamSubField *) &subfields[index]; sub->loId = JAMID_DADDRESS; sub->hiId = 0; sub->datLen = strlen(addr_buf); index += sizeof(JamSubField); strcpy(&subfields[index] , addr_buf); index += sub->datLen; } if(xjam.pid[0]) { sub = (JamSubField *) &subfields[index]; sub->loId = JAMID_PID; sub->hiId = 0; sub->datLen = strlen(xjam.pid); index += sizeof(JamSubField); strcpy(&subfields[index] , xjam.pid); index += sub->datLen; } return index; } JamMsgBase::JamMsgBase() { lastAreaNum = -1; jamHeader = new JamFileHeader; CLEAR_OBJECT(*jamHeader); } JamMsgBase::~JamMsgBase() { close(); delete jamHeader; } bool JamMsgBase::open() { return TRUE; } void JamMsgBase::close() { f_jhr.close(); f_jdt.close(); f_jdx.close(); f_jlr.close(); lastAreaNum = -1; } bool JamMsgBase::jamLock() { return f_jhr.lock(0,1); } bool JamMsgBase::jamUnLock() { return f_jhr.unlock(0,1); } bool JamMsgBase::readHeader() { f_jhr.rewind(); return (f_jhr.read( jamHeader , sizeof(JamFileHeader) ) == sizeof(JamFileHeader)); } bool JamMsgBase::writeHeader() { f_jhr.rewind(); return (f_jhr.write( jamHeader , sizeof(JamFileHeader) ) == sizeof(JamFileHeader)); } bool JamMsgBase::openArea(MsgArea& ma) { if(ma.areaNum == lastAreaNum) return TRUE; lastAreaNum = -1; FileName fn_jhr( ma.path , ".JHR" ); FileName fn_jdt( ma.path , ".JDT" ); FileName fn_jdx( ma.path , ".JDX" ); FileName fn_jlr( ma.path , ".JLR" ); f_jhr.close(); f_jdt.close(); f_jdx.close(); f_jlr.close(); if(!f_jhr.open( fn_jhr , fmode_rw | fmode_shared , 4096)) { if(!f_jhr.open( fn_jhr , fmode_create | fmode_rw | fmode_shared , 4096)) return FALSE; CLEAR_OBJECT(*jamHeader); jamHeader->signature = JAM_SIGNATURE; jamHeader->baseMsgNum = 1; jamHeader->passwordCrc = dword(-1); jamHeader->dateCreated = PbDate2JamDate( Date(TODAY) , Time(NOW) ); if(!writeHeader()) return FALSE; } else { if(!readHeader()) return FALSE; } if( !f_jdt.open( fn_jdt , fmode_rw | fmode_copen | fmode_shared , 512 ) || !f_jdx.open( fn_jdx , fmode_rw | fmode_copen | fmode_shared , 2048 ) || !f_jlr.open( fn_jlr , fmode_rw | fmode_copen | fmode_shared , 512 ) ) { return FALSE; } lastAreaNum = ma.areaNum; return TRUE; } long JamMsgBase::readMsg(Message &msg,long id) { int order = 1; JamIndex idx; if(id < 0) { order = -1; id = -id; } if(!openArea(*msg.msgArea)) return -1; long num_found = findIdx( idx , id , order ); if(num_found < 0) return -1; JamHeader hdr; JamExtHeader ext_hdr; f_jhr.seek(idx.offset); if(f_jhr.read( &hdr , sizeof(JamHeader) ) != sizeof(JamHeader)) return -1; if(hdr.signature != JAM_SIGNATURE) return -1; byte *subfields = new byte[word(hdr.subFieldLen)]; if(f_jhr.read( subfields , hdr.subFieldLen ) != hdr.subFieldLen) return -1; SubFields2ExtHeader( subfields , word(hdr.subFieldLen) , ext_hdr ); JamMsg2Message( &hdr , &ext_hdr , &msg ); delete [] subfields; return num_found; } long JamMsgBase::lowMsg(MsgArea &ma) { if(!openArea(ma)) return -1; readHeader(); return jamHeader->baseMsgNum; } long JamMsgBase::numMsgs(MsgArea &ma) { if(!openArea(ma)) return -1; readHeader(); return jamHeader->activeMsgs; } long JamMsgBase::highMsg(MsgArea &ma) { if(!openArea(ma)) return -1; readHeader(); return (f_jdx.len() / sizeof(JamIndex) + jamHeader->baseMsgNum - 1); } word JamMsgBase::readMsgText(Message& msg,char *ptr,long offset,word size) { JamIndex idx; long num_found = findIdx( idx , msg.num , 0 ); if(num_found != msg.num) return 0; JamHeader hdr; f_jhr.seek(idx.offset); if(f_jhr.read( &hdr , sizeof(JamHeader) ) != sizeof(JamHeader)) return 0; if(hdr.signature != JAM_SIGNATURE) return 0; if(offset + size > hdr.txtLen) { if(offset > hdr.txtLen) return 0; size = hdr.txtLen - offset; } f_jdt.seek(hdr.offset + offset); return f_jdt.read( ptr , size ); } long JamMsgBase::appendMsg(Message& msg) { JamIndex j_idx; JamHeader j_hdr; JamExtHeader j_ext_hdr; if(!openArea(*msg.msgArea)) return -1; jamLock(); readHeader(); long next_num = f_jdx.len() / sizeof(JamIndex); j_idx.crc32 = JamCrc(msg.to); j_idx.offset = f_jhr.len(); f_jdx.seek(next_num * sizeof(JamIndex)); f_jdx.write(&j_idx , sizeof(JamIndex)); byte *subfields = new char[1024]; CLEAR_OBJECT( j_hdr ); CLEAR_OBJECT( j_ext_hdr ); j_hdr.signature = JAM_SIGNATURE; j_hdr.revision = 1; j_hdr.passwordCrc = dword(-1); j_hdr.offset = f_jdt.len(); msg.num = next_num + jamHeader->baseMsgNum; msg.id = msg.num; Message2JamMsg(&j_hdr,&j_ext_hdr,&msg); strcpy(j_ext_hdr.pid,PID_STRING_JAM); j_hdr.subFieldLen = ExtHeader2SubFields(subfields, j_ext_hdr); File f_txt; if(f_txt.open("MSGTMP",fmode_read,512)) { f_jdt.seek( j_hdr.offset ); for(int len = 0;;) { int c = f_txt.readByte(); if(c < 0) break; if(char(c) == '' || char(c) == '\n') continue; f_jdt << char(c); len++; } j_hdr.txtLen = len; } f_jhr.seek ( j_idx.offset ); f_jhr.write( &j_hdr , sizeof(JamHeader)); f_jhr.write( subfields , j_hdr.subFieldLen); delete [] subfields; jamHeader->activeMsgs++; jamHeader->modCounter++; writeHeader(); jamUnLock(); return msg.num; } bool JamMsgBase::updateMsg(Message& msg) { JamIndex idx; JamHeader hdr; if(!openArea(*msg.msgArea)) return FALSE; if(!jamLock()) return FALSE; readHeader(); long found = findIdx( idx , msg.num , 0 ); if(found != msg.num) { jamUnLock(); return FALSE; } f_jhr.seek(idx.offset); if(f_jhr.read( &hdr , sizeof(JamHeader) ) != sizeof(JamHeader)) { jamUnLock(); return FALSE; } Message2JamMsg( &hdr , NULL , &msg ); f_jhr.seek(idx.offset); f_jhr.write( &hdr , sizeof(JamHeader) ); jamHeader->modCounter++; writeHeader(); jamUnLock(); return TRUE; } long JamMsgBase::msgNum(MsgArea&,long id) { return id; } long JamMsgBase::msgId(MsgArea&,long num) { return num; } bool JamMsgBase::deleteMsg(Message &msg) { JamIndex idx; JamHeader hdr; if(!openArea(*msg.msgArea)) return FALSE; if(!jamLock()) return FALSE; readHeader(); long found = findIdx( idx , msg.num , 0 ); if(found != msg.num) { jamUnLock(); return FALSE; } f_jhr.seek(idx.offset); if(f_jhr.read( &hdr , sizeof(JamHeader) ) != sizeof(JamHeader)) { jamUnLock(); return FALSE; } if(hdr.attribute & JAM_MSG_DELETED) { jamUnLock(); return FALSE; } hdr.attribute |= JAM_MSG_DELETED; hdr.txtLen = 0; f_jhr.seek(idx.offset); f_jhr.write( &hdr , sizeof(JamHeader) ); idx.crc32 = dword(-1); f_jdx.seek ( (found - jamHeader->baseMsgNum) * sizeof(JamIndex) ); f_jdx.write( &idx , sizeof(JamIndex) ); jamHeader->activeMsgs--; jamHeader->modCounter++; writeHeader(); jamUnLock(); return TRUE; } static void showbusy() { static int x = 0; char *ss[] = { "|", "/", "-", "\\", NULL }; io << '\b' << ss[x] << char(0xFF); x = ++x % 4; } word JamMsgBase::scanMail(MessageIndex *msgidx,word maxmsgs) { MsgArea ma; int index = 0; io << "\3 "; for(int i = 1; i <= MsgArea::highAreaNum() ; i++) { if(!ma.read(i)) continue; if(ma.msgBaseType != MSGBASE_JAM) continue; if(!user.mailCheckBoards.connected(i)) continue; if(!check_access(ma.readLevel,ma.readFlags,ma.readFlagsNot)) continue; dword name_crc = JamCrc(user.name); dword alias_crc = JamCrc(user.alias); if(!openArea(ma)) continue; long lr = ma.lastRead(user_recnr); showbusy(); f_jdx.rewind(); long rec = 0; while( index < maxmsgs ) { JamIndex jamidx; if(f_jdx.read(&jamidx,sizeof(JamIndex)) != sizeof(JamIndex)) break; if(jamidx.crc32 == name_crc || jamidx.crc32 == alias_crc || (ma.msgType == MSG_TOALL && (rec+jamHeader->baseMsgNum) > lr)) { Message msg(ma.areaNum); //*msg.msgArea = ma; long msgread = readMsg( msg , rec + jamHeader->baseMsgNum ); if(msgread == rec + jamHeader->baseMsgNum && !(msg.attr & MSGATTR_RECEIVED)) { if(( !stricmp(msg.to,user.name) || (!stricmp(msg.to,user.alias) && ma.flags && strcmp(user.name,user.alias)) || (ma.msgType == MSG_TOALL && (rec+jamHeader->baseMsgNum) > lr) ) && (check_access(ma.readLevel,ma.readFlags,ma.readFlagsNot) || ma.sysopAccess()) ) { msgidx[index].num = msgread; msgidx[index].area = ma.areaNum; index++; } } f_jdx.seek( (rec+1) * sizeof(JamIndex) ); } rec++; } } io << '\b'; return index; } long JamMsgBase::lastRead(MsgArea& ma,long) { if(!openArea(ma)) return -1; dword crc = JamCrc(user.name); JamLastRead jlr; f_jlr.rewind(); for(;;) { if(f_jlr.read( &jlr , sizeof(JamLastRead) ) != sizeof(JamLastRead)) break; if(crc == jlr.userCrc) return jlr.highReadMsg; } return 0; } void JamMsgBase::setLastRead(MsgArea& ma,long,long num) { if(!openArea(ma)) return; dword crc = JamCrc(user.name); JamLastRead jlr; f_jlr.rewind(); for(long rec = 0 ;; rec++) { if(f_jlr.read( &jlr , sizeof(JamLastRead) ) != sizeof(JamLastRead)) break; if(crc == jlr.userCrc) { f_jlr.seek( rec * sizeof(JamLastRead) ); jlr.highReadMsg = num; f_jlr.write( &jlr , sizeof(JamLastRead) ); return; } } jlr.userCrc = crc; jlr.userId = crc; jlr.lastReadMsg = num; jlr.highReadMsg = num; f_jlr.seek( rec * sizeof(JamLastRead) ); f_jlr.write( &jlr , sizeof(JamLastRead) ); } long JamMsgBase::findIdx( JamIndex &mi,long num,int order ) { JamIndex local_idx; if(order < 0) order = -1; if(order > 0) order = 1; if(num < jamHeader->baseMsgNum) { if(order <= 0) return -1; num = jamHeader->baseMsgNum; } f_jdx.seek((num - jamHeader->baseMsgNum) * sizeof(JamIndex)); if(f_jdx.read( &local_idx , sizeof(JamIndex) ) != sizeof(JamIndex)) { if(order >= 0) // exact or forward return -1; num = f_jdx.len() / sizeof(JamIndex) + jamHeader->baseMsgNum - 1; f_jdx.seek((num - jamHeader->baseMsgNum) * sizeof(JamIndex)); if(f_jdx.read( &local_idx , sizeof(JamIndex) ) != sizeof(JamIndex)) return -1; if(num <= 0) return -1; } if(local_idx.crc32 != dword(-1)) { mi = local_idx; return num; } if(!order) return -1; while( local_idx.crc32 == dword(-1) ) { num += order; if(order < 0) { f_jdx.seek((num - jamHeader->baseMsgNum) * sizeof(JamIndex)); } if(f_jdx.read( &local_idx , sizeof(JamIndex) ) != sizeof(JamIndex)) return -1; } mi = local_idx; return (local_idx.crc32 != dword(-1)) ? num : -1; }